GraphQL
Neil Haddley • March 1, 2021
GraphQL is a query and manipulation language for APIs.
A REST API client may need to make multiple calls to a REST Service to get all of the data it needs.
A GraphQL API client may be able to request all of the data it needs in a single call.
GraphQL supports reading data, mutating data, and subscribing to data (WebSockets).
server.js
We create a package.json file using the npm init command
$ npm init -y
We add the GraphQL dependencies using npm
$ npm i express@4.16.4 express-graphql@0.7.1 graphql@14.1.1 cors@2.8.5

npm i
server.js
Once the dependencies have been added we can create a server.js file.
package.json
Now we can update the package.json file and run the GraphQL service.
"scripts": {
"start": "node server.js"
},
npm start
Use "npm start" to run the GraphQL server.
$ npm start

Reading books and related author details

Reading data for a single author

Mutating data. Adding an author

Mutating data. Adding a book
A GraphQL client app
It is possible to use react and apollo to create a GraphQL client app.
We create a package.json file using the npm init command
$ npm init -y
We add the GraphQL and Apollo dependencies using npm
$ npm i apollo-boost@0.4.9 graphql@15.4.0 react@17.0.1 react-apollo@3.1.5 react-dom@17.0.1 react-scripts@4.0.1
The app.js code includes a GraphQL query, an ApolloProvider and a Query.

