Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,18 @@ Response:
```

See the `RouteBuilder.graphql` function documentation for advanced configuration options.

### Computing GraphQL Context

The required closure in the `graphql` function is used to compute the `GraphQLContext` object, which is injected into each GraphQL resolver. The `inputs` argument passes in data from the request so that the Context can be created dynamically:

```swift
app.graphql(schema: schema) { inputs in
return GraphQLContext(
userID: inputs.vaporRequest.auth.userID,
logger: inputs.vaporRequest.logger,
debug: inputs.vaporRequest.headers[.init("debug")!] != nil,
operationName: inputs.graphQLRequest.operationName
)
}
```
2 changes: 1 addition & 1 deletion Sources/GraphQLVapor/GraphQLHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ struct GraphQLHandler<
let schema: GraphQLSchema
let rootValue: any Sendable
let config: GraphQLConfig<WebSocketInit>
let computeContext: @Sendable (Request) async throws -> Context
let computeContext: @Sendable (GraphQLContextComputationInputs) async throws -> Context
}
12 changes: 10 additions & 2 deletions Sources/GraphQLVapor/HTTP/GraphQLHandler+HTTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ extension GraphQLHandler {
guard operationType != .mutation else {
throw Abort(.methodNotAllowed, reason: "Mutations using GET are disallowed")
}
let context = try await computeContext(request)
let graphQLContextComputationInputs = GraphQLContextComputationInputs(
vaporRequest: request,
graphQLRequest: graphQLRequest
)
let context = try await computeContext(graphQLContextComputationInputs)
let result = await execute(
graphQLRequest: graphQLRequest,
context: context,
Expand All @@ -30,7 +34,11 @@ extension GraphQLHandler {
throw Abort(.unsupportedMediaType, reason: "Missing `Content-Type` header")
}
let graphQLRequest = try request.content.decode(GraphQLRequest.self)
let context = try await computeContext(request)
let graphQLContextComputationInputs = GraphQLContextComputationInputs(
vaporRequest: request,
graphQLRequest: graphQLRequest
)
let context = try await computeContext(graphQLContextComputationInputs)
let result = await execute(
graphQLRequest: graphQLRequest,
context: context,
Expand Down
7 changes: 6 additions & 1 deletion Sources/GraphQLVapor/RoutesBuilder+graphql.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public extension RoutesBuilder {
schema: GraphQLSchema,
rootValue: any Sendable = (),
config: GraphQLConfig<WebSocketInit> = GraphQLConfig<EmptyWebsocketInit>(),
computeContext: @Sendable @escaping (Request) async throws -> Context
computeContext: @Sendable @escaping (GraphQLContextComputationInputs) async throws -> Context
) {
ContentConfiguration.global.use(encoder: GraphQLJSONEncoder(), for: .jsonGraphQL)
ContentConfiguration.global.use(decoder: JSONDecoder(), for: .jsonGraphQL)
Expand Down Expand Up @@ -67,3 +67,8 @@ public extension RoutesBuilder {
}
}
}

public struct GraphQLContextComputationInputs: Sendable {
public let vaporRequest: Request
public let graphQLRequest: GraphQLRequest
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ extension GraphQLHandler {
request: Request
) async throws -> Response {
let subProtocol = try negotiateSubProtocol(request: request)
let context = try await computeContext(request)
let response = Response(status: .switchingProtocols)
response.upgrader = WebSocketUpgrader(
maxFrameSize: .default,
Expand All @@ -26,7 +25,12 @@ extension GraphQLHandler {
let server = GraphQLTransportWS.Server<WebSocketInit, AsyncThrowingStream<GraphQLResult, Error>>(
messenger: messenger,
onExecute: { graphQLRequest in
try await graphql(
let graphQLContextComputationInputs = GraphQLContextComputationInputs(
vaporRequest: request,
graphQLRequest: graphQLRequest
)
let context = try await computeContext(graphQLContextComputationInputs)
return try await graphql(
schema: schema,
request: graphQLRequest.query,
rootValue: rootValue,
Expand All @@ -36,7 +40,12 @@ extension GraphQLHandler {
)
},
onSubscribe: { graphQLRequest in
try await graphqlSubscribe(
let graphQLContextComputationInputs = GraphQLContextComputationInputs(
vaporRequest: request,
graphQLRequest: graphQLRequest
)
let context = try await computeContext(graphQLContextComputationInputs)
return try await graphqlSubscribe(
schema: schema,
request: graphQLRequest.query,
rootValue: rootValue,
Expand All @@ -52,7 +61,12 @@ extension GraphQLHandler {
let server = GraphQLWS.Server<WebSocketInit, AsyncThrowingStream<GraphQLResult, Error>>(
messenger: messenger,
onExecute: { graphQLRequest in
try await graphql(
let graphQLContextComputationInputs = GraphQLContextComputationInputs(
vaporRequest: request,
graphQLRequest: graphQLRequest
)
let context = try await computeContext(graphQLContextComputationInputs)
return try await graphql(
schema: schema,
request: graphQLRequest.query,
rootValue: rootValue,
Expand All @@ -62,7 +76,12 @@ extension GraphQLHandler {
)
},
onSubscribe: { graphQLRequest in
try await graphqlSubscribe(
let graphQLContextComputationInputs = GraphQLContextComputationInputs(
vaporRequest: request,
graphQLRequest: graphQLRequest
)
let context = try await computeContext(graphQLContextComputationInputs)
return try await graphqlSubscribe(
schema: schema,
request: graphQLRequest.query,
rootValue: rootValue,
Expand Down