Vous êtes sur la page 1sur 10

7/19/2015

Your First GraphQL Server Medium

Your First GraphQL Server


So, today were going to write a small GraphQL server. Im not going to try
to persuade you to drop everything and adopt GraphQLbut if youre
curious about what this stu looks like today and how it works, read on.

Setup an HTTP Server


We need a server to receive our GraphQL queries. Theres nothing in the
GraphQL spec that demands we do this over HTTP, but since the GraphQL
reference implementation is in JavaScript, its expedient to roll a quick
HTTP server with Express.

$mkdirgraphqlintro&&cd./graphqlintro
$npminstallexpresssave
$npminstallbabelsave
$touch./server.js
$touch./index.js

This creates a folder for our project (graphql-intro), and installs Express
and Babel as dependencies. Babel isnt required for GraphQL either, but it
will let us write our JavaScript using ES2015 features that make life easier.
Finally, lets write some code:

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

1/10

7/19/2015

Your First GraphQL Server Medium

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

//index.js
//byrequiring`babel/register`,allofoursuccessive`require`swillbeBabel
require('babel/register')
require('./server.js')

//server.js
importexpressfrom'express'

letapp=express()
letPORT=3000

app.post('/graphql',(req,res)=>{
res.send('Hello!')
})

letserver=app.listen(PORT,function(){
lethost=server.address().address
letport=server.address().port

console.log('GraphQLlisteningathttp://%s:%s',host,port)
})

graphql_1.jshostedwithbyGitHub

viewraw

To run our server, execute:

$nodeindex.js
GraphQLlisteningathttp://0.0.0.0:3000

To test that things are working:

$curlXPOSThttp://localhost:3000/graphql
Hello!

Weve chosen to use an endpoint at /graphql, accessible via HTTP POST,


but there are no hard rulesthe GraphQL spec doesnt dictate how you
communicate to a GraphQL server.

Create a GraphQL Schema


Now that we have a server we can talk to, its time to add some GraphQL.
What does that actually mean?
Lets remind ourselves what a GraphQL request looks like:

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

2/10

7/19/2015

Your First GraphQL Server Medium

querygetHighScore{score}

In this case, our GraphQL client is requesting the `score` sub-eld of the
top-level `getHighScore` eld. Fields are the things we ask a GraphQL
server to return. Fields can also have arguments, like:

querygetHighScores(limit:10){score}

They can do a few more things, but lets move on.


Our GraphQL server needs to be congured to respond to requests like
theseit does this using a schema.
Constructing a schema is analogous to constructing a RESTful route tree.
Our schema will describe what elds the server can respond to and what
types of objects the responses will contain. Type information is very
important to GraphQL, and the client can safely assume that the server will
return consistent types of objects for the same eld (or an error if that
invariant is broken).
As you can imagine, schema denitions can grow pretty meaty. For our
simple GraphQL server, well have one simple eld: `count`.
Back to running commands:

$npminstallgraphqlsave
$npminstallbodyparsersave
$touch./schema.js

This looks promising, right? The GraphQL module contains the GraphQL
technical preview, which allows us to compose our server schema and
process GraphQL requests against it. Body-parser is a simple Express
middleware that we use to grab the GraphQL request being sent.
Time to write our schema:

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

3/10

7/19/2015

Your First GraphQL Server Medium

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

//schema.js
import{
GraphQLObjectType,
GraphQLSchema,
GraphQLInt
}from'graphql/lib/type'

letcount=0

letschema=newGraphQLSchema({
query:newGraphQLObjectType({
name:'RootQueryType',
fields:{
count:{
type:GraphQLInt,
resolve:function(){
returncount
}
}
}
})
})

exportdefaultschema

graphql_2.jshostedwithbyGitHub

viewraw

What were doing here is creating an instance of `GraphQLSchema`, which


takes a big conguration blob. Eventually another part of the GraphQL
library will consume this schema object, but its a reasonable practice to
isolate its construction in a separate le.
In plain english, were conguring the schema to say:
My top-level query object returns a `RootQueryType` object, which has a `count`
eld, which is an integer.
You can imagine there are more scalar types besides integers (strings, lists,
etc.), and that you can nest custom non-scalar types quite deeply.

Connect the Schema


Our fancy schema wouldnt be any good unless we could execute queries
against it. Lets hook up the schema to our HTTP server:

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

4/10

7/19/2015

Your First GraphQL Server Medium

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

importexpressfrom'express'
importschemafrom'./schema'
//newdependencies
import{graphql}from'graphql'
importbodyParserfrom'bodyparser'

letapp=express()
letPORT=3000

//parsePOSTbodyastext
app.use(bodyParser.text({type:'application/graphql'}))

app.post('/graphql',(req,res)=>{
//executeGraphQL!
graphql(schema,req.body)
.then((result)=>{
res.send(JSON.stringify(result,null,2))
})
})

letserver=app.listen(PORT,function(){
varhost=server.address().address
varport=server.address().port

console.log('GraphQLlisteningathttp://%s:%s',host,port)
})

graphql_3.jshostedwithbyGitHub

viewraw

Any POST requests to `/graphql` will now be executed against our


GraphQL schema. We enforce a new content type for these requeststhis
isnt part of the GraphQL spec, but may be a good pattern for servers that
mix GraphQL with existing code.
Restart your server and give it a go:

$node./index.js//restartyourserver
//inanothershell
$curlXPOSTH"ContentType:application/graphql"d'query
RootQueryType{count}'http://localhost:3000/graphql
{
"data":{
"count":0
}
}

Neat! GraphQL also allows us to omit the `query RootQueryType` prex,


