GraphQL is the new REST — Part 1

If you are following this article and using mLab online service, I suggest you create an account for yourself on mLab and then create a new MongoDB instance.

Don’t forget to create a database user and password for the newly created database instance.

Once a username and password are created, mLab provide you with a connection string that you grab and put in the line of code above.

Finally, configure the Node.

js app to listen on Port 4000 for incoming requests.

https://gist.

github.

com/bhaidar/98897c69cfb8f727d72f7c98648afcacAdd GraphQL middlewareExpress allows external APIs or packages to hook into the request/response model by means of a middleware.

To redirect all requests coming on /graphql to the GraphQL middleware, configure the Node.

js app with the following: (Add the code just above the app.

listen())https://gist.

github.

com/bhaidar/439fb1a7ec2b09d08d6e7e4983013e88Any request to /graphql is now handled by expressGraphQL middleware.

This middleware requires passing as a parameter the schema to be used by the GraphQL Server API.

We will define this schema soon below.

The graphiql: true option enables an in-browser IDE to run your queries and mutations against the GraphQL Server.

This is very helpful when testing your GraphQL Server API before having an actual client app connected to the server.

GraphQL SchemaGraphQL flexibility is governed by the flexibility your API provides in terms of which object types can be queried or mutated and which fields belonging to the object types that can be returned by the API and consumed by the clients.

This all depends on the schema and object types that you build and configure with the GraphQL Server.

At the end of the day, GraphQL will validate a query or mutation based on a set of rules that the developer of the API has provided depending on a certain schema.

This is the real power of GraphQL.

A GraphQL Schema is more or less analogous to a RESTful API route tree.

Defining a schema means:You tell the GraphQL Server about the object types to expect, whether in the body of the queries/mutations or in the response generated by those queries/mutations.

You build the valid “Endpoints” that the GraphQL Server exposes to client applications.

Build a GraphQL SchemaCreate a new JavaScript file schema.

js inside a new folder named schema.

Import the GraphQL library at the top of the file as follows:const graphQL = require(‘graphql’);Next, import some of the GraphQL types to be used later throughout the code:https://gist.

github.

com/bhaidar/eb005758d8facb1c6dc81decda735fa7We are using the ES6 destructuring feature to extract the types from graphql-js package.

We will be using those types to define our schema below.

A schema is defined by query and mutation.

A query is a root endpoint exposing all available query API endpoints to the client apps.

A mutation is a root endpoint exposing all available mutation (update, create or delete) API endpoints to the client apps.

https://gist.

github.

com/bhaidar/744d15a7d9f7e3544984a0f774464c7dWe define the RootQuery as follows:https://gist.

github.

com/bhaidar/86ca98a7ac3990b7ae63c8edead26bfcThe RootQuery object is of type GraphQLObjectType.

It has a name of RootQueryType and an array of fields.

The array of fields is actually an array of endpoints that the client apps can use to query the GraphQL Server API.

Let’s explore one of the endpoints.

The rest will be similar.

https://gist.

github.

com/bhaidar/5ca627d3dcce70cf1e88e2b3910a1b0eTo define an endpoint, you provide the following fields:type: The data that this endpoint returns.

In this case, it is the BookType.

We will get back to this type shortly.

args: The arguments that this endpoint accepts to filter the data accordingly and return a response.

In this case, the code defines a single argument named id and is of type GraphQLID.

This is a special type provided by GraphQL to indicate that this field is an ID of the object rather than a normal field.

resolve: A function that gets called by GraphQL whenever it is executing the book query endpoint.

This function should be implemented by the developer to return a Book type based on the id argument passed to this query.

We will fill in the gaps later on when we connect to a MongoDB instance to retrieve a book based on its id.

The resolve() function receives as arguments the parent object (if any) and the list of arguments packaged under the args input parameter.

Therefore, to access the book id passed to this query, you do it by args.

id.

That’s the power of GraphQL.

It allows you, the author, to build a graph of objects with instructions in the form of resolve() functions, to tell GraphQL how to query for a sub-object by executing the resolve() function, and so on.

The BookType is defined as follows:https://gist.

github.

com/bhaidar/67575d0c0d0cebb506386b6b1a0f547cDefine an object type by using GraphQLObjectType.

A type is defined by providing the name Book in our case.

In addition, you return an object with all the available fields on the book type inside the fields() function.

The fields defined on the object type are the only fields available for a query response.

The Book type in our case defines the following fields:An id field of type GraphQLIDA name field of type GraphQLStringA genre field of type GraphQLStringAn author field of type AuthorType.

