schema-driven
(or schema-first development
) is a process that should be followed when adding a new feature to the API:
-
Extend the GraphQL schema definition with a new root field (and new data types, if needed):
// ------------------- // src/index.js // ------------------- const typeDefs = ` // 1 type Query { info: String! // 2 feed: [Link!]! } // 3 type Link { id: ID! description: String! url: String! } `;
[1]
- all queries should go insidetype Query{}
[2]
-feed
root field is added to the Query type; will be used for retrieving the list ofLink
elements[3]
-Link
data type represents the links that can be posted to the App!
- indicates the field will never contain any elements that arenull
-
The next step is to implement the resolver function for the
feed
query, still on the same file:// 1 let links = [ { id: 'link-0', url: 'graphql.org' description: 'GraphQL is awesome!', } ]; const resolvers = { // 2 Query: { info: () => 'This is the API of a Hackernews Clone', // 3 feed: () => links }, // 4 Link: { id: root => root.id, description: root => root.description, url: root => root.url } };
[1]
-links
variable stores the links at runtime. For now, it stored only in-memory rather than persisted in a database[2]
- allresolvers
for Query should go insideQuery:{}
[3]
- resolver for thefeed
root field, named after its corresponding field from the schema definition[4]
- resolvers for the fields on theLink
type. This can actually be removed, they are not needed because GraphQL server infers what they look like
-
Restart the server with
CMD+C
(to kill the server) and by runningnode src/index.js
to start it again.Send the following
feed
query through the Playground:query { feed { id url description } info }
Notice that you're also sending
info
query, as you can actually send multiple queries in one request. A sample server response would be:{ "data": { "feed": [ { "id": "link-0", "url": "graphql.org", "description": "GraphQL is awesome!" } ], "info": "This is the API of a Hackernews Clone" } }
Every field inside schema definition is backed by one resolver function which is responsible for returning the precise data for that field. Server invokes all these resolver functions for the fields that are contained in the query, package up the response according to the query's shape.
root
(orparent
) - the result of the previous resolver functionargs
- carries thearguments
for the GraphQL operationcontext
- explained in the next sectioninfo
- learn about it from here and here
GraphQL queries can be nested, each level of nesting (ie: nested curly braces) corresponds to one resolver execution level. Consider the following query:
query {
feed {
id
description
url
}
}
The first level invokes the feed
resolver and returns the data stored in links
. On the second level, the resolver for Link
type for each element from the returned list gets invoked, hence the incoming root
object on this level is the element inside the links
list.