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
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FGraphQLSwift%2Fgraphql-vapor%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/GraphQLSwift/graphql-vapor)
[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2FGraphQLSwift%2Fgraphql-vapor%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/GraphQLSwift/graphql-vapor)

> ***WARNING***: This package is in v0.x beta. It's API is still evolving and is subject to breaking changes in minor version bumps.

A Swift library for integrating [GraphQL](https://github.com/GraphQLSwift/GraphQL) with [Vapor](https://github.com/vapor/vapor), enabling you to easily expose GraphQL APIs in your Vapor applications.

## Features
Expand Down
7 changes: 7 additions & 0 deletions Sources/GraphQLVapor/GraphQLConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ public struct GraphQLConfig<
>: Sendable {
let allowGet: Bool
let allowMissingAcceptHeader: Bool
let maxBodySize: ByteCount?
let ide: IDE
let subscriptionProtocols: Set<SubscriptionProtocol>
let websocket: WebSocket
Expand All @@ -17,13 +18,15 @@ public struct GraphQLConfig<
/// - Parameters:
/// - allowGet: Whether to allow GraphQL queries via `GET` requests.
/// - allowMissingAcceptHeader: Whether to allow clients to omit "Accept" headers and default to `application/graphql-response+json` encoded responses.
/// - maxBodySize: The maximum size of GraphQL requests in bytes. If not provided, this uses the default [`app.routes.defaultMaxBodySize`](https://docs.vapor.codes/basics/routing/#body-streaming)
/// - ide: The IDE to expose
/// - subscriptionProtocols: Protocols used to support GraphQL subscription requests
/// - websocket: WebSocket-specific configuration
/// - additionalValidationRules: Additional validation rules to apply to requests. The default GraphQL validation rules are always applied.
public init(
allowGet: Bool = true,
allowMissingAcceptHeader: Bool = false,
maxBodySize: ByteCount? = nil,
ide: IDE = .graphiql,
subscriptionProtocols: Set<SubscriptionProtocol> = [],
websocket: WebSocket = .init(
Expand All @@ -34,12 +37,14 @@ public struct GraphQLConfig<
) {
self.allowGet = allowGet
self.allowMissingAcceptHeader = allowMissingAcceptHeader
self.maxBodySize = maxBodySize
self.additionalValidationRules = additionalValidationRules
self.ide = ide
self.subscriptionProtocols = subscriptionProtocols
self.websocket = websocket
}

/// An embeddable GraphQL IDE
public struct IDE: Sendable, Equatable {
/// GraphiQL: https://github.com/graphql/graphiql
public static var graphiql: Self {
Expand All @@ -58,6 +63,7 @@ public struct GraphQLConfig<
}
}

/// A GraphQL subscription implementation
public struct SubscriptionProtocol: Sendable, Hashable {
/// Expose GraphQL subscriptions over WebSockets
public static var websocket: Self {
Expand All @@ -70,6 +76,7 @@ public struct GraphQLConfig<
}
}

/// WebSocket configuration
public struct WebSocket: Sendable {
let onWebSocketInit: @Sendable (WebSocketInit, Request) async throws -> WebSocketInitResult

Expand Down
22 changes: 7 additions & 15 deletions Sources/GraphQLVapor/HTTP/GraphQLHandler+HTTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,24 +86,16 @@ extension GraphQLHandler {

let response = Response()

let configuredMediaTypes: Set<HTTPMediaType> = [.jsonGraphQL, .json]
let configuredMediaTypes: [HTTPMediaType] = [.jsonGraphQL, .json]

// Try to respond with the best matching media type, in order
var selectedMediaType: HTTPMediaType? = nil
for mediaType in headers.accept.mediaTypes {
if configuredMediaTypes.contains(mediaType) {
selectedMediaType = mediaType
break
}
}

// If no exact matches, look for any matching wildcards
if selectedMediaType == nil {
let acceptableMediaSet = HTTPMediaTypeSet(mediaTypes: headers.accept.mediaTypes)
for mediaType in configuredMediaTypes {
if acceptableMediaSet.contains(mediaType) {
selectedMediaType = mediaType
break
headerLoop: for mediaType in headers.accept.mediaTypes {
for configuredMediaType in configuredMediaTypes {
// Note that `==` handles wildcards.
if mediaType == configuredMediaType {
selectedMediaType = configuredMediaType
break headerLoop
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/GraphQLVapor/RoutesBuilder+graphql.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public extension RoutesBuilder {
}
return try await handler.handleGet(request: request)
}
post(path) { request in
on(.POST, path, body: .collect(maxSize: config.maxBodySize)) { request in
try await handler.handlePost(request: request)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ extension GraphQLHandler {
let subProtocol = try negotiateSubProtocol(request: request)
let response = Response(status: .switchingProtocols)
response.upgrader = WebSocketUpgrader(
maxFrameSize: .default,
maxFrameSize: .init(integerLiteral: (config.maxBodySize ?? request.application.routes.defaultMaxBodySize).value),
shouldUpgrade: {
request.eventLoop.makeFutureWithTask {
["Sec-WebSocket-Protocol": subProtocol.rawValue]
Expand Down