Technology Sharing

Apispec, a Python library for generating OpenAPI (Swagger) specifications

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Table of contents

01What is Apispec?

Why choose Apispec?

Installation and Configuration

02Basic usage of Apispec

Generate simple API documentation

1. Create an Apispec instance

2. Define API routes and views

3. Add path to Apispec

Integrating Flask and Apispec

1. Install Flask and Flask-Apispec

2. Create a Flask application

Integrating Django and Apispec

1. Install Django and Django-Rest-Framework

2. Create a Django project and application

3. Configure the Django project

4. Define Django views

5. Configure URL

6. Generate OpenAPI specification

03Advanced features of Apispec

1. Custom generator

2. Support multiple frameworks

3. Automatically generate interface documentation

4. Integration with third-party tools

04 Actual combat cases

1. Project Introduction

2. Project Structure

3. Install dependencies

4. Define the model

5. Define views and serialization

6. Define the main application

7. Run the application and view the documentation

Visit http://localhost:5000/swagger/ to view the generated API documentation.

05Best Practices

06 Summary



01What is Apispec?

About Apispec

Apispec is a Python library for generating OpenAPI (Swagger) specifications. It can help developers automatically generate and maintain API documents, and provide intuitive and detailed interface descriptions. With Apispec, we can easily convert the documentation string of a Python function or class into a document that complies with the OpenAPI specification, reducing the trouble of manually writing documents.

Why choose Apispec?

  • Simple and easy to use: Apispec provides a simple and easy-to-use API so that you can get started quickly.

  • Flexible and powerful: Supports multiple frameworks (such as Flask, Django) and extensions, allowing you to customize document generation according to your needs.

  • automation: Reduce manual operations and maintenance costs by automatically generating and updating documents.

Installation and Configuration

Before we start using Apispec, we need to install it first. You can install it using pip:

pip install apispec

Github project address:

https://github.com/marshmallow-code/apispec

02Basic usage of Apispec

Let's look at the basic usage of Apispec through a few simple examples.

Generate simple API documentation

1. Create an Apispec instance

  1. from apispec import APISpec
  2. spec = APISpec(
  3.     title="My API",
  4.     version="1.0.0",
  5.     openapi_version="3.0.0",
  6.     info=dict(description="This is a sample API"),
  7. )

2. Define API routes and views

  1. def get_user(user_id):
  2.     """
  3.     ---
  4.     get:
  5.       description: Get a user by ID
  6.       parameters:
  7.         - name: user_id
  8.           in: path
  9.           required: true
  10.           schema:
  11.             type: integer
  12.       responses:
  13.         200:
  14.           description: A user object
  15.           content:
  16.             application/json:
  17.               schema:
  18.                 type: object
  19.                 properties:
  20.                   id:
  21.                     type: integer
  22.                   name:
  23.                     type: string
  24.     """
  25.     return {"id": user_id, "name""John Doe"}

3. Add path to Apispec

  1. spec.path(
  2.     path="/users/{user_id}",
  3.     operations=dict(
  4.         get=dict(
  5.             description="Get a user by ID",
  6.             parameters=[
  7.                 {
  8.                     "name""user_id",
  9.                     "in""path",
  10.                     "required"True,
  11.                     "schema": {"type""integer"},
  12.                 }
  13.             ],
  14.             responses={
  15.                 "200": {
  16.                     "description""A user object",
  17.                     "content": {
  18.                         "application/json": {
  19.                             "schema": {
  20.                                 "type""object",
  21.                                 "properties": {
  22.                                     "id": {"type""integer"},
  23.                                     "name": {"type""string"},
  24.                                 },
  25.                             }
  26.                         }
  27.                     },
  28.                 }
  29.             },
  30.         )
  31.     ),
  32. )

Integrating Flask and Apispec

1. Install Flask and Flask-Apispec

pip install Flask Flask-Apispec

2. Create a Flask application

  1. from flask import Flask, jsonify
  2. from flask_apispec import FlaskApiSpec, doc, marshal_with
  3. from flask_apispec.views import MethodResource
  4. from marshmallow import Schema, fields
  5. app = Flask(__name__)
  6. class UserSchema(Schema):
  7.     id = fields.Int()
  8.     name = fields.Str()
  9. class UserResource(MethodResource):
  10.     @doc(description='Get a user by ID', tags=['User'])
  11.     @marshal_with(UserSchema)
  12.     def get(self, user_id):
  13.         return {"id": user_id, "name""John Doe"}
  14. app.add_url_rule('/users/<int:user_id>', view_func=UserResource.as_view('user_resource'))
  15. docs = FlaskApiSpec(app)
  16. docs.register(UserResource)
  17. @app.route('/swagger/')
  18. def swagger_ui():
  19.     return jsonify(docs.spec.to_dict())
  20. if __name__ == '__main__':
  21.     app.run()

Integrating Django and Apispec

1. Install Django and Django-Rest-Framework

pip install django djangorestframework