localhost:3000
API Gateway
Notice that the Cross-Origin Resource Sharing (CORS) library reference in the GraphQL code above is not needed when the GraphQL server and the GraphQL client App are published using an API Gateway.
server.js
JAVASCRIPT
1const express = require('express') 2const expressGraphQL = require('express-graphql') 3const { 4 GraphQLSchema, 5 GraphQLObjectType, 6 GraphQLString, 7 GraphQLList, 8 GraphQLInt, 9 GraphQLNonNull 10} = require('graphql') 11 12const cors=require('cors'); // optional 13 14const app = express() 15 16app.use(cors()) // optional 17 18const authors = [ 19 { id: 1, name: 'Samer Buna' }, 20 { id: 2, name: 'Robin Wieruch' }, 21 { id: 3, name: 'Nader Dabit' }, 22 { id: 4, name: 'Sebastian Grebe' }, 23 { id: 5, name: 'Eve Porcello' }, 24 { id: 6, name: 'Alex Banks' } 25] 26 27const books = [ 28 { id: 1, isbn10: '161729568X', name: 'GraphQL in Action', authorIds: [1] }, 29 { id: 2, isbn10: '1730853935', name: 'The Road to GraphQL: Your journey to master pragmatic GraphQL in JavaScript with React.js and Node.js', authorIds: [2] }, 30 { id: 3, isbn10: '1492059897', name: 'Full Stack Serverless: Modern Application Development with React, AWS, and GraphQL', authorIds: [3] }, 31 { id: 4, isbn10: '1789134528', name: 'Hands-On Full-Stack Web Development with GraphQL and React', authorIds: [4] }, 32 { id: 5, isbn10: '1492030716', name: 'Learning GraphQL: Declarative Data Fetching for Modern Web Apps', authorIds: [5, 6] }, 33 { id: 6, isbn10: '1492051721', name: 'Learning React: Modern Patterns for Developing React Apps', authorIds: [5, 6] }, 34] 35 36const BookType = new GraphQLObjectType({ 37 name: 'Book', 38 description: 'This represents a book written by an author', 39 fields: () => ({ 40 id: { type: GraphQLNonNull(GraphQLInt) }, 41 name: { type: GraphQLNonNull(GraphQLString) }, 42 isbn10: { type: GraphQLNonNull(GraphQLString) }, 43 authorIds: { type: GraphQLNonNull(GraphQLList(GraphQLInt)) }, 44 authors: { 45 type: new GraphQLList(AuthorType), 46 resolve: (book) => { 47 return authors.filter(author => (book.authorIds.includes(author.id))) 48 } 49 } 50 }) 51}) 52 53const AuthorType = new GraphQLObjectType({ 54 name: 'Author', 55 description: 'This represents an author of a book', 56 fields: () => ({ 57 id: { type: GraphQLNonNull(GraphQLInt) }, 58 name: { type: GraphQLNonNull(GraphQLString) }, 59 books: { 60 type: new GraphQLList(BookType), 61 resolve: (author) => { 62 return books.filter(book => (book.authorIds.includes(author.id))) 63 } 64 } 65 }) 66}) 67 68const RootQueryType = new GraphQLObjectType({ 69 name: 'Query', 70 description: 'Root Query', 71 fields: () => ({ 72 book: { 73 type: BookType, 74 description: 'A Single Book', 75 args: { 76 id: { type: GraphQLInt } 77 }, 78 resolve: (parent, args) => books.find(book => book.id === args.id) 79 }, 80 books: { 81 type: new GraphQLList(BookType), 82 description: 'List of All Books', 83 resolve: () => books 84 }, 85 authors: { 86 type: new GraphQLList(AuthorType), 87 description: 'List of All Authors', 88 resolve: () => authors 89 }, 90 author: { 91 type: AuthorType, 92 description: 'A Single Author', 93 args: { 94 id: { type: GraphQLInt } 95 }, 96 resolve: (parent, args) => authors.find(author => author.id === args.id) 97 } 98 }) 99}) 100 101const RootMutationType = new GraphQLObjectType({ 102 name: 'Mutation', 103 description: 'Root Mutation', 104 fields: () => ({ 105 addBook: { 106 type: BookType, 107 description: 'Add a book', 108 args: { 109 name: { type: GraphQLNonNull(GraphQLString) }, 110 isbn10: { type: GraphQLNonNull(GraphQLString) }, 111 authorIds: { type: GraphQLNonNull(GraphQLList(GraphQLInt)) } 112 }, 113 resolve: (parent, args) => { 114 const book = { id: books.length + 1, name: args.name, isbn10: args.isbn10, authorIds: args.authorIds } 115 books.push(book) 116 return book 117 } 118 }, 119 addAuthor: { 120 type: AuthorType, 121 description: 'Add an author', 122 args: { 123 name: { type: GraphQLNonNull(GraphQLString) } 124 }, 125 resolve: (parent, args) => { 126 const author = { id: authors.length + 1, name: args.name } 127 authors.push(author) 128 return author 129 } 130 } 131 }) 132}) 133 134const schema = new GraphQLSchema({ 135 query: RootQueryType, 136 mutation: RootMutationType 137}) 138 139app.use('/graphql', expressGraphQL({ 140 schema: schema, 141 graphiql: true 142})) 143app.listen(5000, () => console.log('Server Running'))
package.json
JAVASCRIPT
1{ 2 "name": "graphql-server", 3 "version": "1.0.0", 4 "description": "", 5 "main": "index.js", 6 "scripts": { 7 "start": "node server.js" 8 }, 9 "repository": { 10 "type": "git", 11 "url": "git+https://github.com/haddleyoffice365/graphql-server.git" 12 }, 13 "keywords": [], 14 "author": "", 15 "license": "ISC", 16 "bugs": { 17 "url": "https://github.com/haddleyoffice365/graphql-server/issues" 18 }, 19 "homepage": "https://github.com/haddleyoffice365/graphql-server#readme", 20 "dependencies": { 21 "cors": "^2.8.5", 22 "express": "^4.16.4", 23 "express-graphql": "^0.7.1", 24 "graphql": "^14.1.1" 25 } 26}
app.js
JAVASCRIPT
1import ApolloClient from 'apollo-boost'; 2import { ApolloProvider, Query } from 'react-apollo'; 3import gql from 'graphql-tag'; 4 5const client = new ApolloClient({ 6 uri: 'http://localhost:5000/graphql' 7}) 8 9const query = gql` 10query booksQuery { 11 books { 12 id, 13 name, 14 authors 15 { 16 name 17 } 18 } 19} 20` 21 22function App() { 23 24 return ( 25 26 <ApolloProvider client={client}> 27 28 <div> 29 30 <Query query={query}> 31 { 32 ({ loading, error, data }) => { 33 if (loading) return <h4>Loading...</h4> 34 if (error) console.log({ error }) 35 return data.books.map(book => 36 <> 37 <h3 key={book.id}>{book.name}</h3> 38 {book.authors.map(author => 39 <h4>{author.name}</h4>)} 40 </> 41 ) 42 } 43 } 44 </Query> 45 46 </div> 47 48 </ApolloProvider> 49 50 ); 51} 52 53export default App;