2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Table of contents
Installation and Configuration
Generate simple API documentation
2. Define API routes and views
1. Install Flask and Flask-Apispec
Integrating Django and Apispec
1. Install Django and Django-Rest-Framework
2. Create a Django project and application
3. Configure the Django project
6. Generate OpenAPI specification
03Advanced features of Apispec
2. Support multiple frameworks
3. Automatically generate interface documentation
4. Integration with third-party tools
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.
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.
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.
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
Let's look at the basic usage of Apispec through a few simple examples.
- from apispec import APISpec
-
- spec = APISpec(
- title="My API",
- version="1.0.0",
- openapi_version="3.0.0",
- info=dict(description="This is a sample API"),
- )
- def get_user(user_id):
- """
- ---
- get:
- description: Get a user by ID
- parameters:
- - name: user_id
- in: path
- required: true
- schema:
- type: integer
- responses:
- 200:
- description: A user object
- content:
- application/json:
- schema:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- """
- return {"id": user_id, "name": "John Doe"}
- spec.path(
- path="/users/{user_id}",
- operations=dict(
- get=dict(
- description="Get a user by ID",
- parameters=[
- {
- "name": "user_id",
- "in": "path",
- "required": True,
- "schema": {"type": "integer"},
- }
- ],
- responses={
- "200": {
- "description": "A user object",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "id": {"type": "integer"},
- "name": {"type": "string"},
- },
- }
- }
- },
- }
- },
- )
- ),
- )
pip install Flask Flask-Apispec
- from flask import Flask, jsonify
- from flask_apispec import FlaskApiSpec, doc, marshal_with
- from flask_apispec.views import MethodResource
- from marshmallow import Schema, fields
-
- app = Flask(__name__)
-
- class UserSchema(Schema):
- id = fields.Int()
- name = fields.Str()
-
- class UserResource(MethodResource):
- @doc(description='Get a user by ID', tags=['User'])
- @marshal_with(UserSchema)
- def get(self, user_id):
- return {"id": user_id, "name": "John Doe"}
-
- app.add_url_rule('/users/<int:user_id>', view_func=UserResource.as_view('user_resource'))
- docs = FlaskApiSpec(app)
- docs.register(UserResource)
-
- @app.route('/swagger/')
- def swagger_ui():
- return jsonify(docs.spec.to_dict())
-
- if __name__ == '__main__':
- app.run()
pip install django djangorestframework
- django-admin startproject myproject
- cd myproject
- django-admin startapp myapp
Add rest_framework and apispec in settings.py:
- INSTALLED_APPS = [
- ...
- 'rest_framework',
- 'myapp',
- 'apispec',
- ]
In myapp/views.py:
- from rest_framework.views import APIView
- from rest_framework.response import Response
- from rest_framework.schemas import AutoSchema
-
- class UserView(APIView):
- schema = AutoSchema(
- manual_fields=[
- coreapi.Field('user_id', required=True, location='path', schema={'type': 'integer'})
- ]
- )
-
- def get(self, request, user_id):
- """
- Get a user by ID.
- ---
- responses:
- 200:
- description: A user object
- content:
- application/json:
- schema:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- """
- return Response({"id": user_id, "name": "John Doe"})
In myapp/urls.py:
- from django.urls import path
- from .views import UserView
-
- urlpatterns = [
- path('users/<int:user_id>/', UserView.as_view(), name='user-view'),
- ]
In manage.py:
- from apispec import APISpec
- from rest_framework.schemas import get_schema_view
-
- spec = APISpec(
- title="My API",
- version="1.0.0",
- openapi_version="3.0.0",
- )
-
- schema_view = get_schema_view(title="My API")
- schema = schema_view.get_schema(request=None, public=True)
- spec.components.schema('User', schema)
- spec.path(path='/users/{user_id}/', operations=schema['paths']['/users/{user_id}/'])
-
- print(spec.to_yaml())
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.
- from apispec import BasePlugin
-
- class MyPlugin(BasePlugin):
- def path_helper(self, operations, *, resource, **kwargs):
- operations.update({
- 'get': {
- 'description': 'Get a user by ID',
- 'parameters': [
- {'name': 'user_id', 'in': 'path', 'required': True, 'schema': {'type': 'integer'}}
- ],
- 'responses': {
- '200': {
- 'description': 'A user object',
- 'content': {
- 'application/json': {
- 'schema': {
- 'type': 'object',
- 'properties': {
- 'id': {'type': 'integer'},
- 'name': {'type': 'string'}
- }
- }
- }
- }
- }
- }
- }
- })
-
- spec = APISpec(
- title="My API",
- version="1.0.0",
- openapi_version="3.0.0",
- plugins=[MyPlugin()],
- )
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.
Apispec can automatically generate interface documentation based on the documentation string of a function or class, reducing the workload of manual document writing.
- def get_user(user_id):
- """
- ---
- get:
- description: Get a user by ID
- parameters:
- - name: user_id
- in: path
- required: true
- schema:
- type: integer
- responses:
- 200:
- description: A user object
- content:
- application/json:
- schema:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- """
- return {"id": user_id, "name": "John Doe"}
Apispec can be integrated with many third-party tools, such as Swagger UI, ReDoc, etc., to provide intuitive interface document display and testing functions.
- from flask import Flask, jsonify
- from flask_apispec import FlaskApiSpec
-
- app = Flask(__name__)
-
- @app.route('/users/<int:user_id>', methods=['GET'])
- def get_user(user_id):
- """
- ---
- get:
- description: Get a user by ID
- parameters:
- - name: user_id
- in: path
- required: true
- schema:
- type: integer
- responses:
- 200:
- description: A user object
- content:
- application/json:
- schema:
- type: object
- properties:
- id:
- type: integer
- name:
- type: string
- """
- return jsonify({"id": user_id, "name": "John Doe"})
-
- docs = FlaskApiSpec(app)
- docs.register(get_user)
-
- if __name__ == '__main__':
- app.run()
Build a complete API documentation system
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.
- user_management/
- ├── app.py
- ├── models.py
- ├── views.py
- ├── serializers.py
- └── requirements.txt
Add dependencies to requirements.txt:
- Flask
- Flask-RESTful
- Flask-SQLAlchemy
- Flask-Migrate
- apispec
- flask-apispec
Run the following command to install dependencies:
pip install -r requirements.txt
Define the user model in models.py:
- from flask_sqlalchemy import SQLAlchemy
-
- db = SQLAlchemy()
-
- class User(db.Model):
- id = db.Column(db.Integer, primary_key=True)
- name = db.Column(db.String(80), nullable=False)
- email = db.Column(db.String(120), unique=True, nullable=False)
Define the user serializer in serializers.py:
- from marshmallow import Schema, fields
-
- class UserSchema(Schema):
- id = fields.Int(dump_only=True)
- name = fields.Str(required=True)
- email = fields.Email(required=True)
-
Define the view in views.py:
- from flask import request
- from flask_restful import Resource
- from models import User, db
- from serializers import UserSchema
-
- class UserResource(Resource):
- def get(self, user_id):
- user = User.query.get_or_404(user_id)
- schema = UserSchema()
- return schema.dump(user)
-
- def post(self):
- schema = UserSchema()
- user = schema.load(request.json)
- db.session.add(user)
- db.session.commit()
- return schema.dump(user), 201
-
- def put(self, user_id):
- user = User.query.get_or_404(user_id)
- schema = UserSchema(partial=True)
- updated_user = schema.load(request.json, instance=user)
- db.session.commit()
- return schema.dump(updated_user)
-
- def delete(self, user_id):
- user = User.query.get_or_404(user_id)
- db.session.delete(user)
- db.session.commit()
- return '', 204
In app.py:
- from flask import Flask
- from flask_restful import Api
- from flask_migrate import Migrate
- from models import db
- from views import UserResource
- from flask_apispec import FlaskApiSpec
- from flask_apispec.extension import FlaskApiSpec
-
- app = Flask(__name__)
- app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
- db.init_app(app)
- migrate = Migrate(app, db)
- api = Api(app)
-
- api.add_resource(UserResource, '/users/<int:user_id>')
-
- docs = FlaskApiSpec(app)
- docs.register(UserResource)
-
- if __name__ == '__main__':
- app.run()
Run the following command to start the application:
python app.py
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.
- spec.components.parameter("user_id", "path", schema={"type": "integer"}, required=True)
- spec.components.response("User", {
- "description": "A user object",
- "content": {
- "application/json": {
- "schema": {
- "type": "object",
- "properties": {
- "id": {"type": "integer"},
- "name": {"type": "string"}
- }
- }
- }
- }
- })
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
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.