2. Create a Django project and application

  1. django-admin startproject myproject
  2. cd myproject
  3. django-admin startapp myapp

3. Configure the Django project

Add rest_framework and apispec in settings.py:

  1. INSTALLED_APPS = [
  2.     ...
  3.     'rest_framework',
  4.     'myapp',
  5.     'apispec',
  6. ]

4. Define Django views

In myapp/views.py:

  1. from rest_framework.views import APIView
  2. from rest_framework.response import Response
  3. from rest_framework.schemas import AutoSchema
  4. class UserView(APIView):
  5.     schema = AutoSchema(
  6.         manual_fields=[
  7.             coreapi.Field('user_id', required=True, location='path', schema={'type''integer'})
  8.         ]
  9.     )
  10.     def get(self, request, user_id):
  11.         """
  12.         Get a user by ID.
  13.         ---
  14.         responses:
  15.           200:
  16.             description: A user object
  17.             content:
  18.               application/json:
  19.                 schema:
  20.                   type: object
  21.                   properties:
  22.                     id:
  23.                       type: integer
  24.                     name:
  25.                       type: string
  26.         """
  27.         return Response({"id": user_id, "name""John Doe"})

5. Configure URL

In myapp/urls.py:

  1. from django.urls import path
  2. from .views import UserView
  3. urlpatterns = [
  4.     path('users/<int:user_id>/', UserView.as_view(), name='user-view'),
  5. ]

6. Generate OpenAPI specification

In manage.py:

  1. from apispec import APISpec
  2. from rest_framework.schemas import get_schema_view
  3. spec = APISpec(
  4.     title="My API",
  5.     version="1.0.0",
  6.     openapi_version="3.0.0",
  7. )
  8. schema_view = get_schema_view(title="My API")
  9. schema = schema_view.get_schema(request=None, public=True)
  10. spec.components.schema('User', schema)
  11. spec.path(path='/users/{user_id}/', operations=schema['paths']['/users/{user_id}/'])
  12. print(spec.to_yaml())

03Advanced features of Apispec

1. Custom generator

Apispec provides a flexible extension mechanism that allows you to customize the generator. You can implement your own generation logic by inheriting and extending the base class provided by Apispec.

  1. from apispec import BasePlugin
  2. class MyPlugin(BasePlugin):
  3.     def path_helper(self, operations, *, resource, **kwargs):
  4.         operations.update({
  5.             'get': {
  6.                 'description''Get a user by ID',
  7.                 'parameters': [
  8.                     {'name''user_id''in''path''required'True'schema': {'type''integer'}}
  9.                 ],
  10.                 'responses': {
  11.                     '200': {
  12.                         'description''A user object',
  13.                         'content': {
  14.                             'application/json': {
  15.                                 'schema': {
  16.                                     'type''object',
  17.                                     'properties': {
  18.                                         'id': {'type''integer'},
  19.                                         'name': {'type''string'}
  20.                                     }
  21.                                 }
  22.                             }
  23.                         }
  24.                     }
  25.                 }
  26.             }
  27.         })
  28. spec = APISpec(
  29.     title="My API",
  30.     version="1.0.0",
  31.     openapi_version="3.0.0",
  32.     plugins=[MyPlugin()],
  33. )

2. Support multiple frameworks

Apispec supports many popular Python frameworks, such as Flask, Django, Falcon, etc. You can choose the appropriate framework and plug-in according to your needs to quickly generate API documentation.

3. Automatically generate interface documentation

Apispec can automatically generate interface documentation based on the documentation string of a function or class, reducing the workload of manual document writing.

  1. def get_user(user_id):
  2.     """
  3.     ---
  4.     get:
  5.       description: Get a user by ID
  6.       parameters:
  7.         - name: user_id
  8.           in: path
  9.           required: true
  10.           schema:
  11.             type: integer
  12.       responses:
  13.         200:
  14.           description: A user object
  15.           content:
  16.             application/json:
  17.               schema:
  18.                 type: object
  19.                 properties:
  20.                   id:
  21.                     type: integer
  22.                   name:
  23.                     type: string
  24.     """
  25.     return {"id": user_id, "name""John Doe"}

4. Integration with third-party tools

Apispec can be integrated with many third-party tools, such as Swagger UI, ReDoc, etc., to provide intuitive interface document display and testing functions.

  1. from flask import Flask, jsonify
  2. from flask_apispec import FlaskApiSpec
  3. app = Flask(__name__)
  4. @app.route('/users/<int:user_id>', methods=['GET'])
  5. def get_user(user_id):
  6.     """
  7.     ---
  8.     get:
  9.       description: Get a user by ID
  10.       parameters:
  11.         - name: user_id
  12.           in: path
  13.           required: true
  14.           schema:
  15.             type: integer
  16.       responses:
  17.         200:
  18.           description: A user object
  19.           content:
  20.             application/json:
  21.               schema:
  22.                 type: object
  23.                 properties:
  24.                   id:
  25.                     type: integer
  26.                   name:
  27.                     type: string
  28.     """
  29.     return jsonify({"id": user_id, "name""John Doe"})
  30. docs = FlaskApiSpec(app)
  31. docs.register(get_user)
  32. if __name__ == '__main__':
  33.     app.run()

