Package: alma-cdk.openapix
npmi-D@alma-cdk/openapixGenerate AWS Api Gateway REST APIs viaOpenAPI(formely known as “Swagger”) Schema Definitions by consuming "clean" OpenAPI schemas and injectx-amazon-apigateway-extensionswith type-safety.🚧   Project StabilityThis construct is still versioned withv0major version and breaking changes might be introduced if necessary (without a major version bump), though we aim to keep the API as stable as possible (even withinv0development). We aim to publishv1.0.0soon and after that breaking changes will be introduced via major version bumps.There are also some incomplete or buggy features, such as CORS andCognitoUserPoolsAuthorizer.Getting StartedInstallnpm i -D @alma-cdk/openapixDefine your API OpenApi Schema Definition in a.yamlfilewithoutanyx-amazon-apigateway-extensionsUseopenapixconstructs in CDK to consume the.yamlfile and then assign API Gateway integrations using CDKHTTP IntegrationGiven the followinghttp-proxy.yamlOpenApi schema definition,withoutany AWS API Gateway OpenApi extensions:openapi:3.0.3info:title:HTTP Proxydescription:Proxies requests to example.comversion:"0.0.1"paths:"/":get:summary:proxydescription:Proxies example.comYou may then define API Gateway HTTP integration (within your stack):newopenapix.Api(this,'HttpProxy',{source:path.join(__dirname,'../schema/http-proxy.yaml'),paths:{'/':{get:newopenapix.HttpIntegration(this,'http://example.com',{httpMethod:'get',}),},},});See/examples/http-proxyfor full OpenApi definition (with response models) and an example within a CDK application.Lambda IntegrationGiven the followinghello-api.yamlOpenApi schema definition,withoutany AWS API Gateway OpenApi extensions:openapi:3.0.3info:title:Hello APIdescription:Defines an example “Hello World” APIversion:"0.0.1"paths:"/":get:operationId:sayHellosummary:Say Hellodescription:Prints out a greetingparameters:-name:namein:queryrequired:falseschema:type:stringdefault:"World"responses:"200":description:Successful responsecontent:"application/json":schema:$ref:"#/components/schemas/HelloResponse"components:schemas:HelloResponse:description:Response bodytype:objectproperties:message:type:stringdescription:Greetingexample:Hello World!You may then define API Gateway AWS Lambda integration (within your stack):constgreetFn=newNodejsFunction(this,'greet');newopenapix.Api(this,'HelloApi',{source:path.join(__dirname,'../schema/hello-api.yaml'),paths:{'/':{get:newopenapix.LambdaIntegration(this,greetFn),},},})See/examples/hello-apifor full OpenApi definition (with response models) and an example within a CDK application.AWS Service IntegrationGivenbooks-api.yamlOpenApi schema definition,withoutany AWS API Gateway OpenApi extensions, You may then define API Gateway AWS service integration such as DynamoDB (within your stack):newopenapix.Api(this,'BooksApi',{source:path.join(__dirname,'../schema/books-api.yaml'),paths:{'/':{get:newopenapix.AwsIntegration(this,{service:'dynamodb',action:'Scan',options:{credentialsRole:role,//rolemusthaveaccesstoDynamoDBtablerequestTemplates:{'application/json':JSON.stringify({TableName:table.tableName,}),},integrationResponses:[{statusCode:'200',responseTemplates:{//See/examples/http-proxy/lib/list-books.vtl'application/json':readFileSync(__dirname+'/list-books.vtl','utf-8'),},}],},}),},'/{isbn}':{get:newopenapix.AwsIntegration(this,{service:'dynamodb',action:'GetItem',options:{credentialsRole:role,//rolemusthaveaccesstoDynamoDBtablerequestTemplates:{'application/json':JSON.stringify({TableName:table.tableName,Key:{item:{"S":"$input.params('isbn')"}}}),},integrationResponses:[{statusCode:'200',responseTemplates:{//See/examples/http-proxy/lib/get-book.vtl'application/json':readFileSync(__dirname+'/get-book.vtl','utf-8'),},}],},}),},},});See/examples/books-apifor full OpenApi definition (with response models) and an example within a CDK application.Mock IntegrationGiven the followingmock-api.yamlOpenApi schema definition,withoutany AWS API Gateway OpenApi extensions:openapi:3.0.3info:title:Hello APIdescription:Defines an example “Hello World” APIversion:"0.0.1"paths:"/":get:operationId:sayHellosummary:Say Hellodescription:Prints out a greetingparameters:-name:namein:queryrequired:falseschema:type:stringdefault:"World"responses:"200":description:Successful responsecontent:"application/json":schema:$ref:"#/components/schemas/HelloResponse"components:schemas:HelloResponse:description:Response bodytype:objectproperties:message:type:stringdescription:Greetingexample:Hello World!You may then define API Gateway Mock integration (within your stack):newopenapix.Api(this,'MockApi',{source:path.join(__dirname,'../schema/mock-api.yaml'),paths:{'/':{get:newopenapix.MockIntegration(this,{requestTemplates:{"application/json":JSON.stringify({statusCode:200}),},passthroughBehavior:apigateway.PassthroughBehavior.NEVER,requestParameters:{'integration.request.querystring.name':'method.request.querystring.name',},integrationResponses:[{statusCode:'200',responseTemplates:{//see/examples/mock-api/lib/greet.vtl'application/json':readFileSync(__dirname+'/greet.vtl','utf-8'),},responseParameters:{},},],}),},},});See/examples/mock-apifor full OpenApi definition (with response models) and an example within a CDK application.ValidatorsAPI Gateway REST APIs can performrequest parameter and request body validation. You can provide both default validator and integration specific validator (which will override the default for given integration).See/examples/todo-apifor complete example within a CDK application.Giventodo-api.yamlOpenApi schema definitionyou may define the API Gateway validators for your integration in CDK:newopenapix.Api(this,'MyApi',{source:path.join(__dirname,'../schema/todo-api.yaml'),validators:{'all':{validateRequestBody:true,validateRequestParameters:true,default:true,//setthisasthe"API level"defaultvalidator(therecanbeonlyone)},'params-only':{validateRequestBody:false,validateRequestParameters:true,},},paths:{'/todos':{//thisoneusesthedefault'all'validatorpost:newopenapix.HttpIntegration(this,baseUrl,{httpMethod:'post'}),},'/todos/{todoId}':{//thisonehasvalidatoroverrideanduses'params-only'validatorget:newopenapix.HttpIntegration(this,`${baseUrl}/{todoId}`,{validator:'params-only',options:{requestParameters:{'integration.request.path.todoId':'method.request.path.todoId',},},}),},},})Authorizers🚧 Work-in-ProgressThere are multiple ways tocontrol & manages access to API Gateway REST APIssuch asresource policies,IAM permissionsandusage plans with API keysbut this section focuses onCognito User PoolsandLambda authorizers.Cognito AuthorizersIn this example we're defining a Congito User Pool based authorizer.Given the followingschema.yamlOpenApi definition:openapi:3.0.3paths:/:get:security:-MyAuthorizer:["test/read"]# add scopecomponents:securitySchemes:MyCognitoAuthorizer:type:apiKeyname:Authorizationin:headerYou can define the Cognito Authorizer in CDK with:constuserPool:cognito.IUserPool;newopenapix.Api(this,'MyApi',{source:'./schema.yaml',authorizers:[newopenapix.CognitoUserPoolsAuthorizer(this,'MyCognitoAuthorizer',{cognitoUserPools:[userPool],resultsCacheTtl:Duration.minutes(5),})],})Lambda AuthorizersIn this example we're defining a custom Lambda authorizer. The authorizer function code is not relevant for the example but the idea in the example is that an API caller sends some "secret code" in query parameters (?code=example123456) which then the authorizer function somehow evaluates.Given the followingschema.yamlOpenApi definition:openapi:3.0.3paths:/:get:security:-MyAuthorizer:[]# note the empty arraycomponents:securitySchemes:MyCustomAuthorizer:type:apiKeyname:codein:queryYou can define the custom Lambda Authorizer in CDK with:constauthFn:lambda.IFunction;newopenapix.Api(this,'MyApi',{source:'./schema.yaml',authorizers:[newopenapix.LambdaAuthorizer(this,'MyCustomAuthorizer',{fn:authFn,identitySource:apigateway.IdentitySource.queryString('code'),type:'request',authType:'custom',resultsCacheTtl:Duration.minutes(5),}),],})Inject/RejectYou may modify the generated OpenAPI definition (which is used to define API Gateway REST API) by injecting or rejecting values from the source OpenAPI schema definition:newopenapix.Api(this,'MyApi',{source:'./schema.yaml',//AddanyOpenAPIv3data.//CanbeusefulforpassingvaluesfromCDKcode.//Seehttps://swagger.io/specification/injections:{"info.title":"FancyPantsAPI"},//Rejectfieldsbyabsoluteobjectpathfromgenerateddefinitionrejections:['info.description'],//RejectallmatchingfieldsfromgenerateddefinitionrejectionsDeep:['example','examples'],});CORS🚧 Work-in-ProgressUsingopenapix.CorsIntegrationcreates a Mock integration which responds with correct response headers:newopenapix.Api(this,'MyApi',{source:'./schema.yaml',paths:{'/foo':{options:newopenapix.CorsIntegration(this,{//usinghelpermethodtodefineexplicitvalues:headers:CorsHeaders.from(this,'Content-Type','X-Amz-Date','Authorization'),origins:CorsOrigins.from(this,'https://www.example.com'),methods:CorsMethods.from(this,'options','post','get'),}),},'/bar':{options:newopenapix.CorsIntegration(this,{//usingregularstringvalues:headers:'Content-Type,X-Amz-Date,Authorization',origins:'*',methods:'options,get',}),},'/baz':{options:newopenapix.CorsIntegration(this,{//usinghelperconstantforwildcardvalues:headers:CorsHeaders.ANY,origins:CorsOrigins.ANY,methods:CorsMethods.ANY,}),},},});When specifying multipleoriginsthe mock integration usesVTL magicto respond with the correctAccess-Control-Allow-Originheader.Default CORSIf you wish to define same CORS options to every path, you may do so by providing a defaultcorsvalue:newopenapix.Api(this,'MyApi',{source:'./schema.yaml',defaultCors:newopenapix.CorsIntegration(this,{headers:CorsHeaders.ANY,origins:CorsOrigins.ANY,methods:CorsMethods.ANY,}),paths:{/*...*/},});This will apply the givencorsconfiguration toeverypath asoptionsmethod. You may still do path specific overrides by adding anoptionsmethod to specific paths.API Gateway EndpointTypeAWS CDK API Gateway constructs default toEdge-optimized API endpointsby usingEndpointType.EDGEas the default.This construct@alma-cdk/openapixinstead defaults to usingRegional API endpointsby settingEndpointType.REGIONALas the default value. This is because we believe that in most cases you're better of by configuring your own CloudFront distribution in front the API. If you do that, you might also be interested in@alma-cdk/origin-verifyconstruct.You MAY override this default in@alma-cdk/openapixby providing your preferred endpoint types viarestApiProps:newopenapix.Api(this,'MyApi',{source:'./schema.yaml',paths:{/*...*/},restApiProps:{endpointConfiguration:{types:[apigateway.EndpointType.EDGE],},},});