Introduction to GraphQL
@attheodo
What is GraphQL
- GraphQL is a query language for APIs.
- GraphQL is a server-side runtime for executing queries by using a type system you define for your data.
Where we at now?
- Resources:
REST APIs
http://api.mysite.com/v2/meetups
http://api.mysite.com/v2/meetups/12
http://api.mysite.com/v2/meetups/attendees
http://api.mysite.com/v2/meetups/attendees/13
-
Actions:
- GET, POST, PUT, DELETE
-
Augmentation of HTTP status code for application-level errors:
- 200 (OK), 400 (Bad request )...
- HATEOAS
What's wrong with REST?
- The server determines what data it will send to the client:
GET http://api.mysite.com/v2/meetups/12
{
"meetup": {
"id": 12
"name": "Dead Man's Chest"
"date": "20170221T123446Z"
"attendeesIds": [
123,
12
223
21
]
}
}
-
What if we want to display the attendees names in the same view:
- 4 extra HTTP calls!
What's wrong with REST?
- After popular demand...
GET http://api.mysite.com/v3/meetups/12
{
"meetup": {
"id": 12
"name": "Dead Man's Chest"
"date": "20170221T123446Z"
"attendees": [
{
"id": 123
"name": "Vassilis"
},
{
"id": 12
"name": "George"
}
]
}
}
- Becomes a PITA to manage legacy clients still using v2 API...
What's wrong with REST?
-
You might need a combination of HTTP calls to the API to get the data you need:
- Latency
- Complex error handling
- As the API evolves it's difficult to manage and maintain client & server code compatibility.
In short...
What does GraphQL bring to the table?
-
Ask for what you need and get exactly that:
- The clients control the data they get, not the server.
-
Get many resources in a single request:
- Follow references between resources
- Less HTTP traffic
-
Type system:
- GraphQL uses types to ensure clients only ask for what's possible
- Schema introspection - autogenerated code
-
APIs evolve without versions:
- Type system allows new fields and types to be added.
- Deprecation semantics
GraphQL in a nutshell
-
One endpoint:
- http://api.mysite.com/graphql
-
Queries
- Fetch resources from the server (GET)
-
Mutations
- Modify a resource in the server (POST)
- Response
{
"data": {
... what you asked for ...
}
"errors": [
{
"message": "blah"
}
]
}
GraphQL (Queries)
// Request
{
attendee {
id
name
}
}
// Response
{
"data": {
"attendee": {
"id": 12
"name": "Vassilis"
}
}
}
// Request
{
attendee {
id
name
birthdate
}
}
// Response
{
"data": {
"attendee": {
"id": 12
"name": "Vassilis"
"birthdate": "20170221T123446Z"
}
}
}
GraphQL (Queries with Arguments)
// Request
{
member(id: "12") {
id
name
birthday(type: FORMATTED)
}
}
// Response
{
"data": {
"member": {
"id": 12
"name": "Vassilis"
"birthdate": "13 Jan 1986"
}
}
}
enum argument! Much Wow!
GraphQL (Queries & Aliases)
// Request
{
attendee: member(id: "12") {
id
fullname: name
birthday(type: FORMATTED)
}
}
// Response
{
"data": {
"attendee": {
"id": 12
"fullname": "Vassilis"
"birthdate": "13 Jan 1986"
}
}
}
- If you have naming OCD...
- ... you can basically alias everything to your preferences
GraphQL (Queries & Fragments)
// Request
{
meetup {
id
name
location
start_date
end_date
rsvp_url
cover_photo {
url
size
}
}
}
// Request
{
meetup {
...MeetupDetails
}
}
fragment MeetupDetails on Meetup {
id
name
location
start_date
end_date
rsvp_url
cover_photo {
url
size
}
}
- Allows you to re-use defined subqueries in multiple places
GraphQL (Queries with variables)
// Request
query GetMeetupByStartDate($start_date: Date) {
meetup(start_date: $start_date) {
id
name
location
}
}
{
"start_date": "2017-02-21T16:42:34+00:00"
}
// Response
{
"data": {
"id": 1,
"name": "Dead Man's chest",
"location": "Coho"
}
}
Operation Name
Useful for debugging stuff on the server side
GraphQL (Mutations)
// Request
query CreateMeetup($name: String!, location: String!, $start_date: Date) {
createMeetup(name: $name, location: $location, start_date: $start_date){
id
}
}
{
"name": "The Return of the Mummy",
"location": "OK!Thess"
}
// Response
{
"data": {
"id": 100
}
}
If the type name has no "!", it's optional
$start_date can be omitted from the mutation
GraphiQL
-
Web client for your GraphQL API.
- Let's you create and debug your queries and mutations with ease.
DEMO
Consuming GraphQL APIs from iOS
-
The traditional way:
- Create static methods that return you query/mutation strings.
- Define native objects to get your results de-serialized from the API responses.
Consuming GraphQL APIs from iOS
The traditional way
struct GraphQL {
static func getAttendee(id: String) {
return "query {" +
" attendee(id: \"\(id)\") {" +
" id" +
" name" +
" birthdate" +
" }"+
"}"
}
}
// ... feed it in an Alamofire GET request
final class Attendee: NSObject, ResponseObjectSerializable {
let id: String?
let name: String?
let birthdate: Date?
init?(representation: AnyObject) {
id = representation.value(forKeyPath: "id") as? String
name = representation.value(forKeyPath: "name") as? String
birthdate = representation.value(forKeyPath: "birthdate") as? Date
}
}
Consuming GraphQL APIs from iOS
The traditional way
Consuming GraphQL APIs from iOS
The traditional way
-
You miss all the typed goodness
- Need to replicate server types into native objects
- You don't know whether you query/mutations are valid
-
Creating complex queries is huge PITA
- Creating them on GraphiQL and then pasting them in a one-liner string is the sanest way to do it.
- Fragments?
Consuming GraphQL APIs from iOS
The shiny new toy
A strongly-typed, caching GraphQL client for iOS, written in Swift.
Consuming GraphQL APIs from iOS
APOLLO
1. Download your schema
apollo-codegen download-schema http://localhost:8080/graphql --output schema.json
2. Add a build phase to your project
$APOLLO_FRAMEWORK_PATH/check-and-run-apollo-codegen.sh \
generate $(find . -name '*.graphql') \
--schema schema.json \
--output API.swift
3. Define your queries & mutations in .graphql files
4. Build and enjoy
Consuming GraphQL APIs from iOS
APOLLO
// In Queries.graphql
query GetAttendee {
attendee {
id
name
birthdate
}
}
// In your API class
apollo.fetch(query: GetAttendee()) { (result, error) in
print(result?.data?.attendee?.name) // Vassilis
}
Is GraphQL ready from Prime Time?
Questions?
@attheodo
http://attheo.do
Introduction to GraphQL
By Thanos Theodoridis
Introduction to GraphQL
- 425