OpenAPI, formerly known as Swagger (or still known, depending who you ask!), is used to describe a REST API’s
Well, good news, I’ve created a npm package to do that, which you can find on GitHub and in this post we’ll take a look at how to use it.
How it works
The second part of the plugin is used to create an endpoint which the OpenAPI spec file will be exposed via.
Also, the package will give you the option to use each of the different spec version, v2, v3 and v3.1, so you can describe the API in the way that’s right for consumers.
Annotating a Function
Let’s look at how we can annotate a Function to expose an OpenAPI spec, and we’ll look at the Trivia Game example, specifically the
We’ll use the OpenAPI 3.1 spec, which is the latest at time of authoring, as the schema, so the first thing is to import the mapping function:
Next, we’ll change the
export default to be a call to the mapping function, rather than the Function handler itself:
mapOpenApi3_1 (aliased as
openApi in my sample) takes three arguments:
- The Function handler that the trigger invokes
- The path for the API
- The OpenAPI spec definition for this path
Note: If you’re using TypeScript, you’ll get type help as you build out your schema, thanks to the
openapi-types npm package.
This Function will respond on a
GET request, expect the
gameId to be a URL parameter and return a
200 when the game is found or a
404 if it is not, so we can describe that in our object. Let’s start with the parameter:
The top level of the object is the verb that we’re going to be working with (you can define multiple verbs for each Function) and then we use the
parameters array to describe the parameter. The
gameId is being describe as required and that it’s a string, plus we can attach some metadata to it if we desire, I’m giving it a description for example.
Now we can define some responses. Let’s start simple with the 404:
Here we’ve added a new
responses property and we can define any status code we want as the response code and attach info to it. Since this was a 404, all I’ve done is defined the description as it won’t return a body. For a more complex one, let’s put in the 200:
The 200 response will have a body and that is defined in the
content property, in which you can set the content for the different possible mime types. I’m only supporting a mime type of
application/json, so that’s all that’s defined and for the content it returns we’re using a schema reference to a component defined elsewhere in our spec. This is useful if you’ve got objects that can be used in multiple places, which the
Game time would likely be (it’s shared between
POST in the sample).
But that’s the first part completed, we’ve defined the spec information for our
game-get API, on to creating the endpoint that will make it available to us.
Defining the swagger.json endpoint
We’ve got to the effort of annotating our Function but there needs to be some way in which consumers and get that, and to do that, we need to create a Function for them to access it. Start by creating a new HTTP Trigger Function, delete it’s contents and then we can use another helper function from the npm package:
With this Function we’re going define the shared metadata and components that our OpenAPI spec requires, as it’ll be merged with the annotated Functions at runtime. Start by telling consumers about the API:
This is really the minimum you need to do, but since we used
$ref to reference a shared component schema, we should define that as well. I’ll only show one of the shared components, as this object model has components that reference other components, but you should get the idea:
And there you have it,
Game is now defined and can be used as a reference elsewhere within our spec. You can find the full implementation with all other schema objects in the GitHub source.
Start up your Azure Functions (with CORS enabled) and pop the spec endpoint into Swagger UI and you’ll see your docs generated!
There we have it, a working app in Azure Functions which provides OpenAPI docs for anyone who wants to consume them.
I have ideas of things to do next, but I’m more keen to solve the problems that you’d experience with it first.