04Real-life examples

Build a complete API documentation system

1. Project Introduction

Suppose we have a simple user management system and need to write documentation for its API. Our API includes operations such as adding, deleting, modifying, and querying users, as well as some basic authentication functions.

2. Project Structure

  1. user_management/
  2. ├── app.py
  3. ├── models.py
  4. ├── views.py
  5. ├── serializers.py
  6. └── requirements.txt

3. Install dependencies

Add dependencies to requirements.txt:

  1. Flask
  2. Flask-RESTful
  3. Flask-SQLAlchemy
  4. Flask-Migrate
  5. apispec
  6. flask-apispec

Run the following command to install dependencies:

pip install -r requirements.txt

4. Define the model

Define the user model in models.py:

  1. from flask_sqlalchemy import SQLAlchemy
  2. db = SQLAlchemy()
  3. class User(db.Model):
  4.     id = db.Column(db.Integer, primary_key=True)
  5.     name = db.Column(db.String(80), nullable=False)
  6.     email = db.Column(db.String(120), unique=True, nullable=False)

5. Define views and serialization

Define the user serializer in serializers.py:

  1. from marshmallow import Schema, fields
  2. class UserSchema(Schema):
  3.     id = fields.Int(dump_only=True)
  4.     name = fields.Str(required=True)
  5.     email = fields.Email(required=True)

Define the view in views.py:

  1. from flask import request
  2. from flask_restful import Resource
  3. from models import User, db
  4. from serializers import UserSchema
  5. class UserResource(Resource):
  6.     def get(self, user_id):
  7.         user = User.query.get_or_404(user_id)
  8.         schema = UserSchema()
  9.         return schema.dump(user)
  10.     def post(self):
  11.         schema = UserSchema()
  12.         user = schema.load(request.json)
  13.         db.session.add(user)
  14.         db.session.commit()
  15.         return schema.dump(user), 201
  16.     def put(self, user_id):
  17.         user = User.query.get_or_404(user_id)
  18.         schema = UserSchema(partial=True)
  19.         updated_user = schema.load(request.json, instance=user)
  20.         db.session.commit()
  21.         return schema.dump(updated_user)
  22.     def delete(self, user_id):
  23.         user = User.query.get_or_404(user_id)
  24.         db.session.delete(user)
  25.         db.session.commit()
  26.         return ''204

6. Define the main application

In app.py:

  1. from flask import Flask
  2. from flask_restful import Api
  3. from flask_migrate import Migrate
  4. from models import db
  5. from views import UserResource
  6. from flask_apispec import FlaskApiSpec
  7. from flask_apispec.extension import FlaskApiSpec
  8. app = Flask(__name__)
  9. app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
  10. db.init_app(app)
  11. migrate = Migrate(app, db)
  12. api = Api(app)
  13. api.add_resource(UserResource, '/users/<int:user_id>')
  14. docs = FlaskApiSpec(app)
  15. docs.register(UserResource)
  16. if __name__ == '__main__':
  17.     app.run()

7. Run the application and view the documentation

Run the following command to start the application:

python app.py

Visit http://localhost:5000/swagger/ to view the generated API documentation.

05Best Practices

1. Keep documentation and code in sync

Make sure the documentation is always in sync with the code to avoid inconsistencies between the documentation and the actual API. You can use CI/CD tools to automatically generate and deploy documentation.

2. Using Annotations and Decorators

By using annotations and decorators, you can make the documentation more concise and easier to read. For example, use the @doc decorator of Flask-Apispec to add documentation information to the view function.

3. Define global parameters and responses

For commonly used parameters and responses, you can define global parameters and response templates in Apispec to reduce duplicate code.

  1. spec.components.parameter("user_id""path", schema={"type""integer"}, required=True)
  2. spec.components.response("User", {
  3.     "description""A user object",
  4.     "content": {
  5.         "application/json": {
  6.             "schema": {
  7.                 "type""object",
  8.                 "properties": {
  9.                     "id": {"type""integer"},
  10.                     "name": {"type""string"}
  11.                 }
  12.             }
  13.         }
  14.     }
  15. })

4. Review and update documentation regularly

Regularly review and update documents to ensure their accuracy and completeness. This can be achieved by setting up a document review cycle or introducing a document review process.

For more functions and detailed usage, please refer to the official documentation:

https://apispec.readthedocs.io/en/latest

06summary

Through this article, I believe you have a basic understanding and mastery of Apispec. We have comprehensively introduced how to use Apispec to generate and maintain API documentation, from basic usage to advanced functions, to practical cases and best practices.

I hope you can apply this knowledge to actual projects and add a touch of brilliance to your API.