Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Hello! 2 — Sommer Panage • @sommer • Swift Summit 2016

Slide 3

Slide 3 text

What is GraphQL? 3 — Sommer Panage • @sommer • Swift Summit 2016

Slide 4

Slide 4 text

The GraphQL Schema type User { name: String! id: Int! email: String twitter: String } 4 — Sommer Panage • @sommer • Swift Summit 2016

Slide 5

Slide 5 text

Instead of hitting a REST endpoint like... https://mybackend.com/api/user?id=1 5 — Sommer Panage • @sommer • Swift Summit 2016

Slide 6

Slide 6 text

I write a query like... { user(id: 1) { name email twitter } } And send it to my GraphQL endpoint https://mybackend.com/graphql 6 — Sommer Panage • @sommer • Swift Summit 2016

Slide 7

Slide 7 text

And I get back a JSON response like... { "data": { "name": "Sommer Panage", "email": "[email protected]", "twitter": "@sommer" } } 7 — Sommer Panage • @sommer • Swift Summit 2016

Slide 8

Slide 8 text

Why is GraphQL such a big deal for mobile? 8 — Sommer Panage • @sommer • Swift Summit 2016

Slide 9

Slide 9 text

Let's write an app 9 — Sommer Panage • @sommer • Swift Summit 2016

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

That's 3 calls and a whole lot of data for 1 little VC 15 — Sommer Panage • @sommer • Swift Summit 2016

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Wait just a minute... 19 — Sommer Panage • @sommer • Swift Summit 2016

Slide 20

Slide 20 text

Our Star Wars Character model 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? } 20 — Sommer Panage • @sommer • Swift Summit 2016

Slide 21

Slide 21 text

Our Star Wars Character model 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? } 21 — Sommer Panage • @sommer • Swift Summit 2016

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

23 — Sommer Panage • @sommer • Swift Summit 2016

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

25 — Sommer Panage • @sommer • Swift Summit 2016

Slide 26

Slide 26 text

query AllCharacters { allPeople { edges { node { id name homeworld { name } } } } } 26 — Sommer Panage • @sommer • Swift Summit 2016

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

query Character($id: ID) { person (id: $id) { id height, mass, hairColor, eyeColor, imageURL, starshipConnection { edges { node { name } } } } } 28 — Sommer Panage • @sommer • Swift Summit 2016

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

By having query / view- data based models, we no longer need optionals everywhere! 30 — Sommer Panage • @sommer • Swift Summit 2016

Slide 31

Slide 31 text

But our parsing code still looks like... let parsedData = try JSONSerialization.jsonObject(with: data, options: []) as! [String: Any] self.id = parsedData["id"] as! String self.name = parsedData["name"] as! String self.homeworld = Homeworld(dict: parsedData["homeworld"] as! [String : Any]) Ugh! 31 — Sommer Panage • @sommer • Swift Summit 2016

Slide 32

Slide 32 text

Code Gen! 32 — Sommer Panage • @sommer • Swift Summit 2016

Slide 33

Slide 33 text

33 — Sommer Panage • @sommer • Swift Summit 2016

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

Versioning → "Version-Free" → Easy to test for backwards compatability 36 — Sommer Panage • @sommer • Swift Summit 2016

Slide 37

Slide 37 text

Caching 37 — Sommer Panage • @sommer • Swift Summit 2016

Slide 38

Slide 38 text

Simple Caching Query-based, not object based 38 — Sommer Panage • @sommer • Swift Summit 2016

Slide 39

Slide 39 text

Advanced Caching Flattened results, id-record mapped 39 — Sommer Panage • @sommer • Swift Summit 2016

Slide 40

Slide 40 text

Aren't you supposed to use GraphQL with React Native? 40 — Sommer Panage • @sommer • Swift Summit 2016

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

In Conclusion... 42 — Sommer Panage • @sommer • Swift Summit 2016

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

tldr: It's worth it! 45 — Sommer Panage • @sommer • Swift Summit 2016

Slide 46

Slide 46 text

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 Apollo 46 — Sommer Panage • @sommer • Swift Summit 2016

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Thank you!! Come ask me questions about GraphQL + Swift or about Accessibility! 48 — Sommer Panage • @sommer • Swift Summit 2016

Slide 49

Slide 49 text

Credits Images GediminasTurbo Baltaduonis, Danil Polshin, Apple, Facebook, Apollo, Lucasfilm General Chorus Fitness, Apollo, Facebook 49 — Sommer Panage • @sommer • Swift Summit 2016