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
GraphQL
- 37