What The Hell

is graphql

Ramsay Lanier

In a nutshell, graphql
is a query language for your api

in fact, graphql is a replacement for rest

 

Benefits over rest:

Inherently self documenting

More efficient (less server round trips)

Better developer tools

Easier to secure

The graphql architecture

source: https://kadira.io

GraphQL Queries

The shape of the resulting data is the exact same shape as our query. 

Same thing, but with variables and a named query

You can even give your data fields Aliases.

GraphQL Type Language

  type Post {
    id: Int
    post_title: String
    post_content: String
    post_excerpt: String
    post_status: String
    post_type: String
    post_name: String
    post_parent: Int
    menu_order: Int
    layout: Postmeta
    thumbnail: String
  }
  type Postmeta {
    id: Int
    meta_id: Int
    post_id: Int
    meta_key: String
    meta_value: String
  }
  type Menu {
    id: ID!
    name: String
    items: [MenuItem]
  }

  type MenuItem {
    id: ID!
    post_title: String
    linkedId: Int
    object_type: String
    order: Int
    navitem: Post
    children: [MenuItem]
  }
  type Query {
    posts(post_type: String = "post", limit: Int, skip: Int): [Post]
    menus(name: String): Menu
    post(name: String, id: Int): Post
  }

  schema {
    query: Query
  }

Lastly, you need a Query type which serves as the root query. You then need a schema which contains the root query. 

  type Menu {
    id: ID!
    name: String
    items: [MenuItem]
  }

  type MenuItem {
    id: ID!
    post_title: String
    linkedId: Int
    object_type: String
    order: Int
    navitem: Post
    children: [MenuItem]
  }

  type Post {
    id: Int
    post_title: String
    post_content: String
    post_excerpt: String
    post_status: String
    post_type: String
    post_name: String
    post_parent: Int
    menu_order: Int
    thumbnail: String
  }

  type Query {
    posts(post_type: String = "post", limit: Int, skip: Int): [Post]
    menus(name: String): Menu
    post(name: String, id: Int): Post
  }

  schema {
    query: Query
  }

GraphQL Resolvers

  const Resolvers = {
    Query: {
      posts(_, args) {
        return GetPosts(args);
      },
      menus(_, {name}) {
        return GetMenu(name);
      },
      post(_, {name, id}) {
        if (name) {
          return GetPostByName(name, id);
        }
        return GetPostById(id);
      }
    },

    // more stuff here
    ...
  };
  type Query {
    posts(post_type: String = "post", limit: Int, skip: Int): [Post]
    menus(name: String): Menu
    post(name: String, id: Int): Post
  }

  schema {
    query: Query
  }
      

getPosts({ post_type, limit = 10, skip = 0 }) {
  return Post.findAll({
    where: {
      post_type,
      post_status: 'publish'
    },
    limit: limit,
    offset: skip
  });
}

Putting it together with apollostack

Apollo is an incrementally-adoptable data stack that manages the flow of data between clients and backends.

 Based on GraphQL, it gives you a principled, unified, and scalable API for developing modern apps on top of services.

LEARN MORE

Apollo server

import express from 'express';
import bodyParser from 'body-parser';
import { apolloExpress, graphiqlExpress } from 'apollo-server';
import { makeExecutableSchema } from 'graphql-tools';
import { Definitions, Resolvers } from './schema/schema';

const APP_PORT = 3000;
const app = express();

const executableSchema = makeExecutableSchema({
  typeDefs: Definitions,
  resolvers: Resolvers
});

app.use('/graphql', bodyParser.json(), apolloExpress({
  schema: executableSchema,
  context: {}
}));

app.use('/graphiql', graphiqlExpress({
  endpointURL: '/graphql',
}));

app.listen(APP_PORT, () => console.log(
  `GraphQL Server is now running on http://localhost:${APP_PORT}`
));
{
  "query": "query getPost{ post(name: $postName) }",
  "operationName": "getPost",
  "variables": { "postName": "homepage" }
}

Apollo Server accepts only JSON-encoded POST requests. A valid request must contain either a query or an operationName(or both, in case of a named query), and may include variables. For example:

Apollo Client

IN REACT

import React from 'react';
import { render } from 'react-dom';
import { ApolloProvider } from 'react-apollo';
import { Router, browserHistory } from 'react-router';
import routes from './routes';
import ApolloClient from 'apollo-client';

// By default, this client will send queries to the
//  `/graphql` endpoint on the same host
const client = new ApolloClient();

render(
  <ApolloProvider client={client} store={store}>
    <Router history={browserHistory} routes={routes}></Router>
  </ApolloProvider>,
  document.getElementById('root')
)

IN REACT

import React from 'react';
import Page from '../pages/page.js';
import PostContent from '../posts/PostContent';
import { graphql } from 'react-apollo';
import gql from 'graphql-tag'

class FrontPageLayout extends React.Component{
  render(){
    const { loading } = this.props.data;
    

    if (loading){
      return (
        <div>Loading...</div>
      )
    } else {
      const { post_title, post_content, thumbnail} = data.page;
      return (
        <div styleName="content">
          <div styleName="wrapper tight">
            <h1 styleName="title">{post_title}</h1>
            <PostContent post_content={post_content}/>
          </div>
        </div>
      )
    }
  }
}

const GetPage = gql`
query getPage{
  page(post_name: "homepage"){
    id,
    post_title,
    post_content,
    thumbnail
  }
}
`;

const FrontPageWithData = graphql(GetPage)(FrontPageLayout);

export default FrontPageWithData;
Made with Slides.com