GraphQL and React

A RESTful routing primer

  • given a collection of records on a server, there should be a uniform URL and HTTP request method used to utilize that collection of records. (doing CRUD operations to that data)
  • GraphQL can fix some issues in Restful routing and over serving data

On to GraphQL

  • Graph is all the data and their relationships in a database.
  • we define a query and it starts at some node, then follow the edges to get the other data we want
1
2
3
4
5
6
7
8
9
query {
user(id: "1") {
friends {
company {
name
}
}
}
}
  • Express is handling our requests, if the request is a GraphQL query, it will hand the request to the GraphQL. The response from GraphQL will be send back to Express which will then be sent back to the application
  • application -> Express -> GraphQL
  • application <- Express <- GraphQL

Fetching data with queries

  • Resolve function is like an edge in the Graph, it has the parent value and arguments, and takes us to the next node in the graph, to fetch the piece of data we want

The circular reference error

  • in JS, you cannot refer to a variable before it has been defined. But in GraphQL, it is common to have circular reference, e.g. A USER is working at a COMPANY. and this COMPANY has this USER. So we need to have resolve this circular reference problem
1
2
3
4
5
6
const UserType = new GraphQLObject({
name: "User",
fields: () => ({
...
})
})
  • the solution is to wrap the definition of fields into an arrow function. So JS will first define all the variables, but will not execute any functions. Then in GraphQL internally it will invoke this anonymous functions. And inside these CLOSURES we already have defined all these variables.

Fragment

  • a fragment is just a list of properties of an object, by defining a fragment so you don’t have to duplicate all that properties in your query
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
apple: company(id: "1") {
...companyDetails
}
google: company(id: "2") {
...companyDetails
}

fragment companyDetails on Company {
id,
name,
description
}
}

Mutation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/**
* Mutation is to make changes to the data
* fields of the mutation describe the operation that this mutation is going to undertake
*/
const mutation = new GraphQLObjectType({
name: "Mutation",
fields: {
addUser: {
type: UserType,
args: {
firstName: { type: new GraphQLNonNull(GraphQLString) },
age: { type: new GraphQLNonNull(GraphQLInt) },
companyId: { type: GraphQLString },
},
resolve(parentValue, { firstName, age }) {
return axios
.post("http://localhost:3000/users", { firstName, age })
.then((res) => res.data);
},
},
},
});

/**
* GraphQLSchema takes a RootQuery and returns a new instance of GraphQL Schema
* we can use this schema in our Express application
*/
module.exports = new GraphQLSchema({
query: RootQuery,
mutation,
});
  • mutation query from Graphiql
1
2
3
4
5
6
7
mutation {
addUser(firstName: "Yuan", age: 28) {
id,
firstName,
age
}
}
  • new data is also present in the db.json file, notice json-server will automatically assign an ID to our new User

PUT and PATCH

  • PUT request will completely replace the data record with the one in the request
  • PATCH request will only update the data attributes in the record, and leave the existing data attributes untouched

History of data transport

  • RPC -> SOAP -> REST -> GraphQL

Over-fetching

  • REST API will likely to give us more data points than we need
  • GraphQL can give us the exact data we need in the shape we want

Under-fetching

  • if we want to get the details of an actor and all the movies he played using Rest API.
  • firstly we need to make a request to get the actor details. Then for each movie we need to make a separate API request to get the movie details.
  • But if we are using GraphQL, because the Actor and the Movie are related, we could use nested query to get all the data in one request.

One endpoint

  • using Rest API often requires us to make many endpoints to suit our needs. That means our front and backend teams have to spend a lot of time together working out their needs.
  • GraphQL only has one endpoint, all data are related and defined in a well structured schema file.
  • Many companies use Rest and GraphQL together, setting up a GraphQL endpoint that fetches data from REST endpoints is a perfectly valid way to use GraphQL

GraphQL clients

  • speed the workflow for developers teams and improve the efficiency and performance of applications.
  • They handle tasks like network requests, data caching, and injecting data into the UI.
  • Relay and Apollo

The GraphQL Query Language

  • GraphQL is like SQL, they are both query language, doing CRUD operations with data.
  • the difference is SQL is doing operations directly to the database. But GraphQL needs to be sent over the internet or API.
  • SQL is a query language for databases, GraphQL is a query language for the Internet.

GraphQL API tools

  • for testing GraphQL queries against a GraphQL API: GraphiQL and GraphQL Playground

Query Types

  • there are five types in GraphQL
    • Int
    • Float
    • String
    • Boolean
    • ID (unique String)

Fragment

  • selection sets that can be reused in multiple operations
  • Fragment must be associated with a type
  • you could also write inline fragment
1
2
3
4
5
6
7
8
9
10
11
query {
getInfo {
...fragInfo
}
}

fragment fragInfo on Info {
field1
field2
field3
}

Inline fragment

1
2
3
4
5
6
7
query {
...on Info {
field1
field2
field3
}
}
  • inline fragment is like an anonymous fragment

Mutation

  • make changes to data

Subscription

  • when the subscription is sent to the server, the subscription is listening for any changes to the data
1
2
3
4
5
6
7
subscription {
infoChange {
field1
field2
field3
}
}
  • the subscription remains open until you close it.

Introspection

  • query details about the current API’s schema