AuthorType is another custom object type that we define ourselves.

This field is special because it defines a resolve() function.

This function receives two input parameters: parent and args.

The parent parameter is the actual Book object queries by GraphQL.

When GraphQL wants to return a field of type custom object type, it will execute the resolve() function to return this object.

Later on, we will add the mongoose API call to retrieve an author from the database by means of Book.

authorId field.

This is the beauty of GraphQL in giving the developer of the API the upper hand to define the different pathways that GraphQL can use to traverse the object model and return a single response per query, no matter how complicated the query is.

Let’s define the Mutation object used by the schema.

https://gist.

github.

com/bhaidar/56dbd6ddaa5427a0e8c8a7e8d5fc9b4aSimilar to the RootQuery object, the Mutation object defines the API endpoints that can be used by client apps to mutate or change the data.

We will go through one of the mutations here, and the rest are available on the Github repo.

The code fragment defines the addBook endpoint.

This endpoint returns data of type BookType.

It receives name, genre and authorId as input parameters.

Notice how we can make input parameters mandatory by using the GraphQLNonNull object.

In addition, this mutation defines the resolve() function.

This function is executed by GraphQL when this endpoint is called.

The resolve() function should contain code to insert or add a new Book object to the MongoDB.

Now that the GraphQL is defined, let’s explore an example of how to connect to MongoDB using the mongoose client API.

Connect to MongoDB via mongoose APILet’s start by defining the schema of the database that mongoose will connect to.

To do so, create a new folder named models.

Then, for each collection or table in the relational database terms, you add a JavaScript file and define the mongoose model object.

For now, add the book.

js file with the following code:const mongoose = require(‘mongoose’);const Schema = mongoose.

Schema;const bookSchema = new Schema({ /** * No need to add “id” column * It is being created by mLab as “_id” */ name: String, genre: String, authorId: String});module.

exports = mongoose.

model(‘Book’, bookSchema);This is the mongoose way of defining a collection inside MongoDB.

This collection will be created inside the MongoDB database the first time it connects to the database instance and doesn’t find a collection there.

The Book collection in our case defines the name, genre, and authorId fields.

Let’s import this collection to our schema.

js file and connect to MongoDB.

The rest of the collections are available on the Github repo.

Start by requiring or importing the Book collection as follows:const Book = require(‘.

/models/book’);Now let’s revisit the book query endpoint and implement its resolve() function to return an actual book from the database:https://gist.

github.

com/bhaidar/abf9488104d36f5a0c4072f2981f5f74Simply by calling the findById() function on the Book model, you are retrieving a Book object based on its id field.

The rest of the mongoose API calls are available on the Github repo.

Now that the GraphQL schema is ready and we’ve already configured the Express-GraphQL middleware with this schema, it’s showtime!Demonstrate the Graphiql IDERun the server app by issuing the following command:node app.

jsThe server is now up and running on PORT 4000.

Let’s open a browser and visit this URL: http://localhost:4000/graphiqlOn the left side you can type in your queries or mutations.

In the middle is the results panel, where the results of a query or mutation are displayed.

On the right side you find the Documentation Explorer.

You can use it to diagnose the documentation of the GraphQL Server API.

Here you are able to see the available queries and mutations, together with their details, as well as how to construct the queries and which fields are available to you.

Let’s add a single book by typing the following GraphQL query.

Check the GraphQL website for a complete reference on how to construct queries and mutations.

https://gist.

github.

com/bhaidar/cfa8551c7a6cdfdd0a60e38334d4ddfbIn the Query Variables section of the panel, on the left side, add the following variables:https://gist.

github.

com/bhaidar/04f3f01ab065105f4b8d7b23a185a2ccThe mutation above creates a new Book record with a certain name, genre, and authorId and returns the id and name of the newly created Book.

The response generated by the above mutation is as follows:https://gist.

github.

com/bhaidar/111a69bad1da45a674d2b61f07432e52To query this book, you issue the following:https://gist.

github.

com/bhaidar/619d218460d4e40f43e6694fbeb2d784Now, the GraphQL Server API is up and running.

Let’s switch gears and build the GraphQL Angular Client app in Part 2 of this series.

ConclusionGraphQL is considered a recent addition to technology.

With its rapid momentum, it looks like it will replace the REStful in terms of accessing and manipulating data in our applications.

In this first part of the series on GraphQL, we’ve built together a GraphQL Server API on top of Node.

js Express.

In Part 2 of this series, we will build a GraphQL Client app with Angular.

Stay tuned!.. More details

Leave a Reply