Wenn Sie einen Typ mit Pythons Own ORM (fsglue) in einem schemenlosen Firestore definieren und mit OpenAPI oder Typescript kombinieren, einer flexiblen, aber typisierten und komfortablen Entwicklungsumgebung Ich habe es geschafft, also habe ich versucht, es einfach zusammenzufassen
Als Hobby entwickle ich die Low-Code-Geschäftsanwendungsplattform Bizglue, und dies ist eine Geschichte hinter den Kulissen. Die Motive für die Entwicklung des Dienstes finden Sie unter Anmerkung. Wenn Sie also interessiert sind, lesen Sie diese bitte auch durch.
Rauer Durchfluss bis zur endgültigen Konfiguration
--AppEngine (Standardumgebung)
Was "weich" ist, ist, dass Firestore selbst im Grunde genommen schemenlos ist, sodass das Hinzufügen von Feldern und abwärtskompatiblen Änderungen einfach durch Ändern der Modelldefinition erfolgen kann (keine mühsame Migrationsverarbeitung erforderlich). .. Es ist ein wenig mühsam, den API-Client manuell zu generieren, aber ich denke, es ist sehr praktisch, den Typ mit Typescript basierend auf der auf der Serverseite definierten Modelldefinition überprüfen zu können.
Ich werde es mit Beispielcode etwas konkreter erklären.
Wenn Sie ein Modell wie dieses definieren
import fsglue
TAGS_SCHEMA = {
"type": "array",
"items": {
"type": "string",
},
}
class User(fsglue.BaseModel):
COLLECTION_PATH = "users"
COLLECTION_PATH_PARAMS = []
name = fsglue.StringProperty(required=True)
tags = fsglue.JsonProperty(schema=TAGS_SCHEMA, default=[])
created_at = fsglue.TimestampProperty(auto_now=True)
updated_at = fsglue.TimestampProperty(auto_now_add=True)
Sie können die folgende JsonSchema-Definition mit "User.to_schema ()" generieren.
{
"type": "object",
"required": [
"name",
"owner"
],
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"created_at": {
"type": "number"
},
"updated_at": {
"type": "number"
}
}
}
Übergeben Sie das Ausführungsergebnis von "User.to_schema ()" an flasgger, damit in der Definition für jeden Endpunkt darauf verwiesen werden kann.
from flasgger import Swagger
from xxx import models #Modelldefinition
from xxx import app #Kolben App
template = {
"swagger": "2.0",
...Unterlassung...
"definitions": {
"User": models.User.to_schema(), #Modell definieren
...Unterlassung...
},
...Unterlassung...
}
swagger = Swagger(app, template=template)
Implementieren Sie beispielsweise eine API, um eine Liste der Benutzer einer bestimmten Organisation mit dem folgenden Bild abzurufen.
from flask import Blueprint
from flasgger.utils import swag_from
app = Blueprint("user", __name__, url_prefix="/api/v1")
@app.route('/organization/<org_id>/user/', methods=['GET'])
@swag_from({
"operationId": "getUserList",
"summary": "getUserList",
"parameters": [
{"name": "org_id", "in": "path", "type": "string", "required": "true"},
],
"responses": {
"200": {
"description": "users",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/User", #Siehe in blinker registrierte Modelle
}
},
}
},
"tags": ["user"],
})
@auth.xxx_required #Autoritätsprüfer Dekorateur
def list_user(org_id, **kwargs):
users = User.all(org_id, to_dict=True)
return jsonify(users)
Sie können openapi-generator installieren und einen API-Client in der Entwicklungsumgebung mit dem folgenden Befehl generieren (diesmal typescript-fetch
) Ich benutze einen Client)
#Holen Sie sich json der OpenAPI-Definition
curl http://localhost:8080/apispec_1.json > ./xxx/apispec.json
# openapi-API-Client mit Generator generieren
./node_modules/.bin/openapi-generator \
generate \
-g typescript-fetch \
-o ./yyy/api/ \
-i ./xxx/apispec.json \
--additional-properties modelPropertyNaming=snake_case \ #Optionen sind Ihre Wahl
--additional-properties supportsES6=true \
--additional-properties typescriptThreePlus=true \
--additional-properties disallowAdditionalPropertiesIfNotPresent=false
Mit dem folgenden Bild können Sie den API-Client verwenden und gleichzeitig vom Typescript-Typ profitieren. (Bei der tatsächlichen Verwendung wird die generierte API über einen Wrapper aufgerufen, anstatt direkt aufgerufen zu werden, um Authentifizierungsinformationen bereitzustellen und eine allgemeine Verarbeitung zu implementieren.)
import { UserApi } from "xxx/UserApi";
const api = new OrganizationApi();
//Im Folgenden arbeiten das API-Argument von getUserList und der Rückgabetyp mit Typescript.
const users = await api.getUserList({ orgId: "test" });
Der openapi-Generator konvertiert die Json-Schemadefinition automatisch in einen TypeScript-Typ, aber es gab einige Stellen, an denen ich den subtilen Juckreiz in den Details nicht erreichen konnte. Es kann nicht geholfen werden, da es in Bezug auf Spezifikationen nicht vollständig kompatibel ist, sondern speziell Abhängigkeiten (#dependencies) wird nicht gut in einen Typ konvertiert, oder enum kann nicht in einen Typescript-Unionstyp konvertiert werden. Dieses Mal habe ich es mitten in der Entwicklung als Open API erstellt. Wenn Sie es also von Anfang an integrieren möchten, ist es möglicherweise besser, es zu erstellen, während Sie den Typ auf der Json-Schemaseite so anpassen, dass sich der Typ auf der Typescript-Seite gut anfühlt.
Es war ein wenig schwierig, eine gemeinsame Verarbeitung (Übergabe eines Tokens beim Aufrufen einer API, Einbeziehung einer gemeinsamen Fehlerbehandlung usw.) in alle APIs zu integrieren. Es scheint praktisch, den generierten API-Client so zu verwenden, wie er ist, aber ich hatte das Gefühl, dass es nicht viele Schnittstellen gibt, um ihn später zu erweitern, und freue mich auf die zukünftige Entwicklung.
Beim Hinzufügen oder Ändern eines Schemas auf der Serverseite zeigt die Typprüfung von Typescript in gewissem Maße den Einfluss der Front-End-Seite, sodass ich der Meinung bin, dass dieser Punkt zu einer Verbesserung der Entwicklungsgeschwindigkeit geführt hat. Das Überprüfen der Konsistenz der Implementierung auf der Serverseite und der Vorderseite ist eine häufige und mühsame Aufgabe, daher ist es schön, dies reduzieren zu können.
Da Firestore selbst schemenlos ist, können Änderungen, die nicht mit vorhandenen Daten in Konflikt stehen, und Änderungen, die sich nicht auf die Indexumgebung auswirken, einfach durch Ändern der Modelldefinition entwickelt werden, sodass Sie von der schemenlosen Typprüfung von Firestore profitieren können Ich halte es für einen guten Mechanismus, durch den Sie auch von der Früherkennung von Fehlern profitieren können. (Ich denke nicht, dass es für eine groß angelegte Entwicklung geeignet ist, aber in diesem Fall habe ich überhaupt keine Lust, Firestore zu verwenden.)
Ich habe es diesmal nicht viel benutzt, aber es wird möglich sein, das von OpenAPI gepflegte Ökosystem zu nutzen. Wenn es also gut integriert ist, scheint es auch die folgenden Verwendungsmethoden zu geben.
Ich persönlich entwickle einen Dienst namens Entwicklungsplattform für Low-Code-Anwendungen Bizglue. Bitte benutzen Sie es!
Recommended Posts