Documenting your Flask-powered API like a boss
Tags: python, flask, apispec, openapi
Published: 2017-12-05 14:23:24

---
title: "Documenting your Flask-powered API like a boss"
published: true
description: 
canonical_url: https://becominghuman.ai/documenting-your-flask-powered-api-like-a-boss-b423a7c0f45e
cover_image: https://static.pexels.com/photos/442420/books-shelves-architecture-wood-442420.jpeg
tags: python, flask, apispec, openapi
---

Flask is a very popular and powerful framework for building web applications. Over the last years, people used it to create REST API that work well with decoupled, modern front-end applications.

One challenge that backend development teams often face, is how to make it easy for front-end developers, wethere internal or with a distant community, to create API-compliant clients (web app, mobile app or even CLI tools...)

In the wild, they are many good examples of well-documented APIs... Take the Twitter API : the docs are great, user-friendly and cover all the available endpoint with tips and examples. Any fresh CS student could write a small Python tool using it, just by following the documentation and its examples.

At @Ooreka, we decided to follow the [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md) (fka Swagger 2.0) specification to build a solid documentation for our Flask-powered micro-services APIs. Let's dive in.

## 3..2..1.. Doc!

Thanks to the [apispec](http://apispec.readthedocs.io/en/latest/) lib, you can automagically generate a specification file (commonly named `swagger.json`) form your Flask code. Some other libraries can do a lot of magic for you, but `apispec` is really simple to use and can sit next to your code without interfering with it.

It supports [Marshmallow and Flask](http://apispec.readthedocs.io/en/latest/using_plugins.html), allowing you to re-use your code to generate a proper documentation !

Let's write our generation script, e.g. `app/scripts/openapi.py` :

```python
from apispec import APISpec

# Create spec
spec = APISpec(
    title='My Awesome API',
    version='1.0.42',
    info=dict(
        description='You know, for devs'
    ),
    plugins=[
        'apispec.ext.flask',
        'apispec.ext.marshmallow'
    ]
)

# Reference your schemas definitions
from app.schemas import FooSchema

spec.definition('Foo', schema=FooSchema)
# ...

# Now, reference your routes.
from app.views import my_route

# We need a working context for apispec introspection.
app = create_app()

with app.test_request_context():
    spec.add_path(view=my_route)
    # ...

# We're good to go! Save this to a file for now.
with open('swagger.json', 'w') as f:
    json.dump(spec.to_dict(), f)
```

Here, we first create a new APISpec instance with some details about our API.
Then, we add our definitions (here, we are using Marshmallow to define how our API will serialize/deserialize data) with `APISpec.definition()`.
Finally, we add our routes to our API specification using `APISpec.add_path()`. `apispec` will parse your route functions docstrings, so make sure your add some OpenAPI YaML stuff here, as in :

```python
@app.route('/foo/<bar_id>')
def my_route(gist_id):
    """ Cool Foo-Bar route.
    - - - # dev.to editor dislike triple hyphen, be sure to remove spaces here.
    get:
        summary: Foo-Bar endpoint.
        description: Get a single foo with the bar ID.
        parameters:
            - name: bar_id
              in: path
              description: Bar ID
              type: integer
              required: true
        responses:
            200:
                description: Foo object to be returned.
                schema: FooSchema
            404:
                description: Foo not found.
    """
    # (...)
    return jsonify(foo)
```

You will end up with a valid JSON API specification. Now, let's see how to bootstrap an HTML version to show it to the world!

## Browerify-ing all this

A really cool tool to do that is the [ReDoc](https://github.com/Rebilly/ReDoc) Javascript library from the guys at [APIs.guru](https://apis.guru/). We'll use it to present the generated JSON specification in a convenient way.

Redoc is basically a single, minified JS file you can include in a bare `index.html` file and tell it where your `swagger.json` is located. It uses a really neat 3 columns design : a navigation sidebar, a wide center section with your API endpoints definitions and a third column dedicated to requests or responses samples and examples.

```html
<!DOCTYPE html>
<html>
  <head>
    <title>Cool API Documentation</title>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <style> body { margin: 0; padding: 0; } </style>
  </head>
  <body>
    <redoc spec-url='./swagger.json' hide-loading></redoc>
    <script src="https://rebilly.github.io/ReDoc/releases/latest/redoc.min.js"> </script>
  </body>
</html>
```

Yep, that was quick. Check out a real-world example [here](https://rebilly.github.io/RebillyAPI/).

## Wrapping it up

The OpenAPI offers many options I didn't cover here for brievity and simplification. You can add your server's real endpoints to the doc, add many details about the parameters and responses of your routes, provide example in your routes functions docstring that will be parsed and added to your spec, etc...

As a final tip, head to the [Flask CLI](http://flask.pocoo.org/docs/0.12/cli/) documentation to see how easily you can hook your generation script into the command line interface of Flask (this will give you some badass command like `FLASK_APP=main.py flask generate_doc`). Oh, and be sure to put this into your Continuous Integration routine to keep your API documentation up-to-date with your API!

Cheers!

_NOTE: This post was originally posted on [Medium](https://becominghuman.ai/documenting-your-flask-powered-api-like-a-boss-b423a7c0f45e)._