GraphQL — с чего начать?

Павел Шалаев (@lawrentiy)

ноябрь 2017

1. Мероприятие

  • Дата
  • Время
  • Название
  • Список участников
  • Создатель

2. Пользователь

  • Имя
  • Роль

3. Роль пользователя: 

  • админ
  • простой пользователь

Схема

Schemas and Types

Type

Fields

Arguments

Scalar types

Enumeration

Lists

Interfaces

Union types

Input types

GraphQL

GraphQL - язык или синтаксис (кому как удобнее).

Позволяет клиенту точно указать, какие данные ему нужны.
Облегчает агрегацию данных из нескольких источников.
Использует систему типов для описания данных.


Построен на трёх основных строительных блоках:

схемaх (schema),

запросах (queries)

решателях (resolvers).


Поддерживают вложенные поля.

Cхема запроса GraphQL и структура базы данных никак не связаны

https://habrahabr.ru/post/326986/

query getMyPost($id: String) {
  post(id: $id){
    title
    body
    author{
      name
      avatarUrl
      profileUrl
    }
  }
}
Query: {
  post(root, args) {
    return Posts.find({ id: args.id });
  }
},
Post: {
  author(post) {
    return Users.find({ id: post.authorId})
  }
}
const typeDefs = `
  type Author {
    id: Int!
    firstName: String
    lastName: String
    posts: [Post] # the list of Posts by this author
  }
  type Post {
    id: Int!
    title: String
    author: Author
    votes: Int
  }
  # the schema allows the following query:
  type Query {
    posts: [Post]
    author(id: Int!): Author
  }
  # this schema allows the following mutation:
  type Mutation {
    upvotePost (
      postId: Int!
    ): Post
  }
`;

Query

Resolvers

Schema

create-react-app

+

apollo-client

react-apollo

graphql

graphql-tag

Запрос

Мутация

Query

Fields

Arguments

Aliases

Fragments

Variables

Directives

Mutations

Inline Fragments

Meta fields

Subscriptions

import * as React from 'react'
import { render } from 'react-dom'

import ApolloClient from 'apollo-client'
import { HttpLink, InMemoryCache } from 'apollo-client-preset'
import { ApolloProvider } from 'react-apollo'
import EventsList from './events/EventsList'
import NewEvent from './events/NewEvent'
import CreateUser from './events/CreateUser'

// Apollo client
const client = new ApolloClient({
    link: new HttpLink({ uri: 'https://api.graph.cool/simple/v1/cja2s8bhwac2c0104via9triy' }),
    cache: new InMemoryCache().restore({})
});

const ApolloApp = (
    <ApolloProvider client={client}>
        <div>
            <NewEvent />
            <CreateUser />
            <EventsList />
        </div>
    </ApolloProvider>
);

render(ApolloApp, document.getElementById('root'));
import * as React from 'react'
import { render } from 'react-dom'

import { graphql } from 'react-apollo'
import gql from 'graphql-tag'

const eventItem = (item) => {
    return <div key={item.id}>
        <b>{item.name}</b>

        <div>{item.users.map(({ name }) => name).join(', ')}</div>
    </div>
};

const EventsList = (props) => {
    const { data } = props;
    const { loading, items } = data;
    // Loading
    if (loading) return <div>loading...</div>;

    // Loaded
    return <div>
        {items.map(eventItem)}
    </div>
};

export const MEETUPS_LIST = gql`
    query {
        items: allMeetups {
        id
        name
        users {
            displayName
        }
    }
    }
`;

export default graphql(MEETUPS_LIST)(EventsList);
import * as React from 'react'
import { render } from 'react-dom'

import { graphql, compose } from 'react-apollo'
import gql from 'graphql-tag'
import {MEETUPS_LIST} from './EventsList'

const NewEvent = (props) => {
    const {mutate} = props;
    const handleKeyUp = (evt) => {
        if (evt.keyCode === 13) {
            mutate({
                variables: { name: evt.target.value },
                optimisticResponse: {
                    create: {
                        users: [{}],
                        name: evt.target.value,
                        id: Math.round(Math.random() * -1000000),
                        __typename: 'Meetup',
                    },
                },
                update: (store, { data: {createMeetup} }) => {
                    // Read the data from the cache for this query.
                    const data = store.readQuery({ query: MEETUPS_LIST });
                    // Add our channel from the mutation to the end.
                    data.items.push(createMeetup);
                    // Write the data back to the cache.
                    store.writeQuery({ query: MEETUPS_LIST, data });
                },
            });
            evt.target.value = '';
        }
    };

    return (
        <input
            type="text"
            placeholder="new event"
            onKeyUp={handleKeyUp}
        />
    );
};

const ADD_EVENT = gql`
    mutation createMeetup($name: String!) {
        createMeetup(name: $name) {
            id
            name
        }
    }
`;

const USER = gql`
    query user {
        user {
            id
            displayName
        }
    }
`;


export default compose(
    graphql(ADD_EVENT, { name: 'createMeetup' }),
    graphql(USER, { name: 'user' }),
)(NewEvent);
{
  "name": "krdf",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "apollo-client": "^2.0.3",
    "apollo-client-preset": "^1.0.3",
    "apollo-test-utils": "^0.3.2",
    "graphql": "^0.11.7",
    "graphql-tag": "^2.5.0",
    "graphql-tools": "^2.7.2",
    "react": "^16.1.1",
    "react-apollo": "^2.0.1",
    "react-dom": "^16.1.1",
    "react-scripts": "1.0.17",
    "subscriptions-transport-ws": "^0.9.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

Resolvers

 

 

Но это совсем другая история....

 

 

Query: {
  post(root, args) {
    return Posts.find({ id: args.id });
  }
},
Post: {
  author(post) {
    return Users.find({ id: post.authorId})
  }
}
Made with Slides.com