GraphQL Workshop Day

Daily Standup

Today I went to a GraphQL workshop as part of the ReactJS Girls Conf. I’ll paste my notes here for reference…these are more random jottings than considered review of what we covered, but maybe still useful in future!

Querying

If you want to write a query on the same variable twice, you must set an alias:

query {
checkedOutPets:totalPets(status:CHECKEDOUT)
availablePets:totalPets(status:AVAILABLE)
allPets {
name
weight
category
}
}

You can create a dynamic query using variables:

query ($category: PetCategory){
allPets(category:$category) {
name
category
}
}

# QUERY VARIABLES
{
"category": "CAT"
}

To have multiple queries in your query document playground, you have to name each query:

query CustomersQuery {
allCustomers {
name
currentPets {
name
}
}
}

query PetByIdQuery {
petById(id: "C-1") {
name
inCareOf {
name
username
}
}
}

To query all fields on a schema, you do have to write all of the field names…or you can do it once in a GraphQL fragment and then use the spread operator to access it:

fragment AllFields on Lift {
id
name
status
capacity
night
elevationGain
}

query {
allLifts {
...AllFields
}
}

There is also such a thing as an inline fragment.

Mutations / Updating Data

Example:

query allLiftsWithTrails {
allLifts {
name
elevationGain
status
trailAccess {
name
}
}
}

mutation setStatus{
setLiftStatus(
id: "panorama"
status: OPEN
) {
name
status
}
}

query getPan {
Lift(id: "panorama") {
name
status
night
}
}

Subscriptions

These work with web sockets and listen for changes

Creating A Schema

See the GraphQL Schema Cheat Sheet for reference

The schema is required for setting up the sandbox…this is where all of the auto-completes come from. Basic schema setup uses GraphQL schema definition language:

type Photo {
id: ID!
name: String!
description: String
category: PhotoCategory!
}

enum PhotoCategory {
SELFIE
LANDSCAPE
ACTION
}

Exclamation makes the field non-nullable. Multiple exclamations make it so that the query can’t return null, nor can a single result be null. If there are no results for the query, it will return an empty array:

allPhotos: [Photo!]!

Another way to make a field non-nullable is to set a default where no input is provided:

type Lift {
status: LiftStatus=CLOSED
}

enum LiftStatus {
OPEN
CLOSED
HOLD
}

Queries for a single result return an object, while queries for a list of results will return an array.

To add multiple fields to a query:

type Query {
photo(id: ID! location: String): Photo!
}

Interfaces

Interfaces can be used to make models extendable, for example a Pet model will have basic fields that will apply to models, and then subsequent models can add additional fields. For example, a Cat model could get calico: Boolean!.

In the query this would be accessed by __typename.

Setting Up Mutations

Add the fields that will be part of the mutation, then return it:

type Mutation {
postPhoto(
name: String
description: String
category: PhotoCategory
): Photo!
}

Scalar Types

ID, String, Int, Float and Boolean are the 5 scalar types available in GraphQL. If these don’t suffice, you can create your own scalar types:

scalar DateTime

type Photo {
updated: DateTime
}

Building a Server

Building a GraphQL server requires a schema and resolvers (aka typeDefs). The resolvers are where any logic or manipulation will exist.

To query based on user input, use a function, where the default methods are parent and arguments:

const resolvers = {
Query: {
findByLiftId: (parent, args) => {
return lifts.find(lift => args.id === lift.id)
},
}
};

Another way to do this is to destructure the arguments:

const resolvers = {
Query: {
findByLiftId: (parent, {id}) => {
return lifts.find(lift => id === lift.id)
},
}
};

A client like Apollo Client or Relay provides the benefit of caching…that’s why we use them instead of simple HTTP requests (which also work).

Sourcing Schemas From A File

Instead of writing the schema with the typeDefs definition, you can use the Node fs module to import it from another file:

const fs = require('fs');
const typeDefs = fs.readFileSync('typdefs.graphql', 'UTF-8')

Tips

gql Tag

You can use a gql tag in front of template literals to help the code editor do the correct syntax highlighting:

const typeDefs = gql`
type Query {
hello: String!
}
`;

To do this you also have to import gql with Apollo Server.

GraphQL Conventions

  • ENUM names are typically in all CAPS
  • Query names are usually CasedLikeThis
  • Queries themselves are usually casedLikeThis
  • Comments used to be identified with an octothorpe (# this is a comment) but the new way is to use quotes ("this is a comment"). You can also put comment blocks between triple quotes ("""This is a really long comment blah blah blah""")

Further Reading

Here are some links and resources which may also be helpful:

Other Stuff

Last night at codebar I made some progress on writing tests for GFT. Got it up and running, now having a serious think about what to prioritize for writing tests. Also still haven't completely figured out mocking, still working some things out then.

Up Next

The full conference happening tomorrow after today’s workshops!