View
1.972
Download
1
Category
Preview:
Citation preview
Interfacing with GraphQL in SwiftSommer Panage • @sommer
1 — Sommer Panage • @sommer • Swift Summit 2016
Hello!
2 — Sommer Panage • @sommer • Swift Summit 2016
What is GraphQL?
3 — Sommer Panage • @sommer • Swift Summit 2016
The GraphQL Schema
type User { name: String! id: Int! email: String twitter: String}
4 — Sommer Panage • @sommer • Swift Summit 2016
Instead of hitting a REST endpoint like...
https://mybackend.com/api/user?id=1
5 — Sommer Panage • @sommer • Swift Summit 2016
I write a query like...
{ user(id: 1) { name email twitter }}
And send it to my GraphQL endpointhttps://mybackend.com/graphql
6 — Sommer Panage • @sommer • Swift Summit 2016
And I get back a JSON response like...
{ "data": { "name": "Sommer Panage", "email": "sommer@panage.org", "twitter": "@sommer" }}
7 — Sommer Panage • @sommer • Swift Summit 2016
Why is GraphQL such a big deal for mobile?
8 — Sommer Panage • @sommer • Swift Summit 2016
Let's write an app
9 — Sommer Panage • @sommer • Swift Summit 2016
In a REST world, we'd hit this endpoint:
http://swapi.co/api/people/1/
And we'd get back...
10 — Sommer Panage • @sommer • Swift Summit 2016
{ "name": "Luke Skywalker", "height": "1.72 m", "mass": "77 Kg", "hair_color": "Blond", "skin_color": "Caucasian", "eye_color": "Blue", "birth_year": "19 BBY", "gender": "Male", "homeworld": "http://swapi.co/api/planets/1/", "films": [ "http://swapi.co/api/films/1/", "http://swapi.co/api/films/2/", "http://swapi.co/api/films/3/" ], "species": [ "http://swapi.co/api/species/1/" ], "vehicles": [ "http://swapi.co/api/vehicles/14/", "http://swapi.co/api/vehicles/30/" ], "starships": [ "http://swapi.co/api/starships/12/", "http://swapi.co/api/starships/22/" ], "created": "2014-12-09T13:50:51.644000Z", "edited": "2014-12-10T13:52:43.172000Z", "url": "http://swapi.co/api/people/1/", "image_url": "http://static.srcdn.com/wp-content/uploads/luke-skywalker-star-wars-a-new-hope.jpg"}
11 — Sommer Panage • @sommer • Swift Summit 2016
And then...we'd make two more calls to...
http://swapi.co/api/starships/12/and
http://swapi.co/api/starships/22/
12 — Sommer Panage • @sommer • Swift Summit 2016
{ "name": "X-wing", "model": "T-65 X-wing", "manufacturer": "Incom Corporation", "cost_in_credits": "149999", "length": "12.5", "max_atmosphering_speed": "1050", "crew": "1", "passengers": "0", "cargo_capacity": "110", "consumables": "1 week", "hyperdrive_rating": "1.0", "MGLT": "100", "starship_class": "Starfighter", "pilots": [ "http://swapi.co/api/people/1/", "http://swapi.co/api/people/9/", "http://swapi.co/api/people/18/", "http://swapi.co/api/people/19/" ], "films": [ "http://swapi.co/api/films/3/", "http://swapi.co/api/films/2/", "http://swapi.co/api/films/1/" ], "created": "2014-12-12T11:19:05.340000Z", "edited": "2014-12-22T17:35:44.491233Z", "url": "http://swapi.co/api/starships/12/"}
13 — Sommer Panage • @sommer • Swift Summit 2016
{ "name": "Imperial shuttle", "model": "Lambda-class T-4a shuttle", "manufacturer": "Sienar Fleet Systems", "cost_in_credits": "240000", "length": "20", "max_atmosphering_speed": "850", "crew": "6", "passengers": "20", "cargo_capacity": "80000", "consumables": "2 months", "hyperdrive_rating": "1.0", "MGLT": "50", "starship_class": "Armed government transport", "pilots": [ "http://swapi.co/api/people/1/", "http://swapi.co/api/people/13/", "http://swapi.co/api/people/14/" ], "films": [ "http://swapi.co/api/films/3/", "http://swapi.co/api/films/2/" ], "created": "2014-12-15T13:04:47.235000Z", "edited": "2014-12-22T17:35:44.795405Z", "url": "http://swapi.co/api/starships/22/"}
14 — Sommer Panage • @sommer • Swift Summit 2016
That's 3 calls and a whole lot of data for 1 little VC
15 — Sommer Panage • @sommer • Swift Summit 2016
Now in GraphQL, instead we'd write the following query:
{ person(personID: 1) { name, height, mass, hairColor, eyeColor, imageURL, starshipConnection { edges { node { name } } } }}
16 — Sommer Panage • @sommer • Swift Summit 2016
And, I'd get back exactly what I wanted!
{ "data": { "person": { "name": "Luke Skywalker", "height": 172, "mass": 77, "hairColor": "blond", "eyeColor": "blue", "imageURL": "http://static.srcdn.com/wp-content/uploads/luke-skywalker-star-wars-a-new-hope.jpg", "starshipConnection": { "edges": [ { "node": { "name": "X-wing" } }, { "node": { "name": "Imperial shuttle" } } ] } } }}
17 — Sommer Panage • @sommer • Swift Summit 2016
So, why is GraphQL such a big deal for mobile?
1. Ask and ye shall receive!2. Fewer round trips!
3. Less client logic around data!
18 — Sommer Panage • @sommer • Swift Summit 2016
Wait just a minute...
19 — Sommer Panage • @sommer • Swift Summit 2016
Our Star Wars Character modelstruct SWCharacter { let name: String let heightInCm: Int let massInKg: Int let hairColorDescriptor: String let skinColorDescriptor: String let eyeColorDescriptor: String let birthYear: StarWarsUniverse.Year let gender: StarWarsUniverse.Gender let homeworld: StarWarsUniverse.Planet let films: [SWFilm] let species: [StarWarsUniverse.Species] let vehicles: [StarWarsUniverse.Vehicle] let starships: [StarWarsUniverse.Starship] let imageURL: URL?}
20 — Sommer Panage • @sommer • Swift Summit 2016
Our Star Wars Character modelstruct SWCharacter { let name: String? let heightInCm: Int? let massInKg: Int? let hairColorDescriptor: String? let skinColorDescriptor: String? let eyeColorDescriptor: String let birthYear: StarWarsUniverse.Year? let gender: StarWarsUniverse.Gender? let homeworld: StarWarsUniverse.Planet? let films: [SWFilm]? let species: [StarWarsUniverse.Species]? let vehicles: [StarWarsUniverse.Vehicle]? let starships: [StarWarsUniverse.Starship]? let imageURL: URL?}
21 — Sommer Panage • @sommer • Swift Summit 2016
Swift, No!!!!struct SWCharacter { let name: String? let heightInCm: Int? let massInKg: Int? let hairColorDescriptor: String? let skinColorDescriptor: String? let eyeColorDescriptor: String let birthYear: StarWarsUniverse.Year? let gender: StarWarsUniverse.Gender? let homeworld: StarWarsUniverse.Planet? let films: [SWFilm]? let species: [StarWarsUniverse.Species]? let vehicles: [StarWarsUniverse.Vehicle]? let starships: [StarWarsUniverse.Starship]? let imageURL: URL?}
22 — Sommer Panage • @sommer • Swift Summit 2016
23 — Sommer Panage • @sommer • Swift Summit 2016
Let's model the data how we want it, not how it is
→ 1 View Controller→ 1 Query
→ 1 Data Model
24 — Sommer Panage • @sommer • Swift Summit 2016
25 — Sommer Panage • @sommer • Swift Summit 2016
query AllCharacters { allPeople { edges { node { id name homeworld { name } } } }}
26 — Sommer Panage • @sommer • Swift Summit 2016
struct AllCharactersData { let people: [Person]
struct Person { let id: String let name: String let homeworld: Homeworld
struct Homeworld { let name: String } }}
27 — Sommer Panage • @sommer • Swift Summit 2016
query Character($id: ID) { person (id: $id) { id height, mass, hairColor, eyeColor, imageURL, starshipConnection { edges { node { name } } } } }
28 — Sommer Panage • @sommer • Swift Summit 2016
struct CharacterData { struct Person { let id: String let height: Int let mass: Int let hairColor: String let eyeColor: String let imageURL: URL? let starshipConnect: [Starship]
struct Starship { let name: String } }}
29 — Sommer Panage • @sommer • Swift Summit 2016
By having query / view-data based models, we
no longer need optionals everywhere!
30 — Sommer Panage • @sommer • Swift Summit 2016
But our parsing code still looks like...let parsedData = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any]self.id = parsedData["id"] as! Stringself.name = parsedData["name"] as! Stringself.homeworld = Homeworld(dict: parsedData["homeworld"] as! [String : Any])
Ugh!
31 — Sommer Panage • @sommer • Swift Summit 2016
Code Gen!
32 — Sommer Panage • @sommer • Swift Summit 2016
33 — Sommer Panage • @sommer • Swift Summit 2016
Apollo's iOS GraphQL Client for Swift
→ Compile-time safety→ Inline validation errors for GraphQL→ No wasted cycles on query-gen
34 — Sommer Panage • @sommer • Swift Summit 2016
What about...?35 — Sommer Panage • @sommer • Swift Summit 2016
Versioning
→ "Version-Free"→ Easy to test for backwards compatability
36 — Sommer Panage • @sommer • Swift Summit 2016
Caching
37 — Sommer Panage • @sommer • Swift Summit 2016
Simple Caching
Query-based, not object based
38 — Sommer Panage • @sommer • Swift Summit 2016
Advanced Caching
Flattened results, id-record mapped
39 — Sommer Panage • @sommer • Swift Summit 2016
Aren't you supposed to use GraphQL with React
Native?
40 — Sommer Panage • @sommer • Swift Summit 2016
GraphQL + Swift
-> GraphQL shines on mobile-> Swift gives us types and compile time safety
-> React Native is new and exciting, but that comes with challenges too
41 — Sommer Panage • @sommer • Swift Summit 2016
In Conclusion...
42 — Sommer Panage • @sommer • Swift Summit 2016
Pros to GraphQL + Swift
→ Fewer requests for data→ Getting the exact data you need→ Code gen -> no janky parsing code
→ Models that are reflective of your views→ A strongly typed backend schema
43 — Sommer Panage • @sommer • Swift Summit 2016
Cons to GraphQL + Swift
→ Not a lot of tooling yet→ Best practices still emerging
→ Poorly defined schema becomes a big client problem
→ Not as good for endpoints requiring heavy logic
44 — Sommer Panage • @sommer • Swift Summit 2016
tldr: It's worth it!
45 — Sommer Panage • @sommer • Swift Summit 2016
Check out
→ Apollo iOS Client: Documentation and info on Apollo's awesome Swift iOS GraphQL client
→ 5 benefits of static GraphQL Queries: Blog post from Apollo
→ Bringing GraphQL to iOS: Blog post from Apollo→ GraphQL First: A better way to build modern apps:
Blog post from Apollo46 — Sommer Panage • @sommer • Swift Summit 2016
Check out...con’t
→ GraphQL for mobile: Blog post from Artsy→ Relay: Thinking in GraphQL: Post from FB on
Caching
47 — Sommer Panage • @sommer • Swift Summit 2016
Thank you!!Come ask me questions about GraphQL + Swift
or about Accessibility!
48 — Sommer Panage • @sommer • Swift Summit 2016
CreditsImages
GediminasTurbo Baltaduonis, Danil Polshin, Apple, Facebook, Apollo, Lucasfilm
General
Chorus Fitness, Apollo, Facebook49 — Sommer Panage • @sommer • Swift Summit 2016
Recommended