# Context

GraphQLSwift/GraphQL allow a custom data structure to be passed into all of your field resolver functions. This allows you to apply some dependency injection to your API and put any code that talks to a database or get the values from the request.

# Context, Request and Response

Pioneer provide a similar solution to apollo-server-express for building context using the raw http requests and http responses. It provide both in the context builder that needed to be provided when constructing Pioneer.

main.swift
import Pioneer
import Vapor

let app = try Application(.detect())

@Sendable
func getContext(req: Request, res: Response) -> Context {
    // Do something extra if needed
    Context(req: req, res: req)
}

let server = Pioneer(
    schema: schema,
    resolver: Resolver(),
    contextBuilder: getContext,
    websocketProtocol: .graphqlWs,
    introspection: true,
    playground: .sandbox
)

# Request (HTTP)

The request given is directly from Vapor, so you can use any method you would use in a regular Vapor application to get any values from it.

Getting a cookie example
struct Resolver {
    func someCookie(ctx: Context, _: NoArguments) async -> String {
        return ctx.req.cookies["some-key"]
    }
}

# Response

Pioneer already provided the response object in the context builder that is going to be the one used to respond to the request. You don't need return one, and instead just mutate its properties.

Setting a cookie example
func users(ctx: Context, _: NoArguments) async -> [User] {
    ctx.response.cookies["refresh-token"] = /* refresh token */
    ctx.response.cookies["access-token"] = /* access token */
    return await getUsers()
}

# Websocket Context

Since 0.7.0, Pioneer allow a seperate context builder for the websocket operations where it provide a different set of arguments.

This context builder is similar to what you can provide to the context property in graphql-ws where you are given the Request, Payload, and GraphQLRequest.

main.swift
import Pioneer
import Vapor

let app = try Application(.detect())

@Sendable
func getContext(req: Request, res: Response) -> Context {
    try Context(
        req: req, res: res,
        params: nil,
        gql: req.content.decode(GraphQLRequest.self)
    )
}

@Sendable
func getWebsocketContext(req: Request, params: Payload, gql: GraphQLRequest) -> {
    Context(
        req: req, res: .init(),
        params: params,
        gql: gql
    )
}

let server = Pioneer(
    schema: schema,
    resolver: Resolver(),
    contextBuilder: getContext,
    websocketContextBuilder: getWebsocketContext,
    websocketProtocol: .graphqlWs,
    introspection: true,
    playground: .sandbox
)

# Request (WS)

The request given is directly from Vapor when upgrading to websocket, so you can use any method you would use in a regular Vapor application to get any values from it.

Getting Fluent DB or EventLoop
struct Resolver {
    func something(ctx: Context, _: NoArguments) async -> [User] {
        return User.query(on: ctx.req.db).all()
    }
}

# Payload

The connection params is given during websocket initialization from payload as part of ConnectionInit message inside an established WebSocket connection.

Getting some values
struct Resolver {
    func someHeader(ctx: Context, _: NoArguments) async -> String? {
        guard .string(let token) = ctx.params?["Authorization"] else { ... }
        return token
    }
}

# GraphQLRequest

This is operation specific graphql request / query given an operation is being executed.

Getting operation type
struct Resolver {
    func someHeader(ctx: Context, _: NoArguments) throws -> String? {
        switch try ctx.gql.operationType() {
        case .subscription:
            ...
        case .query:
            ...
        case .mutation:
            ...
        }
    }
}

GraphQLRequest API References
https://swiftpackageindex.com/d-exclaimation/pioneer/documentation/pioneer/graphqlrequest

# WebSocket Initialisation Hook and Authorization

There might be times where you want to authorize any incoming WebSocket connection before any operation done, and thus before the context builder is executed.

Since v0.10.0, Pioneer now provide a way to run custom code during the GraphQL over WebSocket initialisation phase that can deny a WebSocket connection by throwing an error.

let server = Pioneer(
    schema: schema,
    resolver: Resolver(),
    contextBuilder: getContext,
    websocketContextBuilder: getWebsocketContext,
    websocketOnInit: { payload in 
        guard .some(.string(let token)) = payload?["Authorization"] {
            throw Abort(.unauthorized)
        }

        // do something with the Authorization token
    },
    websocketProtocol: .graphqlWs,
    introspection: true,
    playground: .sandbox
)