
Teilen Sie:
Liz Acosta ist Developer Advocate bei Vonage. Ihr Karriereweg von der Filmstudentin über die Marketingspezialistin und die Ingenieurin zur Developer Advocate mag zwar unkonventionell erscheinen, ist aber ziemlich typisch für Developer Relations! Liz liebt Pizza, Pflanzen, Möpse und Python.
Auf der Suche nach Validierung: Datenvalidierung in Python mit Pydantic und Vonage Verify
Lesedauer: 15 Minuten
Dieser Blogbeitrag bietet eine Einführung in Pydantic, die beliebte Bibliothek zur Datenvalidierung für Python. Er enthält eine Demonstration der Vorteile, die Pydantic in Verbindung mit der Vonage Verify API bietet.
Einführung
Was ist „Duck-Typing“ in Python?
Um zu verstehen, warum Pydantic eine so nützliche Bibliothek ist, muss man zunächst verstehen, wie Typisierung in Python funktioniert. In der Programmierung bezieht sich „Typisierung“ auf Systeme zur Klassifizierung und Kategorisierung von Daten. Wie Daten typisiert sind, bestimmt, wie mit ihnen umgegangen werden kann – zum Beispiel kann man das Wort „two“ nicht mit der Zahl 2 addieren.
Python verdankt einen Großteil seines Erfolgs und seiner Beliebtheit seiner Flexibilität in Bezug auf die Typisierung. Im Gegensatz zu den meisten kompilierten Sprachen, bei denen Typen explizit deklariert werden müssen, setzt Python das sogenannte Duck-Typing. Duck-Typing ist ein dynamisches Typsystem, das davon ausgeht: „Wenn ein Objekt wie eine Ente läuft und wie eine Ente quakt, dann muss es eine Ente sein.“
Genauer gesagt, laut der Python-Dokumentationist Duck-Typing:
„Ein Programmierstil, bei dem nicht der Typ eines Objekts geprüft wird, um festzustellen, ob es über die richtige Schnittstelle verfügt; stattdessen wird die Methode oder das Attribut einfach aufgerufen bzw. verwendet … Durch die Betonung von Schnittstellen anstelle spezifischer Typen erhöht gut gestalteter Code seine Flexibilität, indem er polymorphe Substitution ermöglicht. Duck-Typing vermeidet Prüfungen mithilfe von
type()oderisinstance().“
Ein Beispiel hierfür ist in der Praxis die Python-Funktion len Funktion. len() gibt „die Länge (die Anzahl der Elemente) eines Objekts.“ Beachten Sie im folgenden Code, wie len() erfolgreich eine Ausgabe erzeugt, unabhängig vom Typ des Objekts, mit dem sie aufgerufen wird:
>>> example_1 = "Hello? World!"
>>> type(example_1)
<class 'str'>
>>> example_2 = [1, 3, 5, 8]
>>> type(example_2)
<class 'list'>
>>> example_3 = {"hello" : "world", "foo": "bar"}
>>> type(example_3)
<class 'dict'>
>>> len(example_1)
13 # 13 letters in "Hello? World!"
>>> len(example_2)
4 # 4 items in the list
>>> len(example_3)
2 # 2 key-value pairs in the dictionary
In einem Beispiel für dynamische Typisierung, das eher dem entspricht, was man in Python in der Praxis antrifft, definiert der folgende Code drei verschiedene Klassen von Hunderassen, die jeweils bark():
class Pug:
def bark(self):
print("The pug goes arf arf!")
class LabradorRetriever:
def bark(self):
print("The labrador retriever goes arf arf!")
class Wolfhound:
def bark(self):
print("The wolfhound goes arf arf!")Man kann jeweils ein Exemplar jeder Hunderasse instanziieren und bark() die Schnittstelle bei jedem einzelnen davon fehlerfrei aufrufen, da sie alle dieselbe Schnittstelle. Dank Duck-Typing wird der folgende Code erfolgreich ausgeführt:
>>> pets = [Pug(), LabradorRetriever(), Wolfhound()]
>>> for pet in pets:
... pet.bark()
The pug goes arf arf!
The labrador retriever goes arf arf!
The wolfhound goes arf arf!pet kann von der Klasse Pug, LabradorRetrieveroder Wolfhound und Python ruft die bark Funktion ohne Fehler aufrufen.
Das kann praktisch sein, und in vielen Zusammenhängen ist es genau das, was man will. Für Skripting, Data Science und explorative Arbeiten ist die dynamische Typisierung von Python ein Vorteil und kein Nachteil. Dank des Duck-Typing können Sie schnell iterieren, ohne den Aufwand starrer Typdeklarationen. Dies ist ein wesentlicher Grund dafür, dass sich Python zur dominierenden Sprache für KI- und Data-Science-Workflows entwickelt hat.
Im Backend-Code der Produktion sieht die Lage jedoch ganz anders aus. Eine Flask- oder Django-Application ohne deklarierte Typen kann zu Schwierigkeiten bei der Wartung und Fehlersuche führen. Durch das „Duck-Typing“ in Python treten Typkonflikte als kryptische Laufzeitfehler auf, anstatt als klare, frühzeitig erkennbare Fehler. Das Problem verschärft sich noch weiter, wenn Applications auf bestimmte Datentypen angewiesen sind, um wie vorgesehen zu funktionieren – beispielsweise bei der Arbeit mit APIs, der Verarbeitung von Konfigurationsdateien oder der Verarbeitung von Benutzereingaben.
Wenn Sie beispielsweise die folgende Klasse definiert haben:
class Sphynx:
def meow(self):
print("The sphynx goes meow meow!")Anschließend habe ich den Beispielcode aktualisiert und eine Instanz von Sphynx in die Liste der pets , durch die Sie iterieren möchten, erhalten Sie folgende Fehlermeldung:
>>> pets = [Pug(), LabradorRetriever(), Sphynx()]
>>> for pet in pets:
... pet.bark()
...
The pug goes arf arf!
The labrador retriever goes arf arf!
Traceback (most recent call last):
File "<python-input-74>", line 2, in <module>
pet.bark()
^^^^^^^^
AttributeError: 'Sphynx' object has no attribute 'bark'Wie dieses Beispiel verdeutlicht, kann die Flexibilität des Duck-Typing in bestimmten Kontexten zum Nachteil werden. So kann es beispielsweise vorkommen, dass ein falscher Typ, der an einen API-Aufruf übergeben wird, erst dann zu einem Fehler führt, wenn die Anfrage bereits in Bearbeitung ist – was Ihnen möglicherweise Kosten für einen kostenpflichtigen Aufruf verursacht, der von vornherein zum Scheitern verurteilt war.
Eine Möglichkeit, einige der Probleme anzugehen, die bei der dynamischen Typisierung auftreten, sind die Typangaben.
Was sind Typangaben?
Ein Typ-Hinweis ist eine Code-Annotation, die „den erwarteten Typ für eine Variable, ein Klassenattribut, einen Funktionsparameter oder einen Rückgabewert angibt.“ Daher ist eine Typ-Annotation bezieht sich darauf, wie Typhinweise in Python syntaktisch verwendet werden.
Der folgende Code ist ein einfaches Beispiel für die Verwendung von Typangaben:
def greeting(name: str) -> str:
return 'Hello ' + nameIn diesem Beispiel lautet der Typ-Hinweis str und die Typ-Annotation lautet name: str und -> str Syntax. Die Typannotation gibt an, dass der erwartete Typ des Parameters name eine Zeichenkette ist und dass der erwartete Rückgabetyp der Funktion greeting eine Zeichenkette ist.
Das Hinzufügen von Typangaben zur Beispielklasse Pug Klasse könnte wie folgt aussehen:
class Pug:
def init(self, name: str) -> None:
self.name: str = name
def bark(self) -> None:
print(f"The pug {self.name} goes arf arf!")Und wenn wir unseren pets Iterationscode so anpassen, dass er Typangaben enthält, könnte er wie folgt aussehen:
def make_dogs_bark(pets: List[Pug | LabradorRetriever | Wolfhound ]) -> None:
for pet in pets:
pet.bark()
make_dogs_bark([Pug(), LabradorRetriever(), Sphynx()])Wie der Name schon sagt, handelt es sich hierbei lediglich um Hinweise. Sie tragen dazu bei, den Code lesbarer und wartbarer zu machen, werden jedoch vom Python-Interpreter nicht erzwungen. Wir könnten ein zusätzliches Tool wie mypy verwenden, um die Typen zu überprüfen, und würden dann eine Fehlermeldung wie diese erhalten:
error: List item 2 has incompatible type "Sphynx"; expected "Pug | LabradorRetriever | Wolfhound" [list-item]Dies müsste als zusätzlicher Schritt durchgeführt werden – nichts hindert diesen Code daran, zur Laufzeit ausgeführt zu werden und einen Fehler zu erzeugen.
Auf der Suche nach Bestätigung
Um Fehler zur Laufzeit zu vermeiden – wie beispielsweise einen API-Aufruf mit falschen Daten – könnten Sie die die Daten in Ihrer Anfrage , bevor sie zu senden. Im Beispielcode könnten wir eine Art Validierung definieren, um sicherzustellen, dass jedes Element in der Liste pets kann bark():
def make_dogs_bark_safely(dogs):
"""Manual validation in the function"""
for dog in dogs:
if not hasattr(dog, 'bark') or not callable(getattr(dog, 'bark')):
raise TypeError(f"Invalid dog type: {type(dog).__name__}")
dog.bark()
# Now this fails immediately with a clear message:
pets = [Pug(), Sphynx()]
make_dogs_bark_safely(pets)
# TypeError: Invalid dog type: SphynxDieses Muster wird nicht nur schnell mühsam und unhandlich, sondern untergräbt auch einige der Vorteile der Python-eigenen dynamischen Typisierung und lässt gleichzeitig einige der Vorzüge der Typangabe außer Acht.
Glücklicherweise, bietet Pydantic bietet Datenvalidierung und bewahrt dabei die Einfachheit und Schnelligkeit der Sprache, indem es bereits integrierte Syntax verwendet.
Was ist Pydantic?
Pydantic ist eine Bibliothek zur Datenvalidierung für Python, die folgende Vorteile bietet:
Nutzungsgrade Typ-Hinweise zur die Schemavalidierung und Serialisierung.
Verwendungszwecke Verwendet Rust im Hintergrund für seine zentrale Validierungslogik, was zu minimalen Auswirkungen auf die Leistung führt.
Unterstützt die Validierung vieler Typen der Standardbibliothek einschließlich
dataclassundTypedDict.Funktioniert sowohl im striktem oder laxem Modus bei der Behandlung von Typen.
Kann Folgendes ausgeben JSON-Schema von Haus aus ausgeben, was eine nahtlose Integration mit anderen Tools ermöglicht.
Erstellt automatisch Dokumentation aus Modellen.
Schauen wir uns einmal genauer an, wie diese Funktionen in der Praxis zusammenwirken, um eine zuverlässige und effiziente Datenvalidierung zu gewährleisten, die sich nahtlos in die Syntax und Struktur von Python einfügt.
Kernfunktionen zur Validierung in Pydantic
Es ist wichtig zu verstehen, dass sich der Begriff „Validierung“ in Pydantic auf „den Prozess der Instanziierung eines Modells (oder eines anderen Typs), das den festgelegten Typen und Einschränkungen entspricht“. Mit anderen Worten: Die Validierung in Pydantic bezieht sich auf das Ergebnis einer Modellinstanziierung, nicht auf die Eingabedaten. Daher löst Pydantic eine ValidationError aus, wenn Daten nicht erfolgreich in eine Instanz eines Modells geparst werden können.
Basismodell
BaseModel bildet das Herzstück von Pydantic. Man erbt von dieser Klasse, um Datenmodelle mit typangekennigten Feldern zu definieren. Eine der wichtigsten Methoden zur Definition von Schemata in Pydantic ist die Verwendung von Modellen. Wenn man eine Instanz von BaseModel Pydantic die Daten automatisch anhand des definierten Schemas.
Mit Pydantic sieht die Pug Klasse sieht nun wie folgt aus:
class Pug(BaseModel):
name: str
age: int
color: str = "fawn"
def bark(self):
print(f"The pug {self.name} goes arf arf!")Wenn Sie Pug, würde Pydantic sicherstellen, dass das resultierende Objekt einen name vom Typ „string“, ein age vom Typ „Integer“ sowie ein color vom Typ „string“ mit fawn als Standardwert.
Typhinweise und Pflichtfelder
Typangaben steuern die Schemavalidierung und die Serialisierung. Felder, die lediglich mit einer Typangabe deklariert sind, sind obligatorisch; Felder mit Standardwerten sind optional.
Im Pug Beispiel wird das name Feld ist mit str , was bedeutet, dass jede beliebige Zeichenkette ausreicht, aber eine Zeichenkette angeben angegeben werden; dasselbe gilt für das age Feld. Das color Feld stellt jedoch einen Standardwert von fawn und ist daher bei der Instanziierung eines Pug.
Typumwandlung
Pydantic kann entweder im strengen oder im standardmäßigen lockeren Modus verwendet werden. Im lockeren Modus wandelt die Bibliothek Daten automatisch in den im Schema definierten Typ um.
Wenn wir also beispielsweise "5" als Zeichenkette für die age eines Pug, würde Pydantic diese in eine Ganzzahl umwandeln.
Feldkonfiguration
Die Field Funktion ermöglicht das Hinzufügen von Metadaten und Einschränkungen für Schemafelder.
Einige häufig verwendete Parameter sind:
Einschränkungen wie beispielsweise größer als
gt) und größer als oder gleichge) sowiemin_lengthundmax_lengthAliase zur Zuordnung von Namen von Eingabe- und Ausgabefeldern mithilfe von
alias,validation_alias, undserialization_alias)Strikter Modus um Typumwandlungen bei bestimmten Feldern zu verhindern
strict=True)
Um die Einschränkungen für das name Feld für Pug, würden Sie den folgenden Code verwenden:
class Pug(BaseModel):
name: str = Field(..., min_length=1, description="The pug's name")
age: int
color: str = "fawn"
def bark(self):
print(f"The pug {self.name} goes arf arf!") Serialisierung
Pydantic-Modellinstanzen lassen sich mithilfe von model_dump(). Dadurch lässt sich die Serialisierung in JSON oder andere Formate zur Verwendung an anderer Stelle im Projekt ganz einfach durchführen. Beispielsweise model_dump_json() serialisiert ein Modell direkt in JSON.
Im Folgenden finden Sie ein Beispiel für die Erstellung einer Instanz von Pug und deren anschließender Serialisierung mithilfe einer der integrierten Funktionen von Pydantic:
matty_pug = Pug(name="Matty", age=14)
result = matty_pug.model_dump()
print(result)Dies würde folgende Ausgabe ergeben:
{'name': 'Matty', 'age': 14, 'color': fawn} Was ist ein Anwendungsbeispiel aus der Praxis für Pydantic?
Seit seiner Einführung hat sich Pydantic schnell zu einer der am häufigsten verwendeten Bibliotheken zur Datenvalidierung für Python entwickelt. Rund 8.000 Pakete auf PyPI nutzen Pydantic, darunter (und vor allem) FastAPI, huggingface, Django Ninja, SQLModel, LangChain und Vonage.
Im November 2024 veröffentlichte Vonage eine von Grund auf neu geschriebene Version des Vonage-Python-SDK veröffentlicht. Es ist nicht immer einfach, ganz von vorne anzufangen, aber die Neuprogrammierung bot die Gelegenheit, einige entscheidende strukturelle Verbesserungen vorzunehmen und die Benutzerinteraktion mit dem SDK zu optimieren.
Zu den Änderungen, die im Rahmen dieser Initiative vorgenommen wurden, gehörte unter anderem die Integration von Pydantic in das SDK, um den Aufruf von Vonage-APIs und die Auswertung der Antworten zu vereinfachen.
Sehen Sie sich das folgende Video an, um zu erfahren, was einer unserer Entwickler, der am Python-SDK arbeitet, über die Verwendung von Pydantic zu sagen hat.
Wie das Vonage-Python-SDK Pydantic-Modelle nutzt
Die Verwendung von Pydantic-Modellen zur Erstellung von Anfragen gewährleistet eine korrekte Typisierung und erleichtert die Übergabe der richtigen Objekte an die Vonage-APIs. Mit Version 4 des SDK werden API-Antworten nun in vollständig dokumentierte Pydantic-Modelle deserialisiert, was eine höhere Konsistenz gewährleistet als die Rückgabe von Dictionaries wie in der Vorgängerversion. Darüber hinaus können Sie Pydantic-Modelle weiterhin mit model.model_dump bzw. model.model_dump_json bzw.
In dieser Demonstration werfen wir einen Blick auf die Vonage Verify API und darauf, wie sie mithilfe von Pydantic im SDK modelliert wird.
Was ist die Vonage Verify API?
Die Verify API ist das Produkt der nächsten Generation von Vonage für die Zwei-Faktor-Authentifizierung (2FA). Mit der Verify API können Sie Ihre Nutzer authentifizieren und Betrug verhindern – dank einer einfachen, benutzerfreundlichen API, die die Komplexität der 2FA weltweit ausblendet.
Sie erweitert herkömmliche Authentifizierungsmethoden, indem sie eine größere Bandbreite an Kanälen unterstützt, darunter Over-the-Top-Kanäle (OTT) wie WhatsApp sowie SMS, Voice und E-Mail. Die API unterstützt sowohl JSON Web Tokens (JWT) als auch die Basic-Authentifizierung. Die Basic-Authentifizierung ist einfacher in der Handhabung, unterstützt jedoch keine erweiterten Funktionen wie ACLs. Sie können entweder JWT oder die Basic-Authentifizierung verwenden, jedoch nicht beide gleichzeitig. Weitere Informationen zur Authentifizierung finden Sie in der Dokumentationnachlesen.
Im Großen und Ganzen folgt die Verify API diesem Arbeitsablauf:
Ein Endnutzer löst in einer Anwendung eine 2FA-Anfrage aus
Im Backend löst diese 2FA-Anfrage eine Verify API-Anfrage aus
Die Verify API sendet dem Endnutzer über den konfigurierten Kanal (SMS, Sprachnachricht, WhatsApp oder E-Mail) ein Einmalpasswort (OTP).
Der Endnutzer gibt das OTP in die Anwendung ein
Dadurch wird eine Verifizierungsanfrage ausgelöst, um das vom Endnutzer angegebene OTP mit dem von der API generierten OTP abzugleichen.
Das Ergebnis dieser Überprüfung bestimmt dann, wie es weitergeht (der Endbenutzer wird authentifiziert usw.)
A diagram of the Verify V2 Request with Summary Callbacks.Eine typische Anfrage zur Erstüberprüfung enthält die folgende Nutzlast:
{
"locale": "es-es",
"channel_timeout": 180,
"client_ref": "myPersonalRef",
"code_length": 4,
"code": "e4dR1Qz",
"brand": "ACME",
"template_id": "4ed3027d-8762-44a0-aa3f-c393717413a4",
"workflow": [
{
"channel": "sms",
"to": "44770090000"
},
{
"channel": "voice",
"to": "44770090000"
}
]
}Dies wird im Folgenden näher erläutert:
Schlüssel | Beschreibung | Erforderlich oder optional |
|---|---|---|
Ländereinstellung | Die für die Bestätigungsmeldung zu verwendende Sprachumgebung | Optional, Standardwert ist |
channel_timeout | Die Wartezeit in Sekunden zwischen den Versuchen, den Bestätigungscode zu übermitteln | Optional, Standardwert ist 180 Sekunden |
client_ref | Eine eindeutige Kennung für die Verifizierungsanfrage | Optional |
Code_Länge | Die Länge des zu generierenden Bestätigungscodes | Optional, Standardwert ist 4 |
Code | Ein optionaler alphanumerischer benutzerdefinierter Code, den Sie verwenden können, wenn Sie nicht möchten, dass Vonage den Code generiert | Optional |
Marke | Der Name des Unternehmens oder des Dienstes, der die Bestätigungsanfrage sendet – dieser wird im Text der SMS- oder TTS-Nachricht angezeigt | Erforderlich, maximale Länge: 16 Zeichen |
template_id | Eine benutzerdefinierte Vorlagen-ID – funktioniert nur, wenn | Optional |
Arbeitsablauf | Die Liste der im Verifizierungsworkflow zu verwendenden Kanäle, die in der Reihenfolge ihrer Auflistung verwendet werden | Erforderlich, maximal 3 Einträge |
Weitere Informationen zur API und ihrer Funktionsweise finden Sie in der Vonage Verify-Dokumentation.
Eine erfolgreiche Anfrage wird mit einem 202 OK , um anzuzeigen, dass die Verifizierungsanfrage eingeleitet wurde. Die Antwort enthält außerdem eine request_id , der zum Abschluss des Verifizierungsprozesses erforderlich ist:
{"request_id": "c11236f4-00bf-4b89-84ba-88b25df97315",}Gleichzeitig sendet Vonage dem Endnutzer über den konfigurierten Workflow ein OTP und versucht dabei, jeden Kanal in der Reihenfolge zu nutzen, in der er definiert ist.
Sobald der Endnutzer das OTP erhalten und an die Anwendung übermittelt hat, erfolgt eine weitere Anfrage an den „Verify“-Endpunkt mit dem request_id als Pfadparameter https://api.nexmo.com/v2/verify/:request_id) und das OTP im Anfragetext für den code Schlüssel.
Wenn der angegebene Code mit dem von Vonage generierten und gesendeten Code übereinstimmt, wird eine 200 OK wird eine Antwort zusammen mit einem "status": "complete" .
Demonstration: Wie nutzt die Verify API Pydantic?
Das Vonage Python SDK erleichtert die Implementierung der Vonage-APIs in einer Python-Application. Durch die Integration von Pydantic in das SDK wird die Nutzung der APIs noch einfacher. Mit Pydantic wird ein Fehler nicht erst erst eines API-Aufrufs und der Entstehung etwaiger Kosten, werden die Anfragemodelle bereits bereits der Ausführung validiert, ohne dass hierfür zusätzlicher Code erforderlich ist.
Das Beispiel für diesen Blogbeitrag ist eine minimale 2FA-Anwendung, die das FastAPI-Framework nutzt. Der Endnutzer ruft eine Webseite auf, auf der er seine E-Mail-Adresse eingibt. Mithilfe der Verify API generiert die Anwendung anschließend einen OTP-Code, der an die vom Endnutzer angegebene E-Mail-Adresse gesendet wird. Der Endnutzer gibt diesen Code in die Anwendung ein, und wenn die Verify-Prüfung erfolgreich ist, wird der Endnutzer mit einem animierten GIF belohnt.
Wenn du möchtest, kannst du direkt zum den Code springen und die README-Datei nutzen, um ihn zum Laufen zu bringen.
Im folgenden Code wird die Verify-Anfrage erstellt:
verify_request = VerifyRequest(
brand=settings.verify_brand_name,
workflow=[
EmailChannel(to=email),
],
channel_timeout=60,
code_length=5,
)Wenn wir in das VerifyRequest Objekt eintauchen, finden wir ein Pydantic-Modell vor:
class VerifyRequest(BaseModel):
brand: str = Field(..., min_length=1, max_length=16)
workflow: list[
Union[
SilentAuthChannel,
SmsChannel,
WhatsappChannel,
VoiceChannel,
EmailChannel,
]
]
locale: Optional[Locale] = None
channel_timeout: Optional[int] = Field(None, ge=15, le=900)
client_ref: Optional[str] = Field(None, min_length=1, max_length=16)
code_length: Optional[int] = Field(None, ge=4, le=10)
code: Optional[str] = Field(None, pattern=r'^[a-zA-Z0-9]{4,10}$')
@model_validator(mode='after')
def check_silent_auth_first_if_present(self):
if len(self.workflow) > 1:
for i in range(1, len(self.workflow)):
if isinstance(self.workflow[i], SilentAuthChannel):
raise VerifyError(
'If using Silent Authentication, it must be the first channel in the "workflow" list.'
)
return selfDas Schema wandelt die API-Anfrage mithilfe von Python-Annotationen in Typen um und nutzt die Field Funktion, um Einschränkungen zu definieren. Das workflow Feld definiert einen Union Typ aus anderen modellierten Typen und veranschaulicht damit, wie Typen verschachtelt werden können.
Zu guter Letzt ist der model_validator(mode='after') ist ein Pydantic-Dekorator, der zusätzliche Konfigurationsmöglichkeiten für die Validierung des VerifyRequest Modell validiert werden soll. In diesem Fall wird die def check_silent_auth_first_if_present Methode nach dem VerifyRequest Modell erstellt wurde, um sicherzustellen, dass, falls SilentAuthChannel im Workflow enthalten ist, muss es an erster Stelle aufgeführt werden.
Bestätigung per E-Mail
Nachdem Sie eine virtuelle Umgebung erstellt und aktiviert sowie die erforderlichen Abhängigkeiten gemäß der READMEdie erforderlichen Abhängigkeiten installiert haben, können Sie die Demonstrationsanwendung wie folgt ausführen:
fastapi devDadurch wird eine Web-App auf http://127.0.0.1:8000:
A screenshot of the index page inviting the end-user to enter their email address to try out the Vonage Verify API.Wenn Sie auf „Bestätigungscode senden“ wird der „Verify API“-Workflow ausgelöst. Sie sollten auf eine Webseite weitergeleitet werden, auf der Sie den Code eingeben können, der an die von Ihnen angegebene E-Mail-Adresse gesendet wurde:
A screenshot of the verification page inviting the end-user to enter the code they received in their email.Wenn Sie hier den richtigen Code eingeben, werden Sie zu einer Bestätigungsseite weitergeleitet.
Im Hintergrund nutzt der nutzt der Code die Pydantic-Modelle im SDK, , um sicherzustellen, dass die Verify-Anfrage korrekt aufgebaut und verarbeitet wird.
Verifikation ohne Validierung: Testen ohne Pydantic
Schauen wir uns nun einmal an, wie Pydantic die Verify API unterstützt.
Im folgenden Code gibt es zwei Funktionen, die dieselbe Aufgabe erfüllen: eine Anfrage an den /verify Endpunkt. Eine der Funktionen erstellt den Request-Body manuell, die andere nutzt Pydantic.
Verwendung eines manuell erstellten Anfragetextes:
def without_pydantic(request_payload):
jwt_client = JwtClient(
application_id=settings.vonage_application_id,
private_key=settings.vonage_private_key_path,
)
jwt_token = jwt_client.generate_application_jwt()
payload = {
"brand": request_payload["brand"],
"workflow": [
{
"channel": "email",
"to": request_payload["to_email"],
}
],
"channel_timeout": request_payload["channel_timeout"],
"code_length": request_payload["code_length"],
}
response = requests.post(
"https://api.nexmo.com/v2/verify",
headers={
"Authorization": f"Bearer {jwt_token.decode()}",
"Content-Type": "application/json",
},
json=payload,
)
return responseVerwendung von Pydantic:
def with_pydantic(request_payload):
client = Vonage(
Auth(
application_id=settings.vonage_application_id,
private_key=settings.vonage_private_key_path,
)
)
verify_request = VerifyRequest(
brand=request_payload["brand"],
workflow=[EmailChannel(to=request_payload["to_email"])],
channel_timeout=request_payload["channel_timeout"],
code_length=request_payload["code_length"],
)
client.verify.start_verification(verify_request)
last_response = client.http_client.last_response
return last_responseDer Code verwendet dann unittest , um die Funktionen mit test_data die gegen die API-Parameter verstoßen:
test_data = {
"brand": 12345,
"to_email": 678910,
"channel_timeout": "sixty",
"code_length": "five",
}Führen Sie die Tests mit dem folgenden Befehl aus:
python -m unittest -vDie Ausführung der Tests sollte zu zwei unterschiedlichen Ergebnissen führen: einem Fehler und einem Fehlschlag.
Der Test für die Funktion, die Pydantic verwendet, sollte folgenden Fehler zurückgeben:
pydantic_core._pydantic_core.ValidationError: 1 validation error for EmailChannel
to
Input should be a valid string [type=string_type, input_value=678910, input_type=int]
For further information visit https://errors.pydantic.dev/2.13/v/string_typeWichtig ist hierbei, dass der Test nicht fehlgeschlagen ist – stattdessen wurde ein Fehler ausgegeben, weil Pydantic einen falschen Datentyp erkannt hat , noch bevor die Anfrage gestellt wurde. Darüber hinaus liefert die Fehlermeldung selbst nützliche Informationen für die Fehlersuche, anstatt nur eine allgemeine Typfehlermeldung anzuzeigen. Wir wissen nicht nur, dass der angegebene Datentyp nicht den Anforderungen des Modells entsprach, sondern auch, welcher Typ erwartet wurde und welcher Typ tatsächlich übergeben wurde:
Input should be a valid string [type=string_type, input_value=678910, input_type=int]Der Test für die Funktion ohne Pydantic liefert einen Fehler zurück:
AssertionError: 422 != 202 : Test without Pydantic failed with: 422. Expected: 202Das bedeutet, dass die Anfrage gestellt wurde und, da die API definiert ist, eine 422 aufgrund ungültiger Parameter zurückgegeben wurde.
In diesem begrenzten Testszenario ist ein fehlerhafter API-Aufruf vernachlässigbar – im größeren Maßstab kann dies jedoch ein kostspieliger Fehler sein. Die Verwendung von Pydantic zur Validierung eines Anfragemodells vor dem API-Aufruf trägt dazu bei, unnötige API-Aufrufe zu minimieren, ermöglicht eine elegantere Fehlerbehandlung und erleichtert Entwicklern die Arbeit.
Zusammenfassung
Pydantic bietet eine leistungsstarke, effiziente Lösung für die Datenvalidierung in Python und hilft Entwicklern dabei, die potenziellen Fallstricke des Duck-Typing zu umgehen. Durch die Definition von Schemata, Einschränkungen und Validierungsregeln mit Pydantic-Modellen können Sie die Datenintegrität sicherstellen und Fehler erkennen, noch bevor API-Anfragen gesendet werden. Dies erspart Ihnen kostspielige ungültige API-Aufrufe und sorgt für eine elegantere Fehlerbehandlung.
Wie die Integration des Vonage Python SDK in die Verify API zeigt, erleichtert Pydantic die Arbeit mit komplexen, verschachtelten Anfragemodellen und sorgt gleichzeitig dafür, dass Ihr Code lesbar und wartbar bleibt. Mit Version 4 des SDK werden API-Antworten in vollständig dokumentierte Pydantic-Modelle deserialisiert, was Ihnen mehr Konsistenz, bessere Tool-Unterstützung und insgesamt eine übersichtlichere Entwicklererfahrung bietet.
Weiterführende Literatur und Quellenangaben
Aktualisierungen zur stillen Authentifizierung in der Verify API: Neue Updates zur stillen Authentifizierung in der Verify API verbessern die Entwicklungs- und Testumgebung.
Einrichtung einer passwortlosen Video-Anmeldung mit „Silent Auth“ und der Video API: Nutzen Sie „Silent Auth“ mit Vonage Video, um Benutzer automatisch zu Verify und Echtzeit-Sitzungen schneller zu starten – ganz ohne Passwörter oder Codes.
Einführung der Zero-Tap-Verifizierung für WhatsApp: Wir geben bekannt, dass die Zero-Tap-Verifizierung für WhatsApp über die Vonage Verify v2-API nun verfügbar ist.
Haben Sie eine Frage oder möchten Sie uns mitteilen, was Sie gerade bauen?
Beteiligen Sie sich am Gespräch auf dem Vonage Community Slack
Abonnieren Sie den Entwickler-Newsletter
Folgen Sie uns auf X (früher Twitter) für Updates
Sehen Sie sich die Tutorials auf unserem YouTube-Kanal
Verbinden Sie sich mit uns auf der Vonage Entwickler-Seite auf LinkedIn
Bleiben Sie auf dem Laufenden und halten Sie sich über die neuesten Nachrichten, Tipps und Veranstaltungen für Entwickler auf dem Laufenden.
Teilen Sie:
Liz Acosta ist Developer Advocate bei Vonage. Ihr Karriereweg von der Filmstudentin über die Marketingspezialistin und die Ingenieurin zur Developer Advocate mag zwar unkonventionell erscheinen, ist aber ziemlich typisch für Developer Relations! Liz liebt Pizza, Pflanzen, Möpse und Python.