49
Interfacing with GraphQL in Swift Sommer Panage • @sommer 1 — Sommer Panage • @sommer • Swift Summit 2016

Swift + GraphQL

Embed Size (px)

Citation preview

Page 1: Swift + GraphQL

Interfacing with GraphQL in SwiftSommer Panage • @sommer

1 — Sommer Panage • @sommer • Swift Summit 2016

Page 2: Swift + GraphQL

Hello!

2 — Sommer Panage • @sommer • Swift Summit 2016

Page 3: Swift + GraphQL

What is GraphQL?

3 — Sommer Panage • @sommer • Swift Summit 2016

Page 4: Swift + GraphQL

The GraphQL Schema

type User { name: String! id: Int! email: String twitter: String}

4 — Sommer Panage • @sommer • Swift Summit 2016

Page 5: Swift + GraphQL

Instead of hitting a REST endpoint like...

https://mybackend.com/api/user?id=1

5 — Sommer Panage • @sommer • Swift Summit 2016

Page 6: Swift + GraphQL

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

Page 7: Swift + GraphQL

And I get back a JSON response like...

{ "data": { "name": "Sommer Panage", "email": "[email protected]", "twitter": "@sommer" }}

7 — Sommer Panage • @sommer • Swift Summit 2016

Page 8: Swift + GraphQL

Why is GraphQL such a big deal for mobile?

8 — Sommer Panage • @sommer • Swift Summit 2016

Page 9: Swift + GraphQL

Let's write an app

9 — Sommer Panage • @sommer • Swift Summit 2016

Page 10: Swift + GraphQL

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

Page 11: Swift + GraphQL

{ "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

Page 12: Swift + GraphQL

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

Page 13: Swift + GraphQL

{ "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

Page 14: Swift + GraphQL

{ "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

Page 15: Swift + GraphQL

That's 3 calls and a whole lot of data for 1 little VC

15 — Sommer Panage • @sommer • Swift Summit 2016

Page 16: Swift + GraphQL

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

Page 17: Swift + GraphQL

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

Page 18: Swift + GraphQL

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

Page 19: Swift + GraphQL

Wait just a minute...

19 — Sommer Panage • @sommer • Swift Summit 2016

Page 20: Swift + GraphQL

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

Page 21: Swift + GraphQL

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

Page 22: Swift + GraphQL

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

Page 23: Swift + GraphQL

23 — Sommer Panage • @sommer • Swift Summit 2016

Page 24: Swift + GraphQL

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

Page 25: Swift + GraphQL

25 — Sommer Panage • @sommer • Swift Summit 2016

Page 26: Swift + GraphQL

query AllCharacters { allPeople { edges { node { id name homeworld { name } } } }}

26 — Sommer Panage • @sommer • Swift Summit 2016

Page 27: Swift + GraphQL

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

Page 28: Swift + GraphQL

query Character($id: ID) { person (id: $id) { id height, mass, hairColor, eyeColor, imageURL, starshipConnection { edges { node { name } } } } }

28 — Sommer Panage • @sommer • Swift Summit 2016

Page 29: Swift + GraphQL

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

Page 30: Swift + GraphQL

By having query / view-data based models, we

no longer need optionals everywhere!

30 — Sommer Panage • @sommer • Swift Summit 2016

Page 31: Swift + GraphQL

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

Page 32: Swift + GraphQL

Code Gen!

32 — Sommer Panage • @sommer • Swift Summit 2016

Page 33: Swift + GraphQL

33 — Sommer Panage • @sommer • Swift Summit 2016

Page 34: Swift + GraphQL

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

Page 35: Swift + GraphQL

What about...?35 — Sommer Panage • @sommer • Swift Summit 2016

Page 36: Swift + GraphQL

Versioning

→ "Version-Free"→ Easy to test for backwards compatability

36 — Sommer Panage • @sommer • Swift Summit 2016

Page 37: Swift + GraphQL

Caching

37 — Sommer Panage • @sommer • Swift Summit 2016

Page 38: Swift + GraphQL

Simple Caching

Query-based, not object based

38 — Sommer Panage • @sommer • Swift Summit 2016

Page 39: Swift + GraphQL

Advanced Caching

Flattened results, id-record mapped

39 — Sommer Panage • @sommer • Swift Summit 2016

Page 40: Swift + GraphQL

Aren't you supposed to use GraphQL with React

Native?

40 — Sommer Panage • @sommer • Swift Summit 2016

Page 41: Swift + GraphQL

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

Page 42: Swift + GraphQL

In Conclusion...

42 — Sommer Panage • @sommer • Swift Summit 2016

Page 43: Swift + GraphQL

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

Page 44: Swift + GraphQL

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

Page 45: Swift + GraphQL

tldr: It's worth it!

45 — Sommer Panage • @sommer • Swift Summit 2016

Page 46: Swift + GraphQL

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

Page 47: Swift + GraphQL

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

Page 48: Swift + GraphQL

Thank you!!Come ask me questions about GraphQL + Swift

or about Accessibility!

48 — Sommer Panage • @sommer • Swift Summit 2016

Page 49: Swift + GraphQL

CreditsImages

GediminasTurbo Baltaduonis, Danil Polshin, Apple, Facebook, Apollo, Lucasfilm

General

Chorus Fitness, Apollo, Facebook49 — Sommer Panage • @sommer • Swift Summit 2016