UNPKG

serverless-offline

Version:

Emulate AWS λ and API Gateway locally when developing your Serverless project

184 lines (146 loc) 4.66 kB
const { entries, fromEntries, keys } = Object const APIGATEWAY_INTEGRATION_TYPE_HTTP_PROXY = "HTTP_PROXY" const APIGATEWAY_ROOT_ID = "RootResourceId" const APIGATEWAY_TYPE_METHOD = "AWS::ApiGateway::Method" const APIGATEWAY_TYPE_RESOURCE = "AWS::ApiGateway::Resource" function getApiGatewayTemplateObjects(resources) { const Resources = resources && resources.Resources if (!Resources) { return {} } const methodObjects = [] const pathObjects = [] entries(Resources).forEach(([key, value]) => { const resourceObj = value || {} const keyValuePair = [key, resourceObj] const { Type } = resourceObj if (Type === APIGATEWAY_TYPE_METHOD) { methodObjects.push(keyValuePair) } else if (Type === APIGATEWAY_TYPE_RESOURCE) { pathObjects.push(keyValuePair) } }) return { methodObjects: fromEntries(methodObjects), pathObjects: fromEntries(pathObjects), } } /* Example of a Resource Object * "ApiGatewayResourceFavicon": { * "Type": "AWS::ApiGateway::Resource", * "Properties": { * "ParentId": { "Fn::GetAtt": [ "ApiGatewayRestApi", "RootResourceId" ] }, * "PathPart": "favicon.ico", * "RestApiId": { "Ref": "ApiGatewayRestApi" } * } * } */ /* Resource Helpers */ function isRoot(resourceId) { return resourceId === APIGATEWAY_ROOT_ID } function getPathPart(resourceObj) { if (!resourceObj || !resourceObj.Properties) { return undefined } return resourceObj.Properties.PathPart } function getParentId(resourceObj) { if (!resourceObj || !resourceObj.Properties) { return undefined } const parentIdObj = resourceObj.Properties.ParentId || {} const { Ref } = parentIdObj if (Ref) return Ref const getAtt = parentIdObj["Fn::GetAtt"] || [] return getAtt[1] } function getFullPath(pathObjects, resourceId) { let currentId = resourceId let currentObj const arrResourceObjects = [] while (currentId && !isRoot(currentId)) { currentObj = pathObjects[currentId] arrResourceObjects.push(currentObj) currentId = getParentId(currentObj) } const arrPath = arrResourceObjects.map(getPathPart).reverse() if (arrPath.some((s) => !s)) { return undefined } return `/${arrPath.join("/")}` } /* Example of an HTTP Proxy Method Object * "ApiGatewayResourcePublicAnyProxyMethod": { * "Type": "AWS::ApiGateway::Method", * "Properties": { * "ResourceId": { "Ref": "ApiGatewayResourcePublicAny" }, * "RestApiId": { "Ref": "ApiGatewayRestApi" }, * "AuthorizationType": "NONE", * "HttpMethod": "GET", * "MethodResponses": [ { "StatusCode": 200 } ], * "RequestParameters": { "method.request.path.proxy": true }, * "Integration": { * "Type": "HTTP_PROXY", * "IntegrationHttpMethod": "GET", * "Uri": "https://www.example.com/us-west-2/{proxy}", // Note that ${self:provider.region} is expanded * "IntegrationResponses": [ { "StatusCode": 200 } ], * "RequestParameters": { "integration.request.path.proxy": "method.request.path.proxy" }, * "PassthroughBehavior": "WHEN_NO_MATCH" * } * } * } */ /* Method Helpers */ function getResourceId(methodObj) { if (!methodObj || !methodObj.Properties) { return undefined } if (!methodObj.Properties.ResourceId) { return undefined } return methodObj.Properties.ResourceId.Ref } function getHttpMethod(methodObj) { if (!methodObj || !methodObj.Properties) { return undefined } return methodObj.Properties.HttpMethod } function getIntegrationObj(methodObj) { if (!methodObj || !methodObj.Properties) { return undefined } return methodObj.Properties.Integration } function constructHapiInterface(pathObjects, methodObjects, methodId) { // returns all info necessary so that routes can be added in index.js const methodObj = methodObjects[methodId] const resourceId = getResourceId(methodObj) const Integration = getIntegrationObj(methodObj) || {} const pathResource = getFullPath(pathObjects, resourceId) const method = getHttpMethod(methodObj) // let integrationType; let proxyUri if (!pathResource) { return {} } if (Integration.Type === APIGATEWAY_INTEGRATION_TYPE_HTTP_PROXY) { proxyUri = Integration.Uri } return { isProxy: !!proxyUri, method, pathResource, proxyUri, } } export default function parseResources(resources) { const { methodObjects, pathObjects } = getApiGatewayTemplateObjects(resources) return fromEntries( keys(methodObjects).map((key) => [ key, constructHapiInterface(pathObjects, methodObjects, key), ]), ) }