Slide 1

Slide 1 text

GraphQL + iOS @macabeus #12cocoaHeadsFortaleza

Slide 2

Slide 2 text

Who am I?

Slide 3

Slide 3 text

My name is Bruno Macabeus I’m student at IFCE & Apple Developer Academy github.com/macabeus

Slide 4

Slide 4 text

Problem!!

Slide 5

Slide 5 text

You are making an app to many devices…

Slide 6

Slide 6 text

You are making an app to many devices… … and each device have a very different UI!

Slide 7

Slide 7 text

You are making an app to many devices… … and each device have a very different UI!

Slide 8

Slide 8 text

Title Short description Title Short description Title Title Title Title /posts title description userId /users/:id name age imageUrl Overfetch and Underfetch Title Title Title

Slide 9

Slide 9 text

/posts?include=title,userId title description userId /users/:id?include=imageUrl name age imageUrl Overfetch and Underfetch Title Short description Title Short description Title Title Title Title Title Title Title

Slide 10

Slide 10 text

/posts?include=title,user.imageUrl title description userId user.imageUrl Overfetch and Underfetch Title Short description Title Short description Title Title Title Title Title Title Title

Slide 11

Slide 11 text

/posts?include=title,description,user.avatar,data &filter=notRead&sort=newest&description=long title description userId user.avatar data Validate of parameters Title Short description Title Short description Title Title Title Title Title Title Title

Slide 12

Slide 12 text

/posts?include=title,description,user.avatar,data &filter=notRead&sort=newest&description=long title description (now is deprecated!) shortDescription userId user.avatar data Notifications of deprecated Title Short description Title Short description Title Title Title Title Title Title Title

Slide 13

Slide 13 text

Can GraphQL help me?

Slide 14

Slide 14 text

Yes! Because with GraphQL you can be more expressive in your query! query GetPosts() { posts { title description user { imageUrl } } }

Slide 15

Slide 15 text

Okay… But, is someone using GraphQL already?

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

How does GraphQL work?

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

query GetPosts() { posts { title description user { imageUrl } } } It’s a sample of GraphQL language

Slide 20

Slide 20 text

{ "data": { "posts": [ { "user": { "name": "Bruno Macabeus” }, "title": “My amazing post!”, "body": “Loren ipsun" }, { "user": { "name": "Ryan Swapp” }, "title": “My blog post", "body": “Foo bar baz” } ] } } Server can respond with JSON or other format

Slide 21

Slide 21 text

Query Mutation Subscription query FetchPosts() { posts { id title body user { name } } } Query is an operation to get data from the server. For example: a list of posts. Operations

Slide 22

Slide 22 text

Query Mutation Subscription mutation CreatePost($title: String!, $body: String!) { createPost(title: $title, body: $body) { id } } Mutation is an operation to perform side-effects on the underlying data system. For example: create a new post, or update one. Operations

Slide 23

Slide 23 text

Query Mutation Subscription subscription NewComment($postId: Int!) { newComment(roomId: $postId) { sender text } } Subscription is an operation to start a new event stream. For example: check for new comments in a post in realtime. Operations

Slide 24

Slide 24 text

query FetchPokemonBattle() { pokemonBattle { id pokemonLeft { id name level hp }, pokemonRight { id name level hp } } } Fragments

Slide 25

Slide 25 text

query FetchPokemonBattle() { pokemonBattle() { id pokemonLeft { ...PokemonDetail }, pokemonRight { ...PokemonDetail } } } fragment PokemonDetail on Pokemon { id name level hp } Fragments allow the reuse of common repeated selections of fields. Fragments query FetchPokemonBattle() { pokemonBattle { id pokemonLeft { id name level hp }, pokemonRight { id name level hp } } }

Slide 26

Slide 26 text

How to use GraphQL in server? (briefly)

Slide 27

Slide 27 text

I wrote a server using the Elixir language, a functional language that run in the BEAM virtual machine, the same virtual machine of Erlang. I chose this language because it’s great for applications that need a lot parallelism, such as a server. And, to create the server-side code for GraphQL, I used the Absinthe package.

Slide 28

Slide 28 text

I wrote a server using the Elixir language, a functional language that run in virtual machine BEAM, the same virtual machine of Erlang. I chose this language because is great for applications that need a lot parallelism, such a server. And, to create the server-side code about GraphQL, I used using the package Absinthe. github.com/macabeus/graphql-example

Slide 29

Slide 29 text

How to use GraphQL in iOS?

Slide 30

Slide 30 text

We could use the Apollo GraphQL tool for iOS Apollo is a community building flexible open source tools for GraphQL.

Slide 31

Slide 31 text

We could use the Apollo GraphQL tool for iOS Apollo is a community building flexible open source tools for GraphQL. Great features for iOS package: Strongly-typed & caching

Slide 32

Slide 32 text

Add the Apollo package Configuration 1/5

Slide 33

Slide 33 text

Download the scheme.json Configuration 2/5

Slide 34

Slide 34 text

Add a new build phase Configuration 3/5

Slide 35

Slide 35 text

And add the new files schema.json and API.swift on the project Configuration 4/5

Slide 36

Slide 36 text

Initialize the ApolloClient somewhere, for example, AppDelegate.swift Configuration 5/5 import Apollo let graphlQLEndpointURL = "http://localhost:4000/api" let apollo = ApolloClient(url: URL(string: graphlQLEndpointURL)!)

Slide 37

Slide 37 text

Coding Create a new .graphql file, that Apollo will compile to Swift

Slide 38

Slide 38 text

Coding class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? in return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } }

Slide 39

Slide 39 text

class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? i return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } query GetPosts($userId: Int) { posts(userId: $userId) { id title body countLikes liked user { name } } }

Slide 40

Slide 40 text

class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? i return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } query GetPosts($userId: Int) { posts(userId: $userId) { id title body countLikes liked user { name } } }

Slide 41

Slide 41 text

class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? i return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } query GetPosts($userId: Int) { posts(userId: $userId) { id title body countLikes liked user { name } } }

Slide 42

Slide 42 text

class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? i return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } query GetPosts($userId: Int) { posts(userId: $userId) { id title body countLikes liked user { name } } }

Slide 43

Slide 43 text

class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? i return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } query GetPosts($userId: Int) { posts(userId: $userId) { id title body countLikes liked user { name } } } “fetch" if is query “perform" if is mutation

Slide 44

Slide 44 text

class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? i return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } query GetPosts($userId: Int) { posts(userId: $userId) { id title body countLikes liked user { name } } }

Slide 45

Slide 45 text

class TableViewControllerPosts: UITableViewController { override func viewDidAppear(_ animated: Bool) { fetchPosts() } func fetchPosts() { let query = GetPostsQuery(userId: 1) apollo.fetch(query: query) { result, error in // Check for errors if let error = error { print(error) return } guard let posts = result?.data?.posts else { print("Without data!") return } // Parse self.tableDataSource = posts.flatMap { post -> Post? i return Post( id: post?.id, name: post?.title, body: post?.body, countLikes: post?.countLikes, liked: post?.liked, author: User( name: post?.user?.name ) ) } } query GetPosts($userId: Int) { posts(userId: $userId) { id title body countLikes liked user { name } } }

Slide 46

Slide 46 text

Hey… wait!!!

Slide 47

Slide 47 text

Now we have a problem, called Massive View Controller!

Slide 48

Slide 48 text

Network layer & unit tests

Slide 49

Slide 49 text

github.com/macabeus/graphql-example

Slide 50

Slide 50 text

GraphQL isn't a silver bullet!

Slide 51

Slide 51 text

GraphQL is designed to build client applications. Depending on the project needs, maybe is better use Rest instead of GraphQL. Or, you could use both, Rest and GraphQL, in same project. One situation that GraphQL is good is when you need a highly query-able API.

Slide 52

Slide 52 text

and beyond…

Slide 53

Slide 53 text

{ page(url:"http://news.ycombinator.com") { items: query(selector:"tr.athing") { rank: text(selector:"td span.rank") title: text(selector:"td.title a") sitebit: text(selector:"span.comhead a") url: attr(selector:"td.title a", name:"href") attrs: next { score: text(selector:"span.score") user: text(selector:"a:eq(0)") comments: text(selector:"a:eq(2)") } } } } GDOM GraphQL-like syntax to create webcrawlers

Slide 54

Slide 54 text

Distributed graph database

Slide 55

Slide 55 text

{ brCharacters(func: eq(name@en, "Blade Runner")) { name@en initial_release_date starring { performance.actor { name@en # actor name } performance.character { name@en # character name } } } } Distributed graph database , that has a query language inspired by GraphQL, called GraphQL+-

Slide 56

Slide 56 text

To learn more

Slide 57

Slide 57 text

https://www.howtographql.com

Slide 58

Slide 58 text

https://ryanswapp.com/2016/11/29/phoenix-graphql- tutorial-with-absinthe/

Slide 59

Slide 59 text

https://github.com/macabeus/graphql-example

Slide 60

Slide 60 text

http://macalogs.com.br