Espen Henriksen

Front-end team lead

Oslo Market Solutions

 

espen_dev

  • One of the leading Nordic suppliers of internet-based financial solutions
  • Oslo based
  • Part of the Oslo Børs VPS corporation
  • Focus on real-time and delayed streaming of market data from many financial markets
  • We also develop stock and fund trading platforms

The theme

The challenge was to talk about:

"How we work with Front-end, What challenges do we see, What does the future looks like."

This talk will focus mostly on the latter. While we do lots of exciting stuff, I have been dying to talk about this for some time.

GraphQL

Why?

Isn't REST the best?

  • REST is good, but has some shortcomings
  • Developed between 1996-1999, the web has changed significantly in that timeframe
  • What used to be single documents has turned into rich web applications
  • GraphQL builds on what we've learned from REST over the years

Horizontal growth

  • A REST API grows horizontally, adding more endpoints as needed
  • Thus, loading a page typically requires many requests
    • More HTTP calls means longer loading time, especially on mobile
  • Many REST endpoints typically means it's hard to provide API compatible changes without deprecating or making incompatible changes
  • Adding a new endpoint does not give the other endpoints any new features

A typical modern website

API documentation

  • APIs have grown in complexity
  • REST was never designed for the complex nature of modern applications
  • No standard way to document an API or describe what is possible
  • Existing solutions like swagger are a band-aid on this glaring omission

Validation

  • REST was not designed with input/output validation in mind
  • As a result, this is almost always an after-thought when designing an API
  • Many developers forget validation all together and set themselves up for bugs

Transfer protocol

  • No standard way to structure data
    • JSON
    • JSONP
    • XML
    • application/x-www-urlencoded
    • multipart/form-data
  • Example: yr.no API

What?

A query language

  • Developed by Facebook and community
  • Designed to scale to Facebook's needs
  • The client decides what data is delivered, not the developer of the REST endpoint
  • Uses a singular endpoint to handle all requests
  • Enables fetching many resources in a single request
    • Fragments

A query

# The type of operation
# + human-readable name of 
#   this operation
query GetAllUsers {

  # The field on the root query
  # we are requesting
  allUsers {

    # The fields on the User
    # object we need
    id
    name
  }
}
# Might return:
{
  "allUsers": [{
    "id": 1,
    "name": "Luke Skywalker"
  }]
}

Mutations

# The type of operation
# + human-readable name of this operation
# + input we require for this mutation
mutation CreateNewUser($name: String!) {

  # The mutation we want to run
  createUser(name: $name) {

    # The fields on the User object we want back on success
    id
    name
  }
}

# variables
{"name": "Espen Henriksen"}

Schema

  • A GraphQL API is strongly typed with a so called "schema"
  • Core concepts of schema
    • Object types (like User) will have fields (like name)
    • A field always has a type, be that an object type or a scalar type (like String or Integer).
    • Developers can use built-in scalar types or define their own (like Date)
  • Types can reference other types, creating a graph of references

A schema

# NOTE: We define this here, and implement it in code elsewhere
scalar Date

# A user of the system
type User {
  id: ID!
  # The full name of this user. Upside down if australian
  name: String!
  # The posts this user has published
  posts: [Post]!
}

# A textual post
type Post {
  id: ID!
  # The user's chosen post title
  title: String!
  # The date this was published
  publishedAt: Date
}

type Query {
  # Get all the users of the system
  allUsers: [User]!
  # Get a single user by id
  user(id: ID!): User!
}

Demo

http://graphql.org/swapi-graphql

Why you should consider GraphQL for your next project

Vertical growth

  • Instead of adding new endpoints when expanding, you expand your schema in the GraphQL endpoint
  • Instead of coding how to fetch the data from a server, you describe types with fields and how to fetch those types
  • Adding a new field to a type will make it accessible all the places that type is used

Documentation as a first-class citizen

  • Your schema is automatically exposed
  • Schema describes what is possible with the API, and thus enables building great API explorers
  • Describing fields and types with comments is built-in to the schema
  • Demo: GraphiQL

Built-in validation

  • The schema describes what is possible
  • Fields can be marked with not-null (!)
  • Any extra fields you send that are not described in the schema are stripped from the response
  • Resources that send null values for non-nullable fields will instead return an error
    • If one resource returns an error, the rest of the resources can still return data. This is NOT REST

Transfer protocol

  • json
  • json
  • json
  • json
  • json
  • json
  • json all the way to the bank

Built with modern apps in mind

  • Optimizes data fetching to be concurrent automatically
  • Some libraries leverage GraphQL to provide powerful features like optimistic updates with rollback
  • GraphQL subscriptions render changes on the server immediately on the client
  • Many libraries implement a client-side store (sort of like redux) to prevent re-fetching automatically
  • Built to make powerful devtools possible

How?

Define a schema

type Query {
  user(id: ID!): User
}

type User {
  id: ID!
  name: String
}

Define fetchers

// resolvers.js
import { User } from './connectors';

export default {
  Query: {
    user(_, args) {
      return User.findAll({ where: args });
    },
  }
}

Expose the API

// server.js
import express from 'express'
import bodyParser from 'body-parser';
import { graphqlExpress } from 'apollo-server-express';
import { makeExecutableSchema } from 'graphql-tools';

import typeDefs from './graphql/schema';
import resolvers from './graphql/resolvers';

const schema = makeExecutableSchema({
  typeDefs,
  resolvers,
});

const app = express();
app.use('/graphql', bodyParser.json(), graphqlExpress({ schema }));

app.listen(4000);

Server done!

Now the client..

Define a component

const MyName = (props) => {
  const {
    data: {
      loading,
      error,
      user,
    },
  } = props;

  if (error) return `An error occured: ${error}`;
  if (loading) return <p>Loading...</p>;
  return <p>My name is {user.name}</p>;
};

const getUser = gql`
  query getUser {
    user(id: 1) {
      id
      name
    }
  }
`

export default graphql(getUser)(MyName)

Set up connector

import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'

const uri = 'http://localhost:4000/graphql';
const apollo = new ApolloClient({
  link: new HttpLink({ uri }),
  cache: new InMemoryCache(),
});

ReactDOM.render(
  <ApolloProvider client={apollo}>
    <YourApp />
  </ApolloProvider>,
  document.getElementById('root'),
);

Client done!

Wait, that's it..?

Nah, you need to install some stuff, but I leave that up to you

What libraries to use?

Client libraries

  • Relay (Facebook)
  • Apollo
  • graph.cool (BaaS)
  • There exist clients for iOS and Android too

Server libraries

Most importantly

  • Start thinking in graphs
  • Your data can most likely be modeled as a graph

Thanks for listening!

Slides:

http://slides.com/esphen/graphql

 

More about us:

https://www.oms.no

Questions?

GraphQL

By Eline H