mirror of
https://github.com/swift-server/swift-openapi-lambda.git
synced 2026-05-03 07:22:26 +00:00
4f2e953097
Change the legal files and the license header in source files according to AWS standards
118 lines
5.0 KiB
Swift
118 lines
5.0 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift OpenAPI Lambda open source project
|
|
//
|
|
// Copyright Swift OpenAPI Lambda project authors
|
|
// Copyright (c) 2023 Amazon.com, Inc. or its affiliates.
|
|
// Licensed under Apache License v2.0
|
|
//
|
|
// See LICENSE.txt for license information
|
|
// See CONTRIBUTORS.txt for the list of Swift OpenAPI Lambda project authors
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
import AWSLambdaRuntime
|
|
import AWSLambdaEvents
|
|
import OpenAPIRuntime
|
|
import HTTPTypes
|
|
|
|
/// Specialization of LambdaHandler which runs an OpenAPILambda
|
|
public struct OpenAPILambdaHandler<OALS: OpenAPILambdaService>: LambdaHandler, Sendable {
|
|
|
|
private let transport: OpenAPILambdaTransport
|
|
private let openAPIService: OALS
|
|
|
|
/// the input type for this Lambda handler (received from the `OpenAPILambda`)
|
|
public typealias Event = OALS.Event
|
|
|
|
/// the output type for this Lambda handler (received from the `OpenAPILambda`)
|
|
public typealias Output = OALS.Output
|
|
|
|
/// Initialize `OpenAPILambdaHandler`.
|
|
///
|
|
/// This initializer decouples the OpenAPILambdaService creation from the registration of the transport
|
|
/// this allows users to control the lifecycle of their service and to inject dependencies.
|
|
///
|
|
/// - Parameters
|
|
/// - withService: The OpenAPI Lambda service to bind to this Lambda handler function
|
|
public init(withService openAPILambdaService: OALS) throws {
|
|
self.openAPIService = openAPILambdaService
|
|
self.transport = OpenAPILambdaTransport(router: TrieRouter())
|
|
try self.openAPIService.register(transport: self.transport)
|
|
}
|
|
|
|
/// The Lambda handling method.
|
|
/// Concrete Lambda handlers implement this method to provide the Lambda functionality.
|
|
///
|
|
/// - Parameters:
|
|
/// - event: Event of type `Event` representing the event or request.
|
|
/// - context: Runtime ``LambdaContext``.
|
|
///
|
|
/// - Returns: A Lambda result ot type `Output`.
|
|
public func handle(_ event: OALS.Event, context: AWSLambdaRuntime.LambdaContext) async throws -> OALS.Output {
|
|
|
|
// by default returns HTTP 500
|
|
var lambdaResponse: OpenAPILambdaResponse = (HTTPResponse(status: .internalServerError), "unknown error")
|
|
|
|
do {
|
|
// convert Lambda event source to OpenAPILambdaRequest
|
|
let request = try openAPIService.request(context: context, from: event)
|
|
|
|
// route the request to find the handlers and extract the paramaters
|
|
let (handler, parameters) = try self.transport.router.route(method: request.0.method, path: request.0.path!)
|
|
|
|
// call the request handler (and extract the HTTPRequest and HTTPBody)
|
|
let httpRequest = request.0
|
|
let httpBody = HTTPBody(stringLiteral: request.1 ?? "")
|
|
let response = try await handler(httpRequest, httpBody, ServerRequestMetadata(pathParameters: parameters))
|
|
|
|
// transform the response to an OpenAPILambdaResponse
|
|
let maxPayloadSize = 10 * 1024 * 1024 // APIGateway payload is 10M max
|
|
let body: String? = try? await String(collecting: response.1 ?? "", upTo: maxPayloadSize)
|
|
lambdaResponse = (response.0, body)
|
|
|
|
}
|
|
catch OpenAPILambdaRouterError.noHandlerForPath(let path) {
|
|
|
|
// There is no hadler registered for this path. This is a programming error.
|
|
lambdaResponse = (
|
|
HTTPResponse(status: .internalServerError),
|
|
"There is no OpenAPI handler registered for the path \(path)"
|
|
)
|
|
|
|
}
|
|
catch OpenAPILambdaRouterError.noRouteForMethod(let method) {
|
|
|
|
// There is no hadler registered for this path. This is a programming error.
|
|
lambdaResponse = (HTTPResponse(status: .notFound), "There is no route registered for the method \(method)")
|
|
|
|
}
|
|
catch OpenAPILambdaRouterError.noRouteForPath(let method, let path) {
|
|
|
|
// There is no hadler registered for this path. This is a programming error.
|
|
lambdaResponse = (
|
|
HTTPResponse(status: .notFound), "There is no route registered for the path \(method) \(path)"
|
|
)
|
|
|
|
}
|
|
catch OpenAPILambdaHttpError.invalidMethod(let method) {
|
|
|
|
// the APIGateway HTTP verb is rejected by HTTTypes HTTPRequest.Method => HTTP 500
|
|
// this should never happen
|
|
lambdaResponse = (
|
|
HTTPResponse(status: .internalServerError),
|
|
"Type mismatch between APIGatewayV2 and HTTPRequest.Method. \(method) verb is rejected by HTTPRequest.Method 🤷♂️"
|
|
)
|
|
|
|
}
|
|
catch {
|
|
// some other error happened
|
|
lambdaResponse = (HTTPResponse(status: .internalServerError), "Unknown error: \(String(reflecting: error))")
|
|
}
|
|
|
|
// transform the OpenAPILambdaResponse to the Lambda Output
|
|
return openAPIService.output(from: lambdaResponse)
|
|
}
|
|
}
|