/notes/:name
/notes/:name/comments
? /notes/:name/comments/authors
? /users/:id
? /notes/:name/comments_with_authors
Язык запросов к API, а так же среда исполнения для этих запросов
query {
note(name: "Books") {
name
text
comments {
text
author {
name
}
}
}
}
ID, Int, Float, String, Boolean
|
|
|
|
type Admin {
id: ID
name: String
accessLevel: String
}
type NormalUser {
id: ID
name: String
age: Int
}
union User = Admin | NormalUser
|
|
|
|
|
|
query NotesQuery {
firstNote: note(name: "Books") {
text
}
secondNote: note(name: "Films") {
text
}
}
fragment NoteFields on Note {
id
name
text
}
query {
firstNote: note(name: "Books") {
...NoteFields
}
secondNote: note(name: "Films") {
...NoteFields
}
}
query {
users {
__typename
... on Admin {
name
accessLevel
}
... on NormalUser {
name
age
}
}
}
query NoteQuery($name: String!) {
note(name: $name) {
name
text
}
}
// Variables
{ "name": "Books" }
query NoteQuery($name: String!, $withComments: Boolean!) {
note(name: $name) {
name
text
comments @include(if: $withComments) {
text
}
}
}
query NoteQuery($name: String!, $withoutComments: Boolean!) {
note(name: $name) {
name
text
comments @skip(if: $withoutComments) {
text
}
}
}
mutation CreateNote($name: String!, $text: String!) {
createNote(name: $name, text: $text) {
name
text
}
}
$ npm install --save graphql
const { graphql, buildSchema } = require('graphql');
const notes = [
{ name: 'Films', text: 'Films to watch' },
{ name: 'Books', text: 'Books to read' }
];
const schema = buildSchema(`
type Note {
name: String
text: String
}
type Query {
note(name: String!): Note
}
`);
const resolvers = {
note: args => notes.find(note => note.name === args.name)
};
const query = `
query {
note(name: "Books") {
text
}
}
`;
graphql(schema, query, resolvers).then(response => {
// { data: { note: { text: "Books to read" } } }
});
const schema = buildSchema(`
type Note {
name: String
text: String
}
type Mutation {
createNote(name: String!, text: String!): Note
}
`);
const resolvers = {
createNote: args => {
const note = { name: args.name, text: args.text };
notes.push(note);
return note;
}
};
const mutation = `
mutation {
createNote(name: "Music", text: "Music to listen") {
name
text
}
}
`;
graphql(schema, mutation, resolvers).then(response => {
// {"data": { "createNote": { "name": "Music", "text": "Music to listen" }}}
});
$ npm install --save express express-graphql
const express = require('express');
const graphql = require('express-graphql');
const schema = require('./schema');
const server = express();
server.use('/graphql', graphql({ schema, graphiql: true }));
server.listen(4000, () => {
console.log('Listening on http://localhost:4000/graphql');
});
const { GraphQLID, GraphQLString, GraphQLObjectType } = require('graphql');
const UserType = new GraphQLObjectType({
name: 'User',
fields: {
id: { type: GraphQLID },
name: { type: GraphQLString }
}
});
const { GraphQLString, GraphQLObjectType } = require('graphql');
const CommentType = new GraphQLObjectType({
name: 'Comment',
fields: {
text: { type: GraphQLString },
author: { type: UserType }
}
});
const {
GraphQLList, GraphQLID, GraphQLString, GraphQLObjectType
} = require('graphql');
const NoteType = new GraphQLObjectType({
name: 'Note',
fields: {
id: { type: GraphQLID },
name: { type: GraphQLString },
text: { type: GraphQLString },
comments: {
type: new GraphQLList(CommentType),
resolve: parentValue =>
comments.filter(comment => comment.noteId === parentValue.id)
}
}
});
const Query = new GraphQLObjectType({
name: 'Query',
fields: {
note: {
type: NoteType,
args: {
name: {
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (parentValue, { name }) =>
notes.find(note => note.name === name)
}
}
});
const Mutation = new GraphQLObjectType({
name: 'Mutation',
fields: {
createNote: {
type: NoteType,
args: {
name: new GraphQLNonNull(GraphQLString),
text: new GraphQLNonNull(GraphQLString)
},
resolve: (parentValue, { name, text }) => {
const note = { name, text };
notes.push(note);
return note;
}
}
}
});
module.export = new GraphQLSchema({
query: Query,
mutation: Mutation
});
|
|
{
"data": null,
"errors": [
{
"code": "UNQ",
"message": "Fields must be unique",
"details": {
"fields": [
"name"
]
}
}
]
}
Lokka | Максимально простой в использовании. Базовая поддержка запросов и мутаций. Простейшее кэширование |
Apollo | Более гибкий. Хороший баланс между функциональностью и сложностью использования |
Relay | Наиболее функциональный, из-за чего наиболее сложный в использовании. Много внимания уделено производительности (особенно на мобильных). |
$ npm install --save react-apollo apollo-client-preset graphql-tag graphql
import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloProvider } from 'react-apollo';
import ApolloClient from 'apollo-client-preset';
const client = new ApolloClient();
ReactDOM.render(
<ApolloProvider client={client}>
<Note name="Books" />
</ApolloProvider>,
document.getElementById('root')
);
import gql from 'graphql-tag';
const query = gql`
query Note($name: String!) {
note(name: $name) {
name
text
}
}
`;
function logProps(WrappedComponent) {
return class extends React.Component {
static getDerivedStateFromProps(nextProps) {
console.log('Current props: ', this.props);
console.log('Next props: ', nextProps);
return null;
}
render() {
return <WrappedComponent {...this.props} />;
}
}
}
import React from 'react';
import { graphql } from 'react-apollo';
function Note({ data }) {
return (
<React.Fragment>
<h1>{data.name}</h1>
<p>{data.text}</p>
</React.Fragment>
);
}
export default graphql(query, {
options: props => ({ variables: { name: props.name } })
})(Note);
Uncaught TypeError: Cannot read property name of undefined
function Note({ data }) {
if (data.loading) {
return 'Loading...';
}
return (
<React.Fragment>
<h1>{data.name}</h1>
<p>{data.text}</p>
</React.Fragment>
);
}
class Form extends React.Component {
state = { name: '', text: '' }
handleSubmit = () => this.makeSomeApiRequest(this.state.name, this.state.text)
handleNameChange = event => this.setState({ name: event.target.value })
handleTextChange = event => this.setState({ text: event.target.value })
render() {
const { name, text } = this.state;
return (
<div>
<input value={name} onChange={this.handleNameChange} />
<textarea value={text} onChange={this.handleTextChange} />
<button onClick={this.handleSubmit}>
Отправить
<button>
</div>
);
}
}
const mutation = gql`
mutation CreateNote($name: String!, $text: String!) {
createNote(name: $name, text: $text) {
id
}
}
`;
export default graphql(mutation)(Form);
class Form extends React.Component {
...
handleSubmit = () => {
const { mutate } = this.props;
const { name, text } = this.state;
mutate({ variables: { name, text } })
.then(() => { ... })
.catch(() => { ... })
}
...
}
|
|
|
|
class Form extends React.Component {
...
handleSubmit = () => {
const { mutate } = this.props;
const { name, text } = this.state;
mutate({
variables: { name, text },
refetchQueries: ['Notes']
})
.then(() => { ... })
.catch(() => { ... })
}
...
}
export default graphql(createNoteMutation)(graphql(notesQuery))(IndexPage));
):
import { compose } from 'react-apollo';
// compose(f, g, h)(x) === f(g(h(x)))
compose(
graphql(createNoteMutation),
graphql(notesQuery)
)(IndexPage);
(: