.graphql file

In this section, we will implement GraphQL Queries and integrate with the ios app UI.

Create .graphql files with your queries or mutations

Apollo iOS generates code from queries and mutations contained in .graphql files in your target.

A useful convention is to colocate queries, mutations or fragments with the Swift code that uses them by creating <name>.graphql next to <name>.swift. If you have the Xcode add-ons installed, you can use the Xcode companion view to show a .swift file and the corresponding .graphql file side by side.

For the sake of brevity, we will keep all our queries and mutations in one file named api.graphql Create a new file at the roo Todo/api.graphql and add the following code:

githubTodo/api.graphql
+ query getMyTodos {
+ todos(where: { is_public: { _eq: false} }, order_by: { created_at: desc }) {
+ id
+ title
+ created_at
+ is_completed
+ }

We have now written the graphql query that will be converted to a class by apollo codegen that you can use inside your view controller files. Try building your target now and check the API.swift, there will bunch of code generated for you by apollo.

What does this query do?

The query fetches todos with a simple condition; is_public must be false. We sort the todos descending by its created_at time according to the schema. We specify which fields we need for the todos node.

The query is now ready, let's integrate it with our ios code, open TodoVC.swift

var apollo: ApolloClient!
override func viewWillAppear(_ animated: Bool) {
if( SessionManager.shared.credentials?.idToken! != nil ) {
apollo = NetworkManager.shared.apolloClient
}
}

apollo client's local instance to be used across and we do this, only when the token is not nil.

// Filtered Todo list
func getFilteredTodos(segmentIndex: Int = 0) -> [Todo]{
switch segmentIndex{
case 0:
return self.todos
case 1:
return self.todos.filter { $0.isChecked == false }
case 2:
return self.todos.filter { $0.isChecked == true }
default:
return self.todos
}
}
- // Add a New Todo
- func addTodos(todo: Todo){
- }
+ // Queries
+
+ // Get Todo from Cloud
+ private func todoQueryCloud(){
+ apollo.fetch(query: GetMyTodosQuery()){ (result, error) in
+ if ((error) != nil) {
+ if SessionManager.shared.logout() {
+ self.performSegue(withIdentifier: "loginVC", sender: self)
+ }
+ return
+ }
+ guard let data = result?.data else { return }
+ self.newTodos = data.todos
+ self.newFitleredTodos = data.todos
+ DispatchQueue.main.async {
+ self.setupUI()
+ self.todoTable.reloadData()
+ }
+ }
+ }
+
- // Remove Todos
- func removeTodos(indexPath: Int){
-
- }

We are making a network call using apollo.fetch and passing the query class conforming to the GraphQLQuery protocol that was generated by apollo codegen for us. This returns a cancellable.

Let's remove the mock todos data which was used to populate sample data.

override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// Add Dummy Data
- todos.append(Todo(title: "My Private Todo"))
- todos.append(Todo(title: "My Private Todo 1"))
- todos.append(Todo(title: "My Private Todo 2"))
- todos.append(Todo(title: "My Private Todo 3"))
- todos.append(Todo(title: "My Private Todo 4"))
- filteredTodos = todos
- todoTable.reloadData()
setupUI()
Utils.shared.setLeftPaddingInput(ofInput: todoInput)
// Dynamic Row Height
todoTable.estimatedRowHeight = 44.0
todoTable.rowHeight = UITableView.automaticDimension
}

Add this function to run in hte viewWillAppear

override func viewWillAppear(_ animated: Bool) {
if( SessionManager.shared.credentials?.idToken! != nil ) {
apollo = NetworkManager.shared.apolloClient
// Query for the todos
+ todoQueryCloud()
}
}

Woot! You have written your first GraphQL integration with iOS. Easy isn't it?

How does this work?

When you execute apollo.fetch, Apollo will deliver results in the completion handler with two key parameters:

error: A runtime error with graphQLErrors and networkError properties. Contains information about what went wrong with your query.

data: An object containing the result of your GraphQL query. This will contain our actual data from the server. In our case, it will be the todo data.

You can read more about reponse format and error handling here

Using the data object, we are parsing the results from the server. In our query, data object has an array todos which can be mapped to render each TodoCell in our todoTable.

If you noted, there has been some client side filtering to the todos that are displayed.