UNPKG

@pulumi/awsx

Version:

[![Actions Status](https://github.com/pulumi/pulumi-awsx/workflows/master/badge.svg)](https://github.com/pulumi/pulumi-awsx/actions) [![Slack](http://www.pulumi.com/images/docs/badges/slack.svg)](https://slack.pulumi.com) [![NPM version](https://badge.fur

739 lines • 33.3 kB
"use strict"; // Copyright 2016-2018, Pulumi Corporation. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. Object.defineProperty(exports, "__esModule", { value: true }); exports.createAPI = exports.API = void 0; // These APIs are currently experimental and may change. const fs = require("fs"); const mime = require("mime"); const fspath = require("path"); const aws = require("@pulumi/aws"); const pulumi = require("@pulumi/pulumi"); const utils_1 = require("../utils"); const apikey_1 = require("./apikey"); const lambdaAuthorizer = require("./lambdaAuthorizer"); function isEventHandler(route) { return route.eventHandler !== undefined; } function isStaticRoute(route) { return route.localPath !== undefined; } function isIntegrationRouteTargetProvider(obj) { return obj.target instanceof Function; } function isIntegrationRoute(route) { return route.target !== undefined; } function isRawDataRoute(route) { return route.data !== undefined; } class API extends pulumi.ComponentResource { constructor(name, args, opts = {}) { super("aws:apigateway:x:API", name, {}, opts); const apiResource = createAPI(this, name, args, opts.parent); this.restAPI = apiResource.restAPI; this.deployment = apiResource.deployment; this.stage = apiResource.stage; this.apiPolicy = apiResource.apiPolicy; this.staticRoutesBucket = apiResource.staticRoutesBucket; this.url = apiResource.url; this.swaggerLambdas = apiResource.swaggerLambdas; this.registerOutputs(); } /** * Returns the [aws.lambda.Function] an [EventHandlerRoute] points to. This will either be for * the aws.lambda.Function created on your behalf if the route was passed a normal * JavaScript/Typescript function, or it will be the [aws.lambda.Function] that was explicitly * passed in. * * [route] and [method] can both be elided if this API only has a single [EventHandlerRoute] * assigned to it. * * [method] can be elided if [route] only has a single [EventHandlerRoute] assigned to it. * * This method will throw if the provided [route] and [method] do not resolve to a single * [aws.lambda.Function] */ getFunction(route, method) { const methods = this.getMethods(route); if (!methods || methods.size === 0) { throw new pulumi.ResourceError(`Route '${route}' has no methods defined for it`, this); } if (!method) { if (methods.size === 1) { for (const m of methods.values()) { return m; } } throw new pulumi.ResourceError(`Route '${route}' has multiple methods defined for it. Please provide [method].`, this); } const result = methods.get(method); if (!result) { throw new pulumi.ResourceError(`Route '${route}' does not have method '${method}' defined for it`, this); } return result; } getMethods(route) { if (route === undefined) { if (this.swaggerLambdas.size === 0) { throw new pulumi.ResourceError(`This Api has no routes to any Functions.`, this); } if (this.swaggerLambdas.size === 1) { for (const map of this.swaggerLambdas.values()) { return map; } } throw new pulumi.ResourceError(`[route] must be provided as this Api defines multiple routes with Functions.`, this); } return this.swaggerLambdas.get(route); } } exports.API = API; function createAPI(parent, name, args, optsParent) { let swaggerString; let swaggerLambdas; let title; let staticRoutesBucket; let apiPolicy; if (args.swaggerString) { const swaggerSpec = pulumi.output(args.swaggerString).apply(s => { const spec = JSON.parse(s); if (spec.info === undefined) { spec.info = {}; } if (spec.info.title === undefined) { spec.info.title = name; } return spec; }); title = swaggerSpec.info.title; swaggerString = swaggerSpec.apply(s => JSON.stringify(s)); swaggerLambdas = new Map(); } else if (args.routes || args.additionalRoutes) { const result = createSwaggerSpec(parent, name, args.routes || [], pulumi.output(args.additionalRoutes || []), args.gatewayResponses, args.requestValidator, args.apiKeySource, args.staticRoutesBucket); title = pulumi.output(name); swaggerString = result.swagger; swaggerLambdas = result.swaggerLambdas; staticRoutesBucket = result.staticRoutesBucket; } else { throw new pulumi.ResourceError("API must specify either [swaggerString] or as least one of the [route] options.", optsParent); } const stageName = args.stageName || "stage"; const restApiArgs = args.restApiArgs || {}; // Create the API Gateway Rest API, using a swagger spec. const restAPI = new aws.apigateway.RestApi(name, Object.assign(Object.assign({}, args.restApiArgs), { name: (0, utils_1.ifUndefined)(restApiArgs.name, title), binaryMediaTypes: (0, utils_1.ifUndefined)(restApiArgs.binaryMediaTypes, ["*/*"]), body: swaggerString, // We pass this in directly, because setting it in the Swagger doesn't cause // it to take affect, it must be passed directly to the RestAPI constructor as well. apiKeySource: args.apiKeySource }), { parent }); if (restApiArgs.policy) { apiPolicy = new aws.apigateway.RestApiPolicy(name, { restApiId: restAPI.id, policy: restApiArgs.policy, }, { parent }); } // Account for all potential REST API Args that should trigger a redeployment const version = pulumi.all([restAPI.apiKeySource, restAPI.binaryMediaTypes, restAPI.endpointConfiguration, restAPI.minimumCompressionSize, restAPI.policy, swaggerString]) .apply(([apiKey, binaryMediaTypes, endpointConfig, minimumCompression, policy, swagger]) => (0, utils_1.sha1hash)(JSON.stringify({ apiKey, binaryMediaTypes, endpointConfig, minimumCompression, policy, swagger }))); // Create a deployment of the Rest API. const deployment = new aws.apigateway.Deployment(name, Object.assign(Object.assign({}, args.deploymentArgs), { restApi: restAPI, // Note: We set `variables` here because it forces recreation of the Deployment object // whenever the body hash changes. Because we use a blank stage name above, there will // not actually be any stage created in AWS, and thus these variables will not actually // end up anywhere. But this will still cause the right replacement of the Deployment // when needed. The Stage allocated below will be the stable stage that always points // to the latest deployment of the API. variables: { version } }), { parent, dependsOn: apiPolicy ? [apiPolicy] : [], }); const permissions = createLambdaPermissions(parent, restAPI, name, swaggerLambdas); // Create a stage, which is an addressable instance of the Rest API. Set it to point at the latest deployment. const stage = new aws.apigateway.Stage(name, Object.assign(Object.assign({}, args.stageArgs), { restApi: restAPI, deployment: deployment, stageName: stageName }), { parent, dependsOn: permissions }); // Expose the URL that the API is served at. const url = pulumi.interpolate `${stage.invokeUrl}/`; return { restAPI, deployment, stage, apiPolicy, staticRoutesBucket, url, swaggerLambdas, }; } exports.createAPI = createAPI; function createLambdaPermissions(parent, restAPI, name, swaggerLambdas) { const permissions = []; for (const [path, lambdas] of swaggerLambdas) { for (const [method, lambda] of lambdas) { const methodAndPath = `${method === "ANY" ? "*" : method}${path}`; permissions.push(new aws.lambda.Permission(name + "-" + (0, utils_1.sha1hash)(methodAndPath), { action: "lambda:invokeFunction", function: lambda, principal: "apigateway.amazonaws.com", // We give permission for this function to be invoked by any stage at the given method and // path on the API. We allow any stage instead of encoding the one known stage that will be // deployed by Pulumi because the API Gateway console "Test" feature invokes the route // handler with the fake stage `test-invoke-stage`. sourceArn: pulumi.interpolate `${restAPI.executionArn}*/${methodAndPath}`, }, { parent })); } } return permissions; } function createSwaggerSpec(parent, name, routes, additionalRoutes, gatewayResponses, requestValidator, apikeySource, bucketOrArgs) { // Default API Key source to "HEADER" apikeySource = apikeySource || "HEADER"; // Set up the initial swagger spec. const swagger = { swagger: "2.0", info: { title: name, version: "1.0" }, paths: {}, "x-amazon-apigateway-binary-media-types": ["*/*"], // Map paths the user doesn't have access to as 404. // http://docs.aws.amazon.com/apigateway/latest/developerguide/supported-gateway-response-types.html "x-amazon-apigateway-gateway-responses": generateGatewayResponses(gatewayResponses), "x-amazon-apigateway-api-key-source": apikeySource, }; if (requestValidator) { swagger["x-amazon-apigateway-request-validators"] = { ALL: { validateRequestBody: true, validateRequestParameters: true, }, BODY_ONLY: { validateRequestBody: true, validateRequestParameters: false, }, PARAMS_ONLY: { validateRequestBody: false, validateRequestParameters: true, }, }; swagger["x-amazon-apigateway-request-validator"] = requestValidator; } const swaggerLambdas = new Map(); // Now add all the routes to it. // Use this to track the API's authorizers and ensure any authorizers with the same name // reference the same authorizer. const apiAuthorizers = {}; let staticRoutesBucket; // First, process the routes that create contingent resources. for (const route of routes) { checkRoute(parent, route, "path"); // We allow paths to be provided that don't start with / just for convenience. But we always // normalize them internally to start with / as that it what swagger requires. if (!route.path.startsWith("/")) { route.path = "/" + route.path; } if (isEventHandler(route)) { addEventHandlerRouteToSwaggerSpec(parent, name, swagger, swaggerLambdas, route, apiAuthorizers); } else if (isStaticRoute(route)) { if (!staticRoutesBucket) { staticRoutesBucket = pulumi.Resource.isInstance(bucketOrArgs) ? bucketOrArgs : new aws.s3.Bucket(safeS3BucketName(name), bucketOrArgs, { parent }); } addStaticRouteToSwaggerSpec(parent, name, swagger, route, staticRoutesBucket, apiAuthorizers); } else if (isIntegrationRoute(route) || isRawDataRoute(route)) { addIntegrationOrRawDataRouteToSwaggerSpec(route); } else { const exhaustiveMatch = route; throw new Error("Non-exhaustive match for route"); } } const swaggerText = pulumi.all([swagger, additionalRoutes]).apply(([_, routes]) => { for (const route of routes) { addIntegrationOrRawDataRouteToSwaggerSpec(route); } return pulumi.output(swagger).apply(s => JSON.stringify(s)); }); return { swagger: swaggerText, swaggerLambdas, staticRoutesBucket }; function addIntegrationOrRawDataRouteToSwaggerSpec(route) { if (isIntegrationRoute(route)) { addIntegrationRouteToSwaggerSpec(parent, name, swagger, route, apiAuthorizers); } else { addRawDataRouteToSwaggerSpec(parent, name, swagger, route); } } } function generateGatewayResponses(responses) { responses = responses || {}; if (!responses["MISSING_AUTHENTICATION_TOKEN"]) { responses["MISSING_AUTHENTICATION_TOKEN"] = { "statusCode": 404, "responseTemplates": { "application/json": "{\"message\": \"404 Not found\" }", }, }; } if (!responses["ACCESS_DENIED"]) { responses["ACCESS_DENIED"] = { "statusCode": 404, "responseTemplates": { "application/json": "{\"message\": \"404 Not found\" }", }, }; } return responses; } function addSwaggerOperation(swagger, path, method, operation) { if (!swagger.paths[path]) { swagger.paths[path] = {}; } swagger.paths[path][method] = operation; } function checkRoute(parent, route, propName) { if (route[propName] === undefined) { throw new pulumi.ResourceError(`Route missing required [${String(propName)}] property`, parent); } } function addEventHandlerRouteToSwaggerSpec(parent, name, swagger, swaggerLambdas, route, apiAuthorizers) { checkRoute(parent, route, "eventHandler"); checkRoute(parent, route, "method"); const method = swaggerMethod(route.method); const lambda = aws.lambda.createFunctionFromEventHandler(name + (0, utils_1.sha1hash)(method + ":" + route.path), route.eventHandler, { parent }); const swaggerOperation = createSwaggerOperationForLambda(); addBasePathOptionsToSwagger(parent, swagger, swaggerOperation, route, apiAuthorizers); addSwaggerOperation(swagger, route.path, method, swaggerOperation); let lambdas = swaggerLambdas.get(route.path); if (!lambdas) { lambdas = new Map(); swaggerLambdas.set(route.path, lambdas); } lambdas.set(route.method, lambda); return; function createSwaggerOperationForLambda() { const region = (0, utils_1.getRegion)(parent); const uri = pulumi.interpolate `arn:aws:apigateway:${region}:lambda:path/2015-03-31/functions/${lambda.arn}/invocations`; return { "x-amazon-apigateway-integration": { uri, passthroughBehavior: "when_no_match", httpMethod: "POST", type: "aws_proxy", }, }; } } function addBasePathOptionsToSwagger(parent, swagger, swaggerOperation, route, apiAuthorizers) { if (route.authorizers) { const authRecords = addAuthorizersToSwagger(parent, swagger, route.authorizers, apiAuthorizers); addAuthorizersToSwaggerOperation(swaggerOperation, authRecords); } if (route.requiredParameters) { addRequiredParametersToSwaggerOperation(swaggerOperation, route.requiredParameters); } if (route.requestValidator) { swaggerOperation["x-amazon-apigateway-request-validator"] = route.requestValidator; } if (route.iamAuthEnabled) { swaggerOperation["x-amazon-apigateway-auth"] = { type: "AWS_IAM" }; } if (route.apiKeyRequired) { addAPIkeyToSecurityDefinitions(swagger); addAPIKeyToSwaggerOperation(swaggerOperation); } } function addAPIkeyToSecurityDefinitions(swagger) { swagger.securityDefinitions = swagger.securityDefinitions || {}; if (swagger.securityDefinitions["api_key"] && swagger.securityDefinitions["api_key"] !== apikey_1.apiKeySecurityDefinition) { throw new Error("Defined a non-apikey security definition with the name api_key"); } swagger.securityDefinitions["api_key"] = apikey_1.apiKeySecurityDefinition; } function addAPIKeyToSwaggerOperation(swaggerOperation) { swaggerOperation.security = swaggerOperation.security || []; swaggerOperation.security.push({ ["api_key"]: [], }); } function addAuthorizersToSwagger(parent, swagger, authorizers, apiAuthorizers) { const authRecords = []; swagger.securityDefinitions = swagger.securityDefinitions || {}; authorizers = Array.isArray(authorizers) ? authorizers : [authorizers]; for (const auth of authorizers) { const suffix = Object.keys(swagger.securityDefinitions).length; const authName = auth.authorizerName || `${swagger.info.title}-authorizer-${suffix}`; auth.authorizerName = authName; // Check API authorizers - if its a new authorizer add it to the apiAuthorizers // if the name already exists, we check that the authorizer references the same authorizer if (!apiAuthorizers[authName]) { apiAuthorizers[authName] = auth; } else if (apiAuthorizers[authName] !== auth) { throw new Error("Two different authorizers using the same name: " + authName); } // Add security definition if it's a new authorizer if (!swagger.securityDefinitions[auth.authorizerName]) { swagger.securityDefinitions[authName] = { type: "apiKey", name: auth.parameterName, in: lambdaAuthorizer.isLambdaAuthorizer(auth) ? auth.parameterLocation : "header", "x-amazon-apigateway-authtype": lambdaAuthorizer.isLambdaAuthorizer(auth) ? auth.authType : "cognito_user_pools", "x-amazon-apigateway-authorizer": lambdaAuthorizer.isLambdaAuthorizer(auth) ? getLambdaAuthorizer(parent, authName, auth) : getCognitoAuthorizer(auth.identitySource, auth.providerARNs), }; } const methods = lambdaAuthorizer.isLambdaAuthorizer(auth) || !auth.methodsToAuthorize ? [] : auth.methodsToAuthorize; authRecords.push({ [authName]: methods }); } return authRecords; } function getCognitoPoolARNs(pools) { const arns = []; for (const pool of pools) { if (pulumi.CustomResource.isInstance(pool)) { arns.push(pool.arn); } else { arns.push(pool); } } return arns; } function getCognitoAuthorizer(identitySource, providerARNs) { return { type: "cognito_user_pools", identitySource: lambdaAuthorizer.getIdentitySource(identitySource), providerARNs: getCognitoPoolARNs(providerARNs), }; } function getLambdaAuthorizer(parent, authorizerName, authorizer) { if (lambdaAuthorizer.isLambdaAuthorizerInfo(authorizer.handler)) { const identitySource = lambdaAuthorizer.getIdentitySource(authorizer.identitySource); let uri; if (pulumi.CustomResource.isInstance(authorizer.handler.uri)) { uri = authorizer.handler.uri.invokeArn; } else { uri = authorizer.handler.uri; } let credentials; if (pulumi.CustomResource.isInstance(authorizer.handler.credentials)) { credentials = authorizer.handler.credentials.arn; } else { credentials = authorizer.handler.credentials; } return { type: authorizer.type, authorizerUri: uri, authorizerCredentials: credentials, identitySource: identitySource, identityValidationExpression: authorizer.identityValidationExpression, authorizerResultTtlInSeconds: authorizer.authorizerResultTtlInSeconds, }; } // We used to create the lambda and role in an unparented fashion. Pass along an appropriate // alias to make sure that they can be parented to the api without causing replacements. const authorizerLambda = aws.lambda.createFunctionFromEventHandler(authorizerName, authorizer.handler, { parent, aliases: [{ parent: pulumi.rootStackResource }], }); const role = lambdaAuthorizer.createRoleWithAuthorizerInvocationPolicy(authorizerName, authorizerLambda, { parent, aliases: [{ parent: pulumi.rootStackResource }], }); const identitySource = lambdaAuthorizer.getIdentitySource(authorizer.identitySource); return { type: authorizer.type, authorizerUri: authorizerLambda.invokeArn, authorizerCredentials: role.arn, identitySource: identitySource, identityValidationExpression: authorizer.identityValidationExpression, authorizerResultTtlInSeconds: authorizer.authorizerResultTtlInSeconds, }; } function addAuthorizersToSwaggerOperation(swaggerOperation, authRecords) { swaggerOperation.security = swaggerOperation.security || []; for (const record of authRecords) { swaggerOperation.security.push(record); } } function addRequiredParametersToSwaggerOperation(swaggerOperation, requiredParameters) { for (const requiredParam of requiredParameters) { const param = { name: requiredParam.name, in: requiredParam.in, required: true, }; swaggerOperation["parameters"] = swaggerOperation["parameters"] || []; swaggerOperation["parameters"].push(param); } } function addStaticRouteToSwaggerSpec(parent, name, swagger, route, bucket, apiAuthorizers) { checkRoute(parent, route, "localPath"); const method = swaggerMethod("GET"); // For each static file, just make a simple bucket object to hold it, and create a swagger path // that routes from the file path to the arn for the bucket object. // // For static directories, use greedy api-gateway path matching so that we can map a single api // gateway route to all the s3 bucket objects we create for the files in these directories. const stat = fs.statSync(route.localPath); if (stat.isFile()) { processFile(route); } else if (stat.isDirectory()) { processDirectory(route); } function createRole(key) { // Create a role and attach it so that this route can access the AWS bucket. const role = new aws.iam.Role(key, { assumeRolePolicy: JSON.stringify(apigatewayAssumeRolePolicyDocument), }, { parent }); const attachment = new aws.iam.RolePolicyAttachment(key, { role: role, policyArn: aws.iam.ManagedPolicy.AmazonS3FullAccess, }, { parent }); return role; } function createBucketObject(key, localPath, contentType) { return new aws.s3.BucketObject(key, { bucket, key, source: new pulumi.asset.FileAsset(localPath), contentType: contentType || mime.getType(localPath) || undefined, }, { parent }); } function processFile(route) { const key = name + (0, utils_1.sha1hash)(method + ":" + route.path); const role = createRole(key); createBucketObject(key, route.localPath, route.contentType); const swaggerOperation = createSwaggerOperationForObjectKey(key, role); addBasePathOptionsToSwagger(parent, swagger, swaggerOperation, route, apiAuthorizers); addSwaggerOperation(swagger, route.path, method, swaggerOperation); } function processDirectory(directory) { const directoryServerPath = route.path.endsWith("/") ? route.path : route.path + "/"; const directoryKey = name + (0, utils_1.sha1hash)(method + ":" + directoryServerPath); const role = createRole(directoryKey); let startDir = fspath.isAbsolute(directory.localPath) ? directory.localPath : fspath.join(process.cwd(), directory.localPath); if (!startDir.endsWith(fspath.sep)) { startDir = fspath.join(startDir, fspath.sep); } // If the user has supplied 'false' for options.index, then no special index file served // at the root. Otherwise if they've supplied an actual filename to serve as the index // file then use what they've provided. Otherwise attempt to serve "index.html" at the // root (if it exists). const indexFile = directory.index === false ? undefined : typeof directory.index === "string" ? directory.index : "index.html"; const indexPath = indexFile === undefined ? undefined : fspath.join(startDir, indexFile); // Recursively walk the directory provided, creating bucket objects for all the files we // encounter. function walk(dir) { const children = fs.readdirSync(dir); for (const childName of children) { const childPath = fspath.join(dir, childName); const stats = fs.statSync(childPath); if (stats.isDirectory()) { walk(childPath); } else if (stats.isFile()) { // childPath could have either Windows or POSIX separators, so we should account for this. const childRelativePath = childPath.substr(startDir.length).split(fspath.sep).join(fspath.posix.sep); const childUrn = directoryKey + "/" + childRelativePath; createBucketObject(childUrn, childPath); if (childPath === indexPath) { // We hit the file that we also want to serve as the index file. Create // a specific swagger path from the server root path to it. const swaggerOperation = createSwaggerOperationForObjectKey(childUrn, role); addBasePathOptionsToSwagger(parent, swagger, swaggerOperation, directory, apiAuthorizers); swagger.paths[directoryServerPath] = { [method]: swaggerOperation, }; } } } } walk(startDir); // Take whatever path the client wants to host this folder at, and add the // greedy matching predicate to the end. const proxyPath = directoryServerPath + "{proxy+}"; const swaggerOperation = createSwaggerOperationForObjectKey(directoryKey, role, "proxy"); addBasePathOptionsToSwagger(parent, swagger, swaggerOperation, directory, apiAuthorizers); addSwaggerOperation(swagger, proxyPath, swaggerMethod("ANY"), swaggerOperation); } function createSwaggerOperationForObjectKey(objectKey, role, pathParameter) { const region = (0, utils_1.getRegion)(bucket); const uri = pulumi.interpolate `arn:aws:apigateway:${region}:s3:path/${bucket.bucket}/${objectKey}${(pathParameter ? `/{${pathParameter}}` : ``)}`; const result = { responses: { "200": { description: "200 response", schema: { type: "object" }, headers: { "Content-Type": { type: "string" }, "content-type": { type: "string" }, }, }, "400": { description: "400 response", }, "500": { description: "500 response", }, }, "x-amazon-apigateway-integration": { credentials: role.arn, uri: uri, passthroughBehavior: "when_no_match", httpMethod: "GET", type: "aws", responses: { "4\\d{2}": { statusCode: "400", }, "default": { statusCode: "200", responseParameters: { "method.response.header.Content-Type": "integration.response.header.Content-Type", "method.response.header.content-type": "integration.response.header.content-type", }, }, "5\\d{2}": { statusCode: "500", }, }, }, }; if (pathParameter) { result.parameters = [{ name: pathParameter, in: "path", required: true, type: "string", }]; result["x-amazon-apigateway-integration"].requestParameters = { [`integration.request.path.${pathParameter}`]: `method.request.path.${pathParameter}`, }; } return result; } } function addIntegrationRouteToSwaggerSpec(parent, name, swagger, route, apiAuthorizers) { checkRoute(parent, route, "target"); const target = isIntegrationRouteTargetProvider(route.target) ? pulumi.output(route.target.target(name + (0, utils_1.sha1hash)(route.path), parent)) : pulumi.output(route.target); // Register two paths in the Swagger spec, for the root and for a catch all under the root const method = swaggerMethod("ANY"); const swaggerPath = route.path.endsWith("/") ? route.path : route.path + "/"; const swaggerPathProxy = swaggerPath + "{proxy+}"; const swaggerOpWithoutProxyPathParam = createSwaggerOperationForProxy(target, /*useProxyPathParameter:*/ false); addBasePathOptionsToSwagger(parent, swagger, swaggerOpWithoutProxyPathParam, route, apiAuthorizers); addSwaggerOperation(swagger, swaggerPath, method, swaggerOpWithoutProxyPathParam); const swaggerOpWithProxyPathParam = createSwaggerOperationForProxy(target, /*useProxyPathParameter:*/ true); addBasePathOptionsToSwagger(parent, swagger, swaggerOpWithProxyPathParam, route, apiAuthorizers); addSwaggerOperation(swagger, swaggerPathProxy, method, swaggerOpWithProxyPathParam); return; function createSwaggerOperationForProxy(target, useProxyPathParameter) { const uri = target.apply(t => { let result = t.uri; // ensure there is a trailing `/` if (!result.endsWith("/")) { result += "/"; } if (useProxyPathParameter) { result += "{proxy}"; } return result; }); const connectionType = target.connectionType; const connectionId = target.connectionId; const type = (0, utils_1.ifUndefined)(target.type, "http_proxy"); const passthroughBehavior = (0, utils_1.ifUndefined)(target.passthroughBehavior, "when_no_match"); const result = { "x-amazon-apigateway-integration": { responses: { default: { statusCode: "200", }, }, uri, type, connectionType, connectionId, passthroughBehavior, httpMethod: "ANY", }, }; if (useProxyPathParameter) { result.parameters = [{ name: "proxy", in: "path", required: true, type: "string", }]; result["x-amazon-apigateway-integration"].requestParameters = { "integration.request.path.proxy": "method.request.path.proxy", }; } return result; } } function addRawDataRouteToSwaggerSpec(parent, name, swagger, route) { checkRoute(parent, route, "data"); checkRoute(parent, route, "method"); // Simply take the [data] part of the route and place it into the correct place in the // swagger spec "paths" location. addSwaggerOperation(swagger, route.path, swaggerMethod(route.method), route.data); } function swaggerMethod(method) { switch (method.toLowerCase()) { case "get": case "put": case "post": case "delete": case "options": case "head": case "patch": return method.toLowerCase(); case "any": return "x-amazon-apigateway-any-method"; default: throw new Error("Method not supported: " + method); } } const apigatewayAssumeRolePolicyDocument = { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "apigateway.amazonaws.com", }, "Action": "sts:AssumeRole", }, ], }; function safeS3BucketName(apiName) { return apiName.toLowerCase().replace(/[^a-z0-9\-]/g, ""); } //# sourceMappingURL=api.js.map