Skip to content
This repository was archived by the owner on Aug 2, 2023. It is now read-only.
This repository was archived by the owner on Aug 2, 2023. It is now read-only.

@GraphQLVariables isn't a class level annotation #16

Description

@jeremygiberson

Unlike GraphQLProperty, GraphQLVariable(s) isn't class level -- I'm not sure how I'm suppose to use them to achieve my query/mutation.

I'm trying to build the following mutation

mutation Create2FA($inputDescriptor: Input2FA!) {
   Create2FA(inputDescriptor: $inputDescriptor) {
       TwoFAID
       Description
       ...
   }
}

Or A more general usage example for Queries:

query FindProducts($filter: InputFilter!) {
     FindProductsWithFilter(filter: $filter) {
        SKU
        Description
     }
}

Expected Uses

I was anticipating a model definition like (but illegal to put variables @ class level):

@GraphQLProperty(name = "Create2FA")
@GraphQLVariables({
    @GraphQLVariable(name = "TwoFA", scalar = "CreateTwoFA!")
})
public class MutationCreate2FA extends TwoFAModel {
}

Available Uses

These are my (legal) options but all provide the wrong result.

Test Case

package privoro.aid.authenticator.graphql;

import io.aexp.nodes.graphql.GraphQLRequestEntity;
import io.aexp.nodes.graphql.Variable;
import org.junit.Test;
import org.privoro.aid.authenticator.graphql.InputCreate2FA;
import org.privoro.aid.authenticator.graphql.MutationCreate2FA;

import java.net.MalformedURLException;

import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;

public class TestGraphQLRequestEntity {
    private String EXAMPLE_URL = "https://graphql.example.com";
    @Test
    public void mutationWithVariables() throws MalformedURLException {
        InputCreate2FA input = new InputCreate2FA();
        input.setUserID("user-id");
        input.setDeviceID("device-id");
        input.setRelyingPartyID("relying-party-id");
        input.setDescription("description");

        GraphQLRequestEntity requestEntity = GraphQLRequestEntity.Builder()
            .url(EXAMPLE_URL)
            .variables(new Variable<InputCreate2FA>("TwoFA", input))
            .request(MutationCreate2FA.class)
            .build();
        System.out.println("Request Entity:" + requestEntity.toString());
        assertThat(requestEntity.toString(), containsString("'query ($TwoFA: CreateTwoFA!) { Create2FA (TwoFA: $TwoFA) {"));
    }
}

Input variable model

package org.privoro.aid.authenticator.graphql;

public class InputCreate2FA {
    public String UserID;
    public String RelyingPartyID;
    public String Description;
    public String DeviceID;
}

Result Model

package org.privoro.aid.authenticator.graphql;

public class TwoFA {
    public String UserID;
    public String RelyingPartyID;
    public String Description;
    public String Status;
    public String Reason;
    public String CreatedTimestamp;
    public String ExpiresAt;
    public String TwoFAID;
}
1 Property and Values set inside the class on the result model property

MutationCreate2FA

public class MutationCreate2FA {
@GraphQLProperty(name = "Create2FA")
@GraphQLVariables({
    @GraphQLVariable(name = "TwoFA", scalar = "CreateTwoFA!")
})
    public TwoFAModel twoFa;
}

Output:

query ($TwoFA:CreateTwoFA!){ twoFA : Create2FA(TwoFA:$TwoFA) { Status RelyingPartyID Description CreatedTimestamp UserID TwoFAID ExpiresAt Reason } } 
2 Property on the class but variables on a result model property

MutationCreate2FA

@GraphQLProperty(name = "Create2FA")
public class MutationCreate2FA {
@GraphQLVariables({
    @GraphQLVariable(name = "TwoFA", scalar = "CreateTwoFA!")
})
    public TwoFAModel twoFa;
}

Output:

query ($TwoFA:CreateTwoFA!){ Create2FA { twoFA (TwoFA:$TwoFA) { Status RelyingPartyID Description CreatedTimestamp UserID TwoFAID ExpiresAt Reason } } } 
3 Variables only specified when building request

MutationCreate2FA

@GraphQLProperty(name = "Create2FA", arguments = {
    @GraphQLArgument(name = "TwoFA", value = "$TwoFA")
})
public class MutationCreate2FA extends TwoFA {
}

Output (close, but the builder doesn't inject the variables):

query { Create2FA (TwoFA:$TwoFA) { Status RelyingPartyID Description CreatedTimestamp UserID TwoFAID ExpiresAt Reason } } 

Preferred usage

If I step back from the docs a little and imagine how I might specify query's and mutations with variables I come up with:

@GraphQLOperation(name = "Create2FAMutation", type="mutation", variables = {
   @GraphQLVariable(name = "inputCreate2FA", scalar = "Create2FA!")
}, properties = {
   @GraphQLProperty(name = "Create2FA", arguments = {
      @GraphQLArgument(name = "TwoFA", variable = "inputCreate2FA")
   })
})
class MutationCreate2FA extends TwoFA {

}

Output

mutation Create2FAMutation ($inputCreate2FA: Create2FA!) { Create2FA (TwoFA:$inputCreate2FA) { Status RelyingPartyID Description CreatedTimestamp UserID TwoFAID ExpiresAt Reason } } 

I think this preferred usage can be provided and be backwards compatible w/ current usage.

I've introduced an annotation @GraphQLOperation which is optional (if you don't need variables) in your query/mutation. This would remove the need for @GraphQLVariables (altogether) and @GraphQLVariable would only be used in top level operation annotations (not on models or on model properties).

I've also added an optional variable parameter to the @GraphQLArgument which associates the argument to a specified variable. The addition allows properties to be defined as arguments that can be bound to variables later which reduces unwanted coupling from the model to the operation.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions