Swagger UI via AWS API Gateway and AWS CDK
There are a bunch of sites that will tell you how to do a Swagger UI in Lambda. This one is nice enough to have a publicly available application you can deploy from AWS SAR. This one tells you how to do it in S3. But none that I’ve found tell you how to do it in AWS CDK. I aim to remedy that.
The whole stack is available at https://github.com/PopeFelix/swagger-ui-apigateway-example-with-typescript-and-cdk if you’d like to skip ahead. :)
Now, you might naively think that all you have to do is write a Lambda like so and you’ll be good to go:
import 'source-map-support/register'
import express from 'express'
import serverlessExpress from '@vendia/serverless-express'
import swaggerUi from 'swagger-ui-express'
import { Handler } from 'aws-lambda'const app = express()
const url = 'https://petstore.swagger.io/v2/swagger.json'export const handler: Handler = async (event, context, callback) => {
const resource = event.resource
const path = event.path
app.use('/', swaggerUi.serve, swaggerUi.setup({ url }))
const handler = serverlessExpress({ app })
return await handler(event, context, callback)
}
And in fact, that Lambda is fine. That’s just what you need for the Swagger UI to work flawlessly. The tricky bit is in the CDK deployment.
Normally, to deploy a Lambda, you’d do something like this:
const swaggerLambda = new cdk.aws_lambda_nodejs.NodejsFunction(
this,
'swagger',
{
entry: path.join(__dirname, '../lambda/swagger/index.ts')
}
)
And that’s exactly what I did, and it didn’t work. Anything I requested via the Swagger endpoint besides swagger-ui-init.js
would return the Swagger UI HTML. It turns out that this was because CDK bundles all of your compiled Typescript together into one big file when it deploys a Lambda. This is great for efficiency, but not so good when modules like swagger-ui-express
are looking for actual system paths. The solution? Set the bundling
options like so:
const swaggerLambda = new cdk.aws_lambda_nodejs.NodejsFunction(
this,
'swagger',
{
entry: path.join(__dirname, '../lambda/swagger/index.ts'),
bundling: {
nodeModules: ['swagger-ui-express', 'express'],
},
}
)
That nodeModules
option tells CDK that swagger-ui-express
and express
need to be installed (i.e. npm i swagger-ui-express express
) rather than bundled with the Lambda code.
And that’s it! Hope this helps!