but I wanted to show as little magic as possible. Thus, this will also work:

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

5/10

7/19/2015

Your First GraphQL Server Medium

$curlXPOSTH'ContentType:application/graphql'd'{count
}'http://localhost:3000/graphql
{
"data":{
"count":0
}
}

Now that weve got non-zero GraphQL stu working, lets take a minute
to talk about introspection.

Introspect the server


Fun fact: you can write a GraphQL query to ask a GraphQL server about its
elds. Very meta.
Sound crazy? Check this out:

$curlXPOSTH'ContentType:application/graphql'd
'{__schema{queryType{name,fields{name,description}}}}'
http://localhost:3000/graphql
{
"data":{
"__schema":{
"queryType":{
"name":"RootQueryType",
"fields":[
{
"name":"count",
"description":null
}
]
}
}
}
}

Heres the query we issued, but more readable:

{
__schema{
queryType{
name,
fields{
name,
description
}
}
}
}

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

6/10

7/19/2015

Your First GraphQL Server Medium

Basically, each GraphQL root eld automatically has a `__schema` eld,


which has its own elds that we can query againstin particular, the
`queryType` eld. Every eld can be queried for meta-information, such as
the name.
More interestingly, you can attach useful human-level metadata like
`description`, `isDeprecated`, and `deprecationReason` to elds. Facebook
says their tooling uses this metadata to build better developer experiences
(i.e. when you use a deprecated eld, you see a red squiggly).
To make this perfectly clear, heres how we add a `description` to our
current schema:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

letschema=newGraphQLSchema({
query:newGraphQLObjectType({
name:'RootQueryType',
fields:{
count:{
type:GraphQLInt,
//addthedescription
description:'Thecount!',
resolve:function(){
returncount
}
}
}
})
})

graphql_4.jshostedwithbyGitHub

viewraw

Restart the server and see the new metadata appear:

$curlXPOSTH'ContentType:application/graphql'd
'{__schema{queryType{name,fields{name,description}}}}'
http://localhost:3000/graphql
{
"data":{
"__schema":{
"queryType":{
"name":"RootQueryType",
"fields":[
{
"name":"count",
"description":"Thecount!"
}
]
}

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

7/10

7/19/2015

Your First GraphQL Server Medium

}
}
}

Were almost done with our whirlwind tour of GraphQLfor my last trick,
Ill show o mutations.

Add a Mutation
If you want read-only access to a bunch of data, then you probably dont
need to read any further. But for most applications, were going to have to
change our data. GraphQL calls these operations mutations.
Mutations are just elds that are intended to have side-eects, so most of
the syntax is identical. Like normal query elds, mutation elds must also
return a typed valuethe intent is that if you mutate something, you
should also return whatever it mutated.
How do we add mutations to our schema? Much like we dene a top-level
`query` key on our schema, we will also dene a top-level `mutation` key:

letschema=newGraphQLSchema({
query:...
mutation://todo
)}

Besides going in a dierent location, how are mutations dierent? We could


have made our `count` eld function update our counter or do some other
mutative action and GraphQL would have no way of knowing.
The meaningful dierence between a mutation and a query is that
mutations are processed serially, but queries make no such guarantee (in fact,
GraphQL encourages servers to exploit the inherent parallelism of
independent queries). The GraphQL spec gives this example of a set of
mutation queries that must be processed by the server in order:

{
first:changeTheNumber(newNumber:1){
theNumber
},
second:changeTheNumber(newNumber:3){
theNumber
},
third:changeTheNumber(newNumber:2){
theNumber

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

8/10

7/19/2015

Your First GraphQL Server Medium

}
}

Thus, by the end of the request, `theNumber` eld should have the value of
`2`.
Lets add a simple mutation that updates our counter and returns the value:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

letschema=newGraphQLSchema({
query
mutation:newGraphQLObjectType({
name:'RootMutationType',
fields:{
updateCount:{
type:GraphQLInt,
description:'Updatesthecount',
resolve:function(){
count+=1
returncount
}
}
}
})
})

graphql_5.jshostedwithbyGitHub

viewraw

Restart your server and give it a try:

$curlXPOSTH'ContentType:application/graphql'd'mutation
RootMutationType{updateCount}'http://localhost:3000/graphql
{
"data":{
"updateCount":1
}
}

Boomthe data has been updated. You can conrm this with a new query:

$curlXPOSTH'ContentType:application/graphql'd'{count
}'http://localhost:3000/graphql
{
"data":{
"count":1
}
}

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

9/10

7/19/2015

Your First GraphQL Server Medium

You can do it as many times as you likemutable state is entertaining.


In a proper GraphQL implementation, we would probably wrap our counter
in a semantic value (like `CountValue`), which would be more meaningfully
returned from both the query and the mutation.

Wrapping Up
Thats a whirlwind tour of how you can use GraphQL today using
Facebooks JavaScript implementation. I didnt cover some more powerful
topicselds with arguments, resolving promises, fragments, directives
theres lots of cool things in the GraphQL spec. Theres also room for new
implementations and schema APIs on the server side. You can imagine a
GraphQL server written in a typed language like Java might look quite
dierent than how it looks in JavaScript.
This is also based on my 48-hour experience with GraphQLif theres
anything missing or wrong, dont hesitate to let me know. You can view the
source (each commit is a new step) here:
https://github.com/clayallsopp/graphql-intro
Thanks to the RisingStack folks for their excellent post and example on
GraphQL.

https://medium.com/@clayallsopp/your-first-graphql-server-3c766ab4f0a2

10/10

Vous aimerez peut-être aussi