Search code examples
amazon-web-servicesaws-lambdaswaggerswagger-ui

Serve Swagger docs via Lambda


I'm trying to publish the documentation for an API I've developed by means of swagger-ui. Since the API is hosted on AWS API Gateway, I have developed the below Lambda to handle the /swagger-simpler API endpoint. I've confirmed that I'm successfully retrieving the docs, but when I go to the /swagger-simpler endpoint, I get the error: Uncaught SyntaxError: expected expression, got '<' in swagger-ui-bundle.js. When I pull up swagger-ui-bundle.js, it's the exact same HTML as I get when I pull up the /swagger-simpler endpoint.

What am I doing wrong?

Swagger Lambda:

/** @format */
import 'source-map-support/register'
import express from 'express'
import serverless from 'serverless-http'
import swaggerUi from 'swagger-ui-express'
import { Handler } from 'aws-lambda'
import { APIGatewayClient, GetExportCommand } from '@aws-sdk/client-api-gateway'

const app = express()
const apiGateway = new APIGatewayClient({})

export const handler: Handler = async (event, context) => {
  const apiId = event.requestContext.apiId
  const stage = event.requestContext.stage

  console.debug('From request context', { apiId, stage })

  let swaggerJson: swaggerUi.JsonObject
  try {
    swaggerJson = await getSwaggerJson(apiId, stage)
  } catch (e) {
    console.error('Failed to retreive Swagger JSON', e)
    throw new Error('Failed to retreive Swagger JSON')
  }
  console.debug('Got Swagger doc object', { swaggerJson })
  app.use('/swagger-simpler', swaggerUi.serve, swaggerUi.setup(swaggerJson))
  console.debug('here')
  const handler = serverless(app)
  console.debug('got handler', { handler })
  const ret = await handler(event, context)
  console.debug('handler returned', { ret })
  return ret
}

const getSwaggerJson = async (
  restApiId: string,
  stageName: string
): Promise<swaggerUi.JsonObject> => {
  const params = {
    exportType: 'oas30',
    restApiId,
    stageName,
    accepts: 'application/json',
  }
  const res = await apiGateway.send(new GetExportCommand(params))
  console.debug('GetExportCommand successful', { res })
  let swaggerJson: string
  if (res.body) {
    swaggerJson = Buffer.from(res.body).toString()
  } else {
    throw new Error('Empty response body from GetExportCommand')
  }
  console.debug('Got Swagger JSON', { swaggerJson })

  return JSON.parse(swaggerJson)
}


Solution

  • It turned out to be a CDK issue. See the article I wrote about it for details, but basically I needed to install swagger-ui-express and express via node_modules rather than having those modules bundled into the generated JS.