[PYTHON] Schemagesteuerte Entwicklung mit Responder: Versuchen Sie, die Swagger-Benutzeroberfläche anzuzeigen

Was ist schemagesteuerte Entwicklung?

Einfach ausgedrückt handelt es sich um eine Entwicklungsmethode, bei der zuerst das API-Schema (Definition von Anforderungs- und Antworttypen sowie Feldnamen) ermittelt wird und die Dokumentation und das Modell systematisch zusammen mit dieser generiert werden. Anschließend wird die interne Implementierung durchgeführt. (Referenz: Erläuterung und Implementierungsbeispiel für eine schemagesteuerte Entwicklung zur Optimierung der Team-Web-API-Entwicklung)

Ich möchte eine schemagesteuerte Entwicklung mit Responder durchführen, einem Webframework von Python.

Das Ziel ist es, den folgenden Swagger sehen zu können. ezgif-1-4c611adeacb7.gif

responder Ein modernes Webframework für Python. In Bezug auf das Volumen handelt es sich um ein Mikroframework wie eine Flasche oder eine Flasche. Schreiben Sie einfach Folgendes und führen Sie es wie `` $ python xxx.py``` aus, um den API-Server zu starten, der JSON zurückgibt.

import responder

api = responder.API()

@api.route("/")
async def view(req, resp):
    resp.media = {'success': True}

if __name__ == "__main__":
    api.run()

Es ist auch bemerkenswert, dass es über moderne Funktionen wie ASGI (Asynchronous Web Server), Websocket, GraphQL und die automatische Generierung von OpenAPI-Schemas verfügt. Ungefähr ein Jahr nach seiner Veröffentlichung ist es ein Monster mit mehr als 3300 Sternen auf Github (Stand November 2019), und die Häufigkeit von Commits ist hoch, daher denke ich, dass es eine gute Zukunft hat.

Referenz:

Umfang dieses Artikels

Die folgenden Entwicklungsmethoden im Responder sind zusammengefasst.

  1. Schemadefinition & Verspottung: (Serialisierung durch Mashmallow)
  2. Mock & Dokumentation zur Verfügung gestellt: (Konvertierung zu OpenAPI 3.0 (Prahlerei) von apispec)

Entspricht dem Kapitel über die Unterstützung offener API-Schemas und die interaktive Dokumentation in der Feature-Tour des Responders (https://responder.readthedocs.io/en/latest/tour.html#openapi-schema-support), ist jedoch bescheiden Da es nur eine Einführung gibt, hätte ich gerne eine praktische Erklärung.

Verfassung

Zur Erläuterung erstellen wir die folgende einfache API.

method Funktion
get Gibt alle vorhandenen IDs zurück
post Gibt zurück, ob die eingegebene ID vorhanden ist

Wenn in der Post ein Validierungsfehler auftritt, wird der Fehlerinhalt zurückgegeben.

version responder: v2.0.3 python: v3.6.5

Schemadefinition & Mock-Erstellung durch Marshmallow

mashmallow ist eine Bibliothek, die die Serialisierung von Objekten unterstützt. Wenn Sie eine Schemaklasse definieren und eine Anforderung oder Antwort über die Schemaklasse laden / sichern, wird die Validierung angewendet. Der Fluss ist wie folgt.

from marshmallow import Schema, fields

class AllIdRespSchema(Schema):
    #Schemadefinition(int Liste)
    exist_ids = fields.List(fields.Int())

class AllExistIDModel():
    #Antwort verspotten
    #Ersetzen Sie diesen Inhalt für die spätere Produktion
    def __init__(self):
        self.exist_ids = [1, 2, 3, 4, 5]

@api.route("/schema_driven")
async def schema_driven_view(req, resp):
    if req.method == "get":
        # validate response data
        resp.media = AllIdRespSchema().dump(AllExistIDModel())

Nach diesem Ablauf werden die für dieses Beispiel erforderliche Schema-Klasse und Mock-Klasse wie folgt definiert. AllIdRespSchema, AllExistIDModel sind im obigen Beispiel definiert.

Schemaname mock Verwenden
AllIdRespSchema AllExistIDModel erhalten Antwort
IdReqSchema Keiner Post Anfrage
IsExistRespSchema IsExistIDModel Antwort nach der Antwort
ErrorRespSchema ErrorModel Antwort auf Validierungsfehler
class IdReqSchema(Schema):
    # if required=True, the field must exist
    id = fields.Int(required=True)

class IsExistRespSchema(Schema):
    is_exist = fields.Bool()

class ErrorRespSchema(Schema):
    error = fields.Str()
    errorDate = fields.Date()
class IsExistIDModel():
    def __init__(self, data):
        id = data.get('id')
        self.is_exist = id in [1, 2, 3, 4, 5]

class ErrorModel():
    def __init__(self, error):
        self.error = str(error)
        self.errorDate = datetime.datetime.now()

Wenn Sie Schema auf diese Weise definieren, müssen Sie nur den Prozessablauf für die Ansicht schreiben.

from marshmallow import ValidationError

@api.route("/schema_driven")
async def schema_driven_view(req, resp):
    if req.method == "get":
        # validate response data
        resp.media = AllIdRespSchema().dump(AllExistIDModel())

    elif req.method == "post":
        request = await req.media()
        try:
            # validate request data using Schema
            data = IdReqSchema().load(request)

        except ValidationError as error:
            # raise ValidationError
            resp.status_code = api.status_codes.HTTP_400
            # validate response data
            resp.media = ErrorRespSchema().dump(ErrorModel(error))
            return

        # validate response data
        resp.media = IsExistRespSchema().dump(IsExistIDModel(data))

Wie Sie sehen können, wird der Inhalt der Ansicht nur mit dem abstrakten Verarbeitungsablauf und dem Klassennamen für Schema-Klasse und Mock geschrieben. Daher denke ich, dass der Inhalt der Ansicht mit einer kleinen Änderung (Änderung des Typs oder des Feldnamens von json) nicht geändert wird.

Als nächstes möchte ich aus diesem Schema ein Dokument generieren, damit ich Feedback erhalten kann.

Mock & Dokument von apispec zur Verfügung gestellt

Ab hier verwenden wir die Responderfunktion. Es ist jedoch tatsächlich ein Wrapper für eine Bibliothek namens Apispec. Wir lassen nur die Dokumentzeichenfolge und die Schemadefinitionen fast so wie sie sind in die Apispec fließen. Wenn Sie es also im Detail anpassen möchten, müssen Sie sich auf die Definition von Apispec und OpenAPI 3.0 beziehen.

apispec analysiert die Schema-Definition und die Dokumentzeichenfolgen von Marshmallow, wandelt sie in das Open API-Format um und generiert eine Swagger-Benutzeroberfläche.

Referenz:

Zunächst müssen Sie ein Argument hinzufügen, wie unten gezeigt, wenn Sie eine API deklarieren.

api = responder.API(
    openapi='3.0.0',  # OpenAPI version
    docs_route='/docs',  # endpoint for interactive documentation by swagger UI. if None, this is not available.
)

Schema Verwenden Sie als Nächstes den Dekorator api.schema, um die Schemadefinition festzulegen. Das Schreiben der Schemadefinition in der Hauptansicht scheint jedoch zu kompliziert zu sein, daher möchte ich die Schemadefinition aus einer anderen Datei importieren. Also werde ich es gewaltsam wie folgt erklären.

api.schema("IdReqSchema")(IdReqSchema)
api.schema("ErrorRespSchema")(ErrorRespSchema)
api.schema("IsExistRespSchema")(IsExistRespSchema)
api.schema("AllIdRespSchema")(AllIdRespSchema)

Wenn Sie den Server starten und auf Folgendes zugreifen, können Sie die Schemadefinition in der Swagger-Benutzeroberfläche wie unten gezeigt überprüfen. 127.0.0.1:5042/docs

ezgif-1-31f99e6a7002.gif

API GET Fügen Sie der obigen Ansichtsdefinition einen Dokumentstring im Yaml-Format hinzu, wie unten gezeigt. Sie können die API in der Beschreibung beschreiben. Sie können auch das Antwortschema für jeden Statuscode angeben. Wenn Sie das Schema wie folgt definieren, können Sie auf die Schemadefinition der Antwort und die Beispielantwort von der Swagger-Benutzeroberfläche verweisen. Da Sie beim Verweisen auf die Beispielantwort tatsächlich auf die API zugreifen, können Sie auch überprüfen, ob ein interner Serverfehler auftritt.

@api.route("/schema_driven")
async def schema_driven_view(req, resp):
    """exist id checker endpoint.
    ---
    name: is_exist
    get:
        description: Get the all exist id
        responses:
            200:
                description: All exist_id to be returned
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/AllIdRespSchema"
    """
    ...

Wenn Sie Swagger aktivieren,

ezgif-1-4c611adeacb7.gif

POST Fügen Sie außerdem eine Dokumentzeichenfolge für den Beitrag hinzu. Dies ist in der offiziellen Dokumentation nicht aufgeführt. Weitere Informationen finden Sie unter Open API Definition.

Sie können die Antwort auf die gleiche Weise wie get schreiben. Schreiben wir zwei Statuscodes, 200 (normal) und 400 (Validierungsfehler). Geben Sie außerdem das Anforderungsschema in requestBody an. Sie können den Hauptteil der Anforderung ändern und tatsächlich die API aufrufen.

@api.route("/schema_driven")
async def schema_driven_view(req, resp):
    """exist id checker endpoint.
    ...
    ---
    post:
        description: Check the id exists or not
        requestBody:
            content:
                appliation/json:
                    schema:
                        $ref: "#/components/schemas/IdReqSchema"
        responses:
            200:
                description: true/false whether id exists to be returned
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/IsExistRespSchema"
            400:
                description: validation error
                content:
                    application/json:
                        schema:
                            $ref: "#/components/schemas/ErrorRespSchema"
    """

ezgif-1-396279e5f7b8.gif

Zusammenfassung

Einführung des Verfahrens zur schemagesteuerten Entwicklung mit Responder. Ich bin sehr dankbar, dass Swagger allein damit zu sehen ist. Außerdem hat der Responder viele sehr interessante Funktionen, daher möchte ich verschiedene Dinge ausprobieren!

refs

Recommended Posts

Schemagesteuerte Entwicklung mit Responder: Versuchen Sie, die Swagger-Benutzeroberfläche anzuzeigen
Versuchen Sie, den Boden durch Rekursion herauszufordern
Versuchen Sie, verschiedene Informationen anzuzeigen, die für das Debuggen mit Python nützlich sind
Versuchen Sie, sich mit ONNX Runtime zu profilieren
Versuchen Sie, Google Map und Geography Map mit Python anzuzeigen
Versuchen Sie, Audio mit M5 STACK auszugeben
Versuchen Sie, Farbfilme mit Python zu reproduzieren
Versuchen Sie, sich mit Python bei qiita anzumelden
Beispielskript zum Anzeigen von BoundingBox mit PIL
So zeigen Sie Python-Japanisch mit Lolipop an
Versuchen Sie, Kirschblüten mit xg Boost vorherzusagen
Versuchen Sie, mit Pandas in ordentliche Daten umzuwandeln
Versuchen Sie schnell, Ihren Datensatz mit Pandas zu visualisieren
Erster Versuch von YDK mit Cisco IOS-XE
Beispielprogramm zum Anzeigen von Videos mit PyQt
Versuchen Sie, ein Bild mit Entfremdung zu erzeugen
Versuchen Sie, Ihr eigenes AWS-SDK mit bash zu erstellen
Versuchen Sie, das Fizzbuzz-Problem mit Keras zu lösen
Versuchen Sie, das Mensch-Maschine-Diagramm mit Python zu lösen
Versuchen Sie, das Dokument der Azure-Dokumentdatenbank mit pydocumentdb zu extrahieren
Versuchen Sie, mit Python eine Lebenskurve zu zeichnen
Ich möchte mehrere Bilder mit matplotlib anzeigen.
So testen Sie den Friends-of-Friends-Algorithmus mit pyfof
Versuchen Sie, in Python einen "Entschlüsselungs" -Code zu erstellen
Versuchen Sie, Python-Dokumente automatisch mit Sphinx zu generieren
So zeigen Sie Bilder kontinuierlich mit matplotlib Memo an
Versuchen Sie, mit Python eine Diedergruppe zu bilden
Versuchen Sie, Client-FTP mit Pythonista am schnellsten zu machen
Versuchen Sie, Fische mit Python + OpenCV2.4 (unvollendet) zu erkennen.