刘俊峰
2017-12-01
GraphQL 是一种适用于 API 的数据查询语言。
仅仅是一种规范,可以有各种前后端的实现方案。
Facebook 于 2012 年开发,2015 年开源。
支持多种操作:query 是查询,mutation 是修改
Every GraphQL service has a query type and may or may not have a mutation type.
schema {
query: Query
mutation: Mutation
}
type Query {
hero(episode: Episode): Character
droid(id: ID!): Droid
}
type Character {
name: String!
appearsIn: [Episode]!
}
type Starship {
id: ID!
name: String!
length(unit: LengthUnit = METER): Float
}
Every GraphQL service defines a set of types which completely describe the set of possible data you can query on that service.
enum Episode {
NEWHOPE
EMPIRE
JEDI
}
union SearchResult = Human | Droid | Starship
interface Character {
id: ID!
name: String!
friends: [Character]
appearsIn: [Episode]!
}
input ReviewInput {
stars: Int!
commentary: String
}
{
hero(id: "1000") {
name
height
# Queries can have comments!
friends {
name
}
}
empireHero: hero(episode: EMPIRE) {
name
}
jediHero: hero(episode: JEDI) {
name
}
}
While query fields are executed in parallel, mutation fields run in series, one after the other.
Returned result mirrors the shape of the requested query, typically as JSON.
GraphQL server does this automatically, developer only need to write resolvers.
yarn add apollo-client apollo-cache-inmemory apollo-link-http react-apollo graphql-tag graphql
// App.jsx
import { ApolloProvider } from 'react-apollo';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
const client = new ApolloClient({
// By default, this client will send queries to the
// `/graphql` endpoint on the same host
// Pass the configuration option { uri: YOUR_GRAPHQL_API_URL } to the `HttpLink` to connect
// to a different host
link: new HttpLink(),
cache: new InMemoryCache()
});
ReactDOM.render(
<ApolloProvider client={client}>
<MyRootComponent/>
</ApolloProvider>,
document.getElementById('root'),
);
// TodoApp.jsx
import { graphql } from 'react-apollo';
import gql from 'graphql-tag';
export default graphql(gql`
query TodoAppQuery {
todos {
id
text
}
}
`)(TodoApp);
function TodoApp({ data: { todos, refetch } }) {
return (
<div>
<button onClick={() => refetch()}>
Refresh
</button>
<ul>
{todos && todos.map(todo => (
<li key={todo.id}>
{todo.text}
</li>
))}
</ul>
</div>
);
}
Text
import { makeExecutableSchema } from 'graphql-tools';
const typeDefs = `
type Author {
id: Int
firstName: String
lastName: String
posts: [Post]
}
type Post {
id: Int
title: String
text: String
views: Int
author: Author
}
type Query {
author(firstName: String, lastName: String): Author
getFortuneCookie: String
}
`;
const resolvers = {
Query: {
author(root, args){
return { id: 1, firstName: 'Hello', lastName: 'World' };
},
},
Author: {
posts(author){
return [
{ id: 1, title: 'A post', text: 'Some text', views: 2},
{ id: 2, title: 'Another post', text: 'Some other text', views: 200}
];
},
},
Post: {
author(post){
return { id: 1, firstName: 'Hello', lastName: 'World' };
},
},
};
export default makeExecutableSchema({ typeDefs, resolvers });
// routes.js
const database = require('./database');
const schema = require('./graphql/schema');
const graphql = new Router();
graphql.post('/graphql',graphqlKoa({ schema, context: {database} }));
graphql.get('/graphiql', graphiqlKoa({ endpointURL: '/graphql' }));