# Resolvers and Context

Now, let's get into the resolvers (and context as well), the main logic of the API.

Graphiti require a seperate top level structure acting as the resolver and a context type be given to these resolver functions.

# Context

Let's start with the context. Pioneer will try to build this context on each request by asking for a function that provides both the Request and Response classes and expects the context instance.

import Vapor

struct Context {
    var req: Request
    var res: Response
}

The context here will very simple which only grab the Request and Response so we can get certain values from the request and set some to the response.

Context Building
../../advanced/context/

# Resolver

The resolver will include all the basic CRUD operations. Both Graphiti and Pioneer comes with extensions to Field and SubscriptionField to allow the use of async/await in queries and/or mutations and also EventStream built from AsyncSequence for subscriptions in the resolvers.

import Vapor
import Pioneer
import Graphiti

struct Resolver {
    func users(_: Context, _: NoArguments) async -> [User] {
        await Datastore.shared.select()
    }

    struct UserIDArgs: Decodable {
        var id: ID
    }

    func user(_: Context, args: UserIDArgs) async -> [User] {
        await Datastore.shared.find(with: [args.id]).first
    }

    struct AddUserArgs: Decodable {
        var user: UserInput
    }

    func create(_: Context, args: AddUserArgs) async -> User? {
        await Datastore.shared.insert(User(args.user))
    }

    struct UpdateUserArgs: Decodable {
        var id: ID
        var user: UserInput
    }

    func update(_: Context, args: UpdateUserArgs) async -> User? {
        await Datastore.shared.update(for args.id, with: User(id: args.id, args.user))
    }


    func delete(_: Context, args: UserIDArgs) async -> User? {
        await Datastore.shared.delete(for: args.id)
    }

}

# Subscriptions

Pioneer has capabilities to handle subscription through websocket, all you need to provide is an EventStream that was built with AsyncSequence.

import GraphQL

let ON_CHANGE_TRIGGER = "user-on-change"

struct Resolver {
    let pubsub = AsyncPubSub()

    ...

    func create(_: Context, args: AddUserArgs) async -> User {
        let user = await Datastore.shared.insert(User(id: args.id, args.user))
        if user = user {
            await pubsub.publish(ON_CHANGE_TRIGGER, payload: user)
        }
        return user
    }

    ...

    func update(_: Context, args: UpdateUserArgs) async -> User? {
        let user = await Datastore.shared.update(for: args.id, with: User(args.user))
        if user = user {
            await pubsub.publish(ON_CHANGE_TRIGGER, payload: user)
        }
        return user
    }

    ...

    func onChange(_: Context, _: NoArgs) -> EventStream<User> {
        pubsub
            .asyncStream(User.self, for: ON_CHANGE_TRIGGER)
            .toEventStream()
    }
}

# Relationship

In the part where we declare the User type, we have this friendIDs property. This property was there for the base for building a relationship.

You can add a custom resolver by extending the User type with a function that resembles the resolver functions, only here it can access the parent type.

extension User {
    func friends(_: Context, _: NoArgs) async -> [User] {
        await Datastore.shared.find(with: _friendIDs)
    }
}