Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GraphQL: Using generic Mutation can lead to unwanted result #5925

Closed
Moumouls opened this issue Aug 15, 2019 · 5 comments
Closed

GraphQL: Using generic Mutation can lead to unwanted result #5925

Moumouls opened this issue Aug 15, 2019 · 5 comments

Comments

@Moumouls
Copy link
Member

Issue Description

Using a generic Mutation can lead to unwanted result, more specifically on data types like: Array/Relation.

Steps to reproduce

Create a new Object (with new field) and an array of Pointers

mutation {
  objects {
    create(
      className: "SomeClass"
      fields: {
        relation: [
          { __type: "Pointer", className: "Country", objectId: "GFFCf5dxKW" }
        ]
      }
    ) {
      objectId
    }
  }
}

Expected Results

relation field must be a Relation

Actual Outcome

Capture d’écran 2019-08-15 à 23 32 45

The data type is interpreted as an Array

Environment Setup

  • Server

    • parse-server version (Be specific! Don't say 'latest'.) : master
    • Localhost or remote server? (AWS, Heroku, Azure, Digital Ocean, etc): localhost
  • Database

    • MongoDB

Suggestion

I think that generic Mutations isn't suitable in real GraphQL app but it's useful for testing the current GraphQL feature. The generic Mutation currently seems to be a black box and can be confusing for new developers who are not familiar with SDKs (Polygon, ACL, Pointer, etc...)

In fact, I think that in most applications that will use the Parse GraphQL as API, the SDKs will be used little or not at all to interact with the GraphQL because it is not comfortable and really logical to combine a SDK and a API GraphQL in terms of developer experience.

We should teach developers to create first a schema with a well designed createClass/createSchema Mutation and then use a specific Mutation

What do you think about this @davimacedo @omairvaiyani @douglasmuraoka ?

@davimacedo
Copy link
Member

The sintax for creating a relationField through the generic method is the same of the REST API. So it whould be:

mutation {
  objects {
    create(
      className: "SomeClass"
      fields: {
        relation: {
          __op: "Batch",
          ops: [{ __op: "AddRelation", objects: [{ __type: "Pointer", className: "Country", objectId: "GFFCf5dxKW" }]}]
      }
    ) {
      objectId
    }
  }
}

See test case here: https://github.com/parse-community/parse-server/blob/master/spec/ParseGraphQLServer.spec.js#L5119

I know it is not intuitive and need docs. The developers can always opt for the custom operations though. The idea behind the generic operations is to keep the schemaless feature in Parse GraphQL API but we can discuss it further and perhaps remove them.

@davimacedo
Copy link
Member

I was thinking little bit more here. Maybe an option could be just remove all generic operations and build new operations to manipulate the schema?

@Moumouls
Copy link
Member Author

Yes not intuitive 😉
I'm not sure it's a solution to add more doc on a GraphQL API, the main goal of GraphQL is to avoid documentation and dive directly in Mutations and Queries.

@Moumouls
Copy link
Member Author

Moumouls commented Aug 15, 2019

I was thinking little bit more here. Maybe an option could be just remove all generic operations and build new operations to manipulate the schema?

It's totally what i suggest, a developer could use the full potential of Parse GraphQL Server without reading single line of external documentation

A example of DX:

  • Developer see mutation: createClass ou createSchema
  • He can use enum to choose data types: Relation, Polygon, Pointer during class creation
  • Schema is now created
  • Now he can create the new object with a full typed help (particularly useful for special data types, ACL (we need to type this 😉 ), Polygon, etc...)
  • The developer can now use the full power of Parse Server without reading single line of an external doc.

#5863

@Moumouls
Copy link
Member Author

Moumouls commented Aug 16, 2019

Type Proposal

type Mutation {
	createClass(input: CreateClassInput): Boolean
	updateClass(input: UpdateClassInput): Boolean
	createSchema(input: [CreateClassInput]): Boolean
	updateSchema(input: [UpdateClassInput]): Boolean
}

input AddArrayInput {
	name: String!
}

input AddRelationInput {
	name: String!
	targetClass: String!
}

input AddNumberInput {
	name: String!
}

input AddBooleanInput {
	name: String!
}

input AddFileInput {
	name: String!
}

input AddPointerInput {
	name: String!
	targetClass: String!
}

input AddDateInput {
	name: String!
}

input AddGeoPointInput {
	name: String!
}

input AddObjectInput {
	name: String!
}

input AddStringInput {
	name: String!
}

input DeleteField {
	name: String!
}

input SchemaClassInput {
	addArrays: [AddArrayInput!]
	addStrings: [AddRelationInput!]
	addNumbers: [AddRelationInput!]
	addDates: [AddRelationInput!]
	addGeoPoints: [AddRelationInput!]
	addFiles: [AddRelationInput!]
	addRelations: [AddRelationInput!]
	addObjects: [AddObjectsInput!]
	addPointers: [AddPointersInput!]
	addPolygons: [AddPolygonsInput!]
	addBooleans: [AddBooleansInput!]
}

input CreateClassInput {
	className: String!
	schema: SchemaClassInput
}

input UpdateClassInput {
	className: ClassNameEnum!
	schema: SchemaClassInput
}

Mutation example:

mutation {
  createClass (input: {
    className: "SomeClass"
    schema: {
      addArrays: [
        {name: "anArray"}
      ]
      addRelations: [
        {name: "users", targetClass: "User"}
        {name: "products", targetClass: "Product"}
      ]
    }
  })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants