Skip to content

labs-nomad/GraphQL-Swift

Repository files navigation

Install

pod 'GraphQL-Swift'

Concept

This library is supposed to be simple. It was inspired by a really simple NPM module called graphql-client

This library does not use any other dependencies and focuses on a protocol-oriented architecture. Right now, you can only make Queries and Mutations. Hopefully add subscriptions soon.

Connecting

To connect to your GraphQL endpoint you need to initalize a GQLNetworkController. The initalizer takes an object that conforms to the GQLAPIDefinition protocol. By default the GQLNetworkController uses a URLSession configured to be ephemeral.

When constructing your GQLAPIDefinition object you can optionally add an object that conforms to GQLAuthorization. From there you can configure your "Authorization" header. So something like this...

struct MockGQLAuthorization: GQLAuthorization {
    //MARK: Properties
    var clientID: String?
    
    var apiKey: String?
    
    var jwt: String?
    
    var authorizationHeader: [String : String] {
        return ["Authorization": "Bearer \(self.jwt ?? self.apiKey ?? self.clientID ?? "")"]
    }
    
    //MARK: init
    init() {
        
    }
}

struct MockAPIDefinition: GQLAPIDefinition {
    //MARK: Properties
    var authorization: GQLAuthorization?
    
    var rootRESTURLString: String = "https://mockgraphqlapi.com"
    
    var rootWebsocketURLString: String = "wss://mockgraphqlapi.com"
    
    //MARK: init
    init(authorization: GQLAuthorization? = nil) {
        self.authorization = authorization
    }
}

let mockAuth = MockGQLAuthorization()

let mockAPI =  MockAPIDefinition(authorization: mockAuth)

let networkController = GQLNetworkController(apiDefinition: mockAPI)

Query

To make a query or mutation you have to create an object that conforms to GQLRequest. Both the GQLQuery and GQLMutation protocols inherit from GQLRequest. Here is a basic query object.

struct UserQuery: GQLQuery {

    var graphQLLiteral: String = """
    query {
        user {
            id
            email
            name
        }
    }
    """
    
    var fragments: [GQLFragment]?
    
    var variables: [String : Any]?
    
    init() {
        
    }
    
}

And you would make the request like this.

let userQuery = UserQuery()

do {
    let dataTask = try networkController.makeGraphQLRequest(userQuery, completion: { (results) in
            switch results {
            case GQLNetworkRequestResults.fail(let error):
                print("Error: \(error)")
                break
            case GQLNetworkRequestResults.success(let jsonDictionary):
                do {
                    let users = try jsonDictionary.parseArrayResults(fieldKey: "user")
                    print(users)
                }catch{
                    //Any parsing errors
                }
            }
        })
}catch{
    //Any errors that were thrown before the request was made.
}

Fragments

You can define a fragment by conforming to the GQLFragment protocol.

Here we can refactor our original UserQuery to contain a fragment.

struct UserDetails: GQLFragment {
     let fragmentLiteral = """
     fragment UserDetails on user {
        id
        name
        email
     }
     """
}

struct UserQuery: GQLQuery {

    var graphQLLiteral: String = """
    query {
        user {
            ...UserDetails
        }
    }
    """
    
    var fragments: [GQLFragment]? = [UserDetails()]
    
    var variables: [String : Any]?
    
    init() {
        
    }
    
}

Variables

Finally we can pass variables into the query like this.

struct UserQuery: GQLQuery {

    var graphQLLiteral: String = """
    query UserByEmail($email: String!){
        user(where: {email: {_eq: $email}}, limit: 1) {
            ...UserDetails
        }
    }
    """
    
    var fragments: [GQLFragment]? = [UserDetails()]
    
    var variables: [String : Any]?
    
    init(email: String) {
        self.variables = ["email": email]
    }
    
}

GraphQL JSON Parsing

The general format of JSON that comes back from a GraphQL request can be read about here.

The responses from the .makeGraphQLRequest function will be the unfilterd or parsed JSON from the request. Since JSON from a GraphQL request does follow some rhyme and reason this library contains some extensions on swift dictionaries to get you started.

  1. Pase the data key.

All requests return a dictionary with a data key. Parse that like this:

do {
    let dataTask = try networkController.makeGraphQLRequest(userQuery, completion: { (results) in
        switch results {
        case .fail(let error):
            print("Error: \(error)")
            break
        case .success(let jsonResults):
            do {
                let dataResults = try jsonResults.parseDataKey()
                print(dataResults)
            }catch{
                //Any parsing errors
            }
        }
    })
}catch{
    //Any errors that were thrown before the request was made.
}
  1. Parse selection set from high level fields.

If you know the form of the object that comes back from any of your top level fields in your query you can get them like this.

do {
    let dataTask = try networkController.makeGraphQLRequest(userQuery, completion: { (results) in
        switch results {
        case .fail(let error):
            print("Error: \(error)")
            break
        case .success(let dictionary):
            do {
                //If your selection set is a dictionary
                let users = try dictionary.parseDictionaryResults(fieldKey: "user")
                print(users)
                //If your selection set is an array
                let users = try dictionary.parseArrayResults(fieldKey: "user")
                print(users)
            }catch{
                //Any parsing errors
            }
        }
    })
}catch{
    //Any errors that were thrown before the request was made.
}

About

A simple GraphQL client in Swift. You are responsible for your JSON.

Resources

License

Stars

Watchers

Forks

Packages

No packages published