GraphQL

Write an awesome doc for GraphQL. A very nice an practical one extracted from GraphQL official documentation.

View on GitHub

GraphQL

My definition of GraphQL

GraphQL is a structured way of talking to the backend and asking for data or performing an operation in a specific way within the established framework of our backend. Meaning we ain’t gonna let client to do whatever they want but will give them more room to play but will still have some form dos and don’ts.

[!NOTE]

Answers to some of questions that I yearned to know:

  • GraphQL is transport-layer agnostic: This is copied and pasted from GraphQL here, in fact this was a burning question for me that if I should stick to HTTP/S or should I use a different protocol. But in short we do not need to change our protocol.

… the GraphQL specification doesn’t require the use of a particular transport protocol for requests … it is common for HTTP to be used for stateless query and mutations operations. Long-lived, stateful subscription operations are often supported by WebSockets or server-sent events instead.

Ref.

  • And related to the previous note, in general in GraphQL we serve our GraphQL service via a single endpoint as described here.
  • This was my second question that I was trying to find an answer to it and it was actually just a few links away from me. In graphql.org they have a section for tools and libs. There I was able to compare and find the right tool for my next move, deciding on a lib for my backend app.

How you create your API in GraphQL

A GraphQL service (AKA GraphQL backend) is created by:

  1. Defining types and their fields.
  2. Writing a function for each field to provide the required data.

a GraphQL service that tells you the name of a logged-in user might look like the code inside the image. In this example the function that provides data for the me field on the Query type uses information about the authenticated user who made the request, while the the name field on the User type is populated by using that user’s ID to fetch their full name from a database.

[!TIP]

Learn about the four available arguments in a resolver here.

Sales pitches of GraphQL

Query what you need

A GraphQL service is running (typically at a URL on a web service):

  1. It receives GraphQL queries to validate and execute from clients.
  2. The service first checks a query to ensure it only refers to the types and fields defined for the API.
  3. Then runs the provided functions to produce a result.

Example query and response

[!NOTE]

Client can make queries to the API, here we our client benefits from:

  • Responses in the expected shape.
  • Receiving just the data with a single request (no roundtrip).

[!CAUTION]

# Operation name

Here we are omitting our query name and operation name. But when you’re developing a real software better to include them to prevent any ambiguity.

query FetchUserInfo {
  me {
    name
  }
}
  • You can also have anonymous mutation operations too. But it is encourages to use named operations since they will give us an edge in:
    • Debugging.
    • Code readability.
    • Server-side logging.
  • Similar to function names.

Learn more.

No need to do API versioning

Here is another example of fetching user info when we are only interested in user’s name, id and appearsIn.

Interactive example of how a GraphQL service will work

Hello world app ;)

  1. pnpm add graphql
  2. Define a schema for your GraphQL service.
    • This is where we define our Query type.
  3. Define root API (AKA root resolver).
    • Defines functions that correspond to the top-level fields in the Query type of the schema.
  4. Define the query.
  5. Make a call to your GraphQL.

Code: https://github.com/kasir-barati/graphql-js-ts/blob/main/apps/hello-world/src/main.ts.

ExpressJS + GraphQL

  1. pnpm add "express@>=5.0.1" graphql-http graphql.
  2. nx g @nx/express:application apps/expressjs-hello-world.
    • pnpm rm @nx/web @nx/webpack @pmmmwh/react-refresh-webpack-plugin @svgr/webpack webpack-cli react-refresh.
    • Remove webpack plugin from nx.json. And from project.json + its files.
    • nx add @ns/esbuild.
    • Update your project.json to use esbuild instead of webpack.
  3. ExpressJS to run a web server.
  4. graphql-http lib to mount a GraphQL API server on the /graphql HTTP endpoint.
  5. pnpm add ruru.

    • GraphiQL is GraphQL’s IDE.
    • You can query and explore your GraphQL API with it.

    GraphiQL IDE issued a GraphQL query to our hello endpoint

  6. Or you can run the e2e tests for it: nx e2e expressjs-hello-world-e2e.

    BTW To learn more about my thought processes and why I did test it this way you can read this.

Code: https://github.com/kasir-barati/graphql-js-ts/tree/main/apps/expressjs-hello-world.

[!TIP]

  • Use Relay as your client in your ReactJS app.
  • Or use graphql-http to just invoke your GraphQL endpoints over HTTP POST requests.

Dynamic values

To construct GraphQL queries first we need to defined the schema:

type Query {
  rollDice(numDice: Int!, numSides: Int): [Int]
}

Then:

const dice = 3;
const sides = 6;
const query = /* GraphQL */ `
  query RollDice($dice: Int!, $sides: Int) {
    rollDice(numDice: $dice, numSides: $sides)
  }
`;

fetch('/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json',
  },
  body: JSON.stringify({
    query,
    variables: { dice, sides },
  }),
})
  .then((r) => r.json())
  .then((data) => console.log('data returned:', data));

Let’s break down

query RollDice($dice: Int!, $sides: Int) {
  rollDice(numDice: $dice, numSides: $sides)
}
body: JSON.stringify({
  query,
  variables: { dice, sides },
}),

variables:

GraphQL is not The Same as REST

Ref