Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why GraphQL `implements` need to duplicate the fields, is that mandatory? If yes, what is the underlying reasons?

Why GraphQL implements keyword need to duplicate the fields, is that mandatory? Like the examples in the document:

enum Episode { NEWHOPE, EMPIRE, JEDI }

interface Character {
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
}

type Human implements Character {
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
  homePlanet: String
}

type Droid implements Character {
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
  primaryFunction: String
}

If yes, what is the underlying reasons?

Coz If I have to duplicate, if I change then i need to change everywhere...

like image 414
lnshi Avatar asked Apr 17 '17 10:04

lnshi


People also ask

What are fields in GraphQL?

A field is essentially an object-specific attribute that holds a value. The object's parent type defines which fields an object must have. Each field is set at definition to hold certain data types, such as String or Enum .

What are the three types of operations in GraphQL?

GraphQL works by sending operations to an endpoint. There are three types of operations: queries, mutations, and subscriptions.

What is the most basic component of a GraphQL schema?

The GraphQL API uses three main components that reside on the GraphQL server. These components are query, resolver, and schema. Server-side components allow parsing the queries coming from GraphQL client applications.

What 2 pieces make up a GraphQL schema?

The GraphQLSchema object is the core of a GraphQL server When using any of these libraries, your development process is centered around a GraphQLSchema object, consisting of two major components: the schema definition. the actual implementation in the form of resolver functions.


2 Answers

Yes, this is mandatory according to the current spec:

The object type must include a field of the same name for every field defined in an interface.

It allows you to specify more precisely types of fields in the derived type. Fields can be changed to be not-null or to some specific subtype of an interface or a union. Taking your example, let's assume that humans are friends only with other humans and the same for droids. Then the following schema is valid.

interface Character {
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
}

type Human implements Character {
  id: String
  name: String
  friends: [Human] # <- notice Human here
  appearsIn: [Episode]
  homePlanet: String
}

type Droid implements Character {
  id: String
  name: String
  friends: [Droid!]! # <- specified Droid here + added not null
  appearsIn: [Episode]
  primaryFunction: String
}

The object field may include additional arguments not defined in the interface field (but any additional argument must not be required).

Check out the spec for more details: Object type validation

like image 145
RomanHotsiy Avatar answered Oct 20 '22 06:10

RomanHotsiy


Yes it's mandatory. If it helps, think of it as analogous to Java classes and interfaces. The interfaces have the type signatures, but cannot have an implementation. It is in the classes where you write out all the implementation, and the type signatures get repeated. This gives you the ability to choose subtypes or covariant types in the types signatures, so they might not be exactly the same.

Now suppose you are creating a GraphQL schema with the JavaScript objects from graphql-js. The interfaces are simply field names and types. The Object Type definitions themselves have the "implementation," or the resolve, resolveType, and other properties that actually make it an executable schema.

Your example, however, uses the schema language instead, which has no "implementation" at all. So they pretty much are an exact repetition of one another. You don't necessarily need to spell it all out every time, you could use string interpolation to share parts of the interface.

const characterFields = `
  id: String
  name: String
  friends: [Character]
  appearsIn: [Episode]
`

const typeDefs = `
  interface Character {
    ${characterFields}
  }

  type Human Implements Character {
    ${characterFields}
    homePlanet: String
  }
`

EDIT: Analogous to the Java comparison, the fields may not be exactly the same type. As RomanHotsiy pointed out, you can make the types non-nullable or use subtypes of polymorphic types.

like image 38
Andy Carlson Avatar answered Oct 20 '22 07:10

Andy Carlson