
Teilen Sie:
Sina ist Java Developer Advocate bei Vonage. Er hat einen akademischen Hintergrund und ist generell neugierig auf alles, was mit Autos, Computern, Programmierung, Technologie und der menschlichen Natur zu tun hat. In seiner Freizeit geht er gerne spazieren oder spielt Videospiele.
Ankündigung des Vonage Kotlin Server SDK
Lesedauer: 14 Minuten
Einführung
Als Kotlin in den frühen 2010er Jahren aufkam, konnten nur wenige ahnen, dass es einmal eine der Top 20 Programmiersprachen und damit andere etablierte JVM-Sprachen wie Groovy und Scala übertrifft. Seitdem Kotlin zur De-facto-Sprache für die Entwicklung von Android-Apps geworden ist, hat sich das Ökosystem mit umfangreichen Funktionen und eine eigene jährliche Konferenz.
Trotz der aktualisierten Release-Kadenz und dem Zustrom von Sprachfeatures, um relevant zu bleiben, bleibt Kotlin eine beliebte Sprache jenseits mobiler Anwendungen. Für die serverseitige Entwicklung ist Kotlin aus mehreren Gründen eine ausgezeichnete Wahl: ein reichhaltiges Ökosystem bestehender Bibliotheken (etwas, von dem alle JVM-basierten Sprachen profitieren), selbst die neueste Version 2.0 ist immer noch mit dem mittlerweile zehn Jahre alten Java 8 Bytecode kompatibel, sie ist von Grund auf ohne Legacy-Features elegant gestaltet und macht das Programmieren mit minimaler Boilerplate und leistungsfähigem, aber intuitivem syntaktischem und semantischem Zucker zu einer Freude.
Ich freue mich, Ihnen mitteilen zu können, dass das Vonage Kotlin SDK nach einem Vierteljahr Vollzeitarbeit fertiggestellt wurde. Vonage Kotlin SDK nun offiziell verfügbar ist und unterstützt wird, und zwar ab v1.0.0! Es ist veröffentlicht in Maven Zentraleveröffentlicht, wo Sie auch eine Anleitung zur Verwendung in Ihrem Build-System finden. Mit diesem SDK können Sie alle GA Vonage APIs in Kotlin nutzen, um Voice-Anrufe zu tätigen, SMS zu senden und zu empfangen und Video-Applikationen zu erstellen. In diesem Blogbeitrag werde ich erläutern, wie und warum dieses SDK entstanden ist.
Hintergrund
In Anbetracht der zunehmenden Verbreitung von Kotlin auf der Serverseite und des allgemeinen Augenrollens, das viele Kotlin-Entwickler empfinden, wenn sie mit Java arbeiten müssen, haben wir uns überlegt, Kotlin-Code-Schnipsel für das Java-Server-SDK. Schließlich ist einer der Vorteile von Kotlin seine nahtlose Kompatibilität mit Java. Wir beschlossen jedoch, noch einen Schritt weiter zu gehen. Wir wollten Kotlin-Entwicklern eine wirklich erstklassige Erfahrung bieten, ohne die Kosten und den Wartungsaufwand für die Entwicklung eines SDKs von Grund auf. Unser Ziel war es, in relativ kurzer Zeit ein Proof-of-Concept zu erstellen, das schließlich zu einem vollwertigen SDK führen sollte, wobei wir für die Implementierung und das Datenmodell weiterhin das Java-SDK verwenden würden. Der Rest ist... nun, in der Commit-Geschichte!
Motivation
Die naheliegende Frage, die mir in den Sinn kam, war: Was ist mit dem Java-SDK los? Schließlich betreue ich es seit dem zweiten Quartal 2022 mehr oder weniger hauptberuflich, und Kotlin selbst leistet eine Menge, um die Kompatibilität sicherzustellen. Die Antwort liegt in dem Delta zwischen Kotlin und Javas Sprachfeatures. Javas Ruf, sehr wortreich zu sein, in Kombination mit der Zurückhaltung der Unternehmen, von Java 8 wegzukommen (oder dies zumindest in einem eisigen Tempo zu tun), und die Tatsache, dass die Kompatibilität zwischen den beiden Sprachen auf der Bytecode-Ebene stattfindet, bedeutet, dass das, was in Java idiomatisch ist, nicht unbedingt gut in Kotlin umgesetzt werden kann. Darüber hinaus kann das beeindruckende Arsenal an leistungsstarken Sprachfunktionen von Kotlin nur durch in Kotlin geschriebenen Code genutzt werden.
Aufhebbarkeit
Eines der Unterscheidungsmerkmale von Kotlin im Vergleich zu Java ist die Unterscheidung zwischen nullbaren und nicht-nullbaren Werten. Dies wird nicht durch eine monadische Struktur wie java.util.Optionalerreicht; sie ist der Sprache und ihrer Syntax eigen. Deshalb, Jeder (Kotlins Äquivalent zu Objekt) und Any? sind zwei deutlich unterschiedliche Typen: ersterer ist nicht-nullbar und letzterer nullbar. Da Java diese Unterscheidung nicht kennt (außer für primitive Typen), gibt es in Kotlin den Begriff der "Plattform-Typen", die durch ein Ausrufezeichen gekennzeichnet sind (z.B. Any!). Aus Kompatibilitätsgründen umgeht Kotlin damit die Funktion der Nullbarkeit. Die Erstellung eines Kotlin-SDKs bietet die Möglichkeit, explizit festzulegen, was sowohl in Funktionsparametern als auch in Rückgabetypen nullbar ist und was nicht.
Benannte, Standard- und optionale Parameter
Der Hauptvorteil der expliziten Nullbarkeit ist vielleicht am besten bei Funktionsargumenten zu erkennen. Die Verwendung von Optional in Java ist nicht gerade elegant, aber in Kotlin können optionale Parameter im Code explizit gemacht werden, indem sie als nullable deklariert und standardmäßig auf null gesetzt werden. Dies ermöglicht es dem Benutzer, nur das anzugeben, was er wirklich will und braucht. Darüber hinaus verfügt Kotlin über benannte Funktionsparameter, was bedeutet, dass Argumente nicht aufgrund ihrer Position angegeben werden müssen. Sie können explizit deklariert werden, was es dem Benutzer ermöglicht, bestimmte optionale Parameter zu überspringen und explizit anzugeben, welchen Parameter er bereitstellt, ohne sich auf Codeeinblendungen einer IDE verlassen zu müssen - besonders nützlich, wenn es mehrere Parameter desselben Typs gibt. Darüber hinaus hat die Möglichkeit, Standardwerte festzulegen, auch für nicht-nullbare Parameter, den Vorteil, dass der Standard explizit dokumentiert wird, und bedeutet, dass nur eine Methode für jede Funktion deklariert werden muss, anstatt Überladungen mit einer unterschiedlichen Anzahl von Argumenten für jede Kombination, wie es in Java der Fall ist.
Ein gängiger Vorgang bei den meisten unserer APIs ist beispielsweise die Auflistung von Ressourcen - in der Regel handelt es sich dabei um die zentrale Ressource einer API - Benutzer, Anrufe, Applications, Broadcasts usw. Die Methodensignatur von listRender in der Video API veranschaulicht den Punkt: Standardwerte für die Anzahl und Offset Parameter sind vorgegeben. Da beide vom gleichen Typ sind, wäre es in Java unmöglich, 4 verschiedene Varianten dieser Methode bereitzustellen. In Kotlin ist nur eine Methode erforderlich, um alle vier Fälle abzudecken: keine Parameter, Versatz nur, count nur und beide Parameter. Diese würden wie folgt aufgerufen werden:
video.listRenders() // Default params
video.listRenders(count = 25) // Count only
video.listRenders(offset = 10) // Offset only
video.listRenders(25, 10) // Both params Lambdas für Bauherren
Ein weiteres Manko des Java SDK ist seine starke Abhängigkeit von Buildern. Ich habe bereits über das Builder-Muster geschriebengeschrieben, und wie es nur existiert, weil die Sprache keine benannten und standardmäßigen (optionalen) Konstruktorparameter hat. In einigen Fällen können wir mit Kotlin ganz auf Builder verzichten und uns nur auf benannte/optionale Parameter verlassen. Ein gutes Beispiel dafür ist die Number Insight API-Implementierung. Unter der Haube wird der Builder aus dem Java SDK verwendet, aber die Ausdruckskraft von Kotlin erlaubt es uns, erforderliche und optionale Parameter allein durch die Methodensignatur zu definieren.
Die Neuimplementierung aller Funktionen nach diesem Muster würde jedoch mehr Arbeit (und Doppelarbeit) erfordern, als in diesem Projekt vorgesehen war, und den Wartungsaufwand erhöhen. Stattdessen kann das im Java SDK etablierte Builder-Muster in Kotlin recht elegant wiederverwendet werden, indem "trailing lambdas" verwendet werden; eine Funktion, die häufig bei der Erstellung domänenspezifischer Sprachen (DSLs) verwendet wird. Zur Veranschaulichung wollen wir mit einigen grundlegenden Beispielen beginnen. In der Messages API-Implementierunggibt es Utility-Methoden für jede gültige Kombination von Nachrichtentyp und Kanal. Jede Funktion nimmt als Eingabe einen Lambda-Ausdruck mit der entsprechenden Builder-Klasse als Empfänger an. Aus der Sicht eines Benutzers würde das Versenden einer SMS also so aussehen:
vonage.messages.send(smsText {
from("Kotlin SDK")
to(System.getenv("TO_NUMBER"))
text("Hello, World!")
})Die Methoden von, bis und Text stammen alle aus dem Java SDK's SmsTextRequest.Builder und seiner Oberklasse MessageRequest.Builder, einschließlich der Dokumentation und der Parameter. Aus der Sicht eines Kotlin-Entwicklers ist jedoch der gesamte Prozess des Abrufs des Builders und des Aufrufs der build() Methode versteckt. In Kombination mit den Standardparametern bedeutet dies, dass alle Parameter eines Builders optional sind und somit komplett weggelassen werden können. Zum Beispiel, hier ist die Implementierung der createSession Funktion in der Video API:
fun createSession(properties: CreateSessionRequest.Builder.() -> Unit = {}): CreateSessionResponse =
client.createSession(CreateSessionRequest.builder().apply(properties).build())Für Standardparameter kann sie wie folgt aufgerufen werden:
val session = vonage.video.createSession()Um optionale Parameter anzugeben, kann die Lambda-Syntax am Ende verwendet werden:
val session = vonage.video.createSession {
mediaMode(MediaMode.RELAYED)
archiveMode(ArchiveMode.MANUAL)
}Es ist auch möglich, nachgestellte Lambdas für die Bereitstellung optionaler Werte zu verwenden. Die vielleicht komplexesten Beispiele liegen in der Implementierung der Voice API, wo die Komplexität der Definition von NCCOs im Java SDK am meisten von diesem Ansatz profitiert. Zur Veranschaulichung hier ein Beispiel für die Erstellung eines Sprachanrufs zu einer Telefonnummer mit zwei Aktionen - Sprechen und Verbinden - im Java SDK zusammen mit einigen anderen Konfigurationen, die in Kotlin geschrieben wurden:
val callEvent = javaClient.voiceClient.createCall(Call.builder()
.to(PhoneEndpoint("448001234567", "1p2#5"))
.fromRandomNumber(true)
.advancedMachineDetection(AdvancedMachineDetection.builder().build())
.ncco(
TalkAction.builder("Hello, this is a text-to-speech call.")
.language(TextToSpeechLanguage.UNITED_KINGDOM_ENGLISH)
.premium(true)
.build(),
ConnectAction.builder()
.endpoint(SipEndpoint.builder("sip:me@example.org").build())
.ringbackTone("http://example.com/ringback.mp3")
.build()
)
.ringingTimer(30)
.eventUrl("https://example.com/webhooks/events")
.build()
)Mit der richtigen Einrückung ist es zwar einigermaßen lesbar, aber nicht ganz so elegant wie ein idiomatischerer Ansatz. Hier ist die gleiche Sache mit dem Kotlin SDK geschrieben:
val callEvent = vonage.voice.createCall {
toPstn("448001234567", "1p2#5")
fromRandomNumber(true)
advancedMachineDetection()
ncco(
talkAction("Hello, this is a text-to-speech call.") {
language(TextToSpeechLanguage.UNITED_KINGDOM_ENGLISH)
premium(true)
},
connectToSip("sip:me@example.org") {
ringbackTone("http://example.com/ringback.mp3")
}
)
ringingTimer(30)
eventUrl("https://example.com/webhooks/events")
}Beachten Sie, dass die DSL-Syntax natürlicher verläuft. Insbesondere die toPstn Funktion befreit den Benutzer von der Notwendigkeit, die zu Methode direkt aufrufen zu müssen, und beachten Sie, dass in Ermangelung einer Konfiguration für Advanced Machine Detection kein Builder oder Lambda erforderlich ist. Allerdings ist für die talkActionist der obligatorische Parameter - der zu sprechende Text - Teil des Konstruktors, während sich die optionalen Parameter im Lambda befinden. Ähnliches gilt für die connectToSip Aktion ist der URI obligatorisch, mit einem optionalen Lambda für zusätzliche Konfiguration. In beiden Fällen kann das Lambda weggelassen werden, etwa so:
val callEvent = vonage.voice.createCall {
toPstn("448001234567", "1p2#5")
fromRandomNumber(true)
advancedMachineDetection()
ncco(
talkAction("Hello, this is a text-to-speech call.")
connectToSip("sip:me@example.org")
)
ringingTimer(30)
eventUrl("https://example.com/webhooks/events")
}Wie dies implementiert wird, können Sie in den connectTo*-Funktionen der Voice APIimplementiert, die zwei Builder in einem einzigen Funktionsaufruf kombinieren. Die Parameter der Funktionen sind für den Endpunkt, mit dem eine Verbindung hergestellt wird, und das abschließende Lambda ist für die Konfiguration der Verbinden Aktion selbst.
Ressourcen-basierte Endpunkte
Ein weiterer Unterschied zwischen dem Kotlin- und dem Java-SDK besteht darin, dass das Kotlin-SDK einen ressourcenbasierten Ansatz für API-Aufrufe verfolgt, und dass es die Funktionen von Kotlin nutzt, um Boilerplate zu reduzieren. In den meisten APIs von Vonage gibt es mindestens eine Ressource, die abgefragt, erstellt, aktualisiert und gelöscht werden kann. Für jede dieser Ressourcen gibt es eine Klasse, die dieser Ressource entspricht und den Zugang zu diesen Endpunkten ermöglicht. Was diese Ressourcen alle gemeinsam haben, ist ein eindeutiger Bezeichner. Anstatt diesen an anderer Stelle zwischenspeichern zu müssen, um wiederholt API-Aufrufe auf eine bestimmte Ressource zu tätigen, kümmert sich das SDK darum, so dass die ID nicht jedes Mal angegeben werden muss. Diese Ressourcen können sogar verschachtelt werden, wie das Beispiel der die Video API-Implementierung. Hier ist ein Beispiel:
val existingSession = vonage.video.session(sessionId)
val streams = existingSession.listStreams()
existingSession.connection(connectionId).sendDtmf("1234")Dies macht viel mehr Sinn, wenn Sie eine IDE mit Autovervollständigung verwenden. In diesem Zusammenhang werden die API-Aufrufe nach Ressourcentyp gruppiert. Besonders in komplexen APIs wie Video, wo es verschachtelte Ressourcen und IDs gibt, macht dies die Aufgabe, eine ID bereitzustellen, weniger fehleranfällig, da der erforderliche Parameter durch die Konstruktion bereitgestellt wird. Auf diese Weise können Methodensignaturen für verschachtelte Ressourcen entrümpelt werden, so dass Sie sich auf die Bereitstellung sinnvoller Parameter konzentrieren können, unabhängig von der Adressierung der Ressource. Im Gegensatz dazu ist das Java SDK "flach/kontextlos" in dem Sinne, dass es in der Regel eine Eins-zu-Eins-Zuordnung zwischen Endpunkten in der API-Spezifikation und Endpunkten im SDK gibt. Durch diesen Ansatz wird die Trennung von erforderlichen und optionalen Parametern weiter verbessert, und es ist wahrscheinlicher, dass eine Anfrage aufgrund ihrer Konstruktion korrekt ist.
Werfen Sie einen Blick auf die API-Spezifikation für die Stummschaltung eines Video-Streams als Beispiel an. Es ist klar, dass die Koordinaten für den Endpunkt die Sitzungs-ID und die Stream-ID erfordern. Unter der Java SDK-Implementierungist es möglich, die Sitzungs-ID und die Stream-ID zu verwechseln, indem sie in der falschen Reihenfolge übergeben werden. Im Gegensatz dazu, die Implementierung des Kotlin SDK keine Parameter erforderlich, da keine Daten gesendet werden. Ähnliches gilt für Hinzufügen eines Streams zu einem Archivdie Implementierung des Kotlin SDK eine einzige Methode, bei der klar ist, dass die Stream-ID der Parameter ist, der angesichts des Kontexts übergeben werden sollte. Im Gegensatz dazu ist die Java SDK-Implementierung zwei Methoden (aufgrund optionaler Parameter) und verlässt sich auf die Methodenbenennung und die Dokumentation, um darzustellen, wie sie funktioniert und was sie tut.
Es ist vielleicht eine Frage der persönlichen Vorliebe; keiner der beiden Ansätze kann als objektiv besser bezeichnet werden. Allerdings ist die Konsequenz, mit der das Kotlin-SDK diesen Ansatz in allen APIs verfolgt, wo immer es möglich ist, ein wichtiger Aspekt, der es von anderen unterscheidet, insbesondere wenn man bedenkt, dass das Java-SDK stark auf Builder angewiesen ist, selbst für obligatorische Parameter.
Erweiterungen
Eine weitere schöne Funktion in Kotlin ist Erweiterungsfunktionen; die Möglichkeit, Methoden für bestehende Klassen zu definieren, ohne sie zu erweitern. Dies ist besonders nützlich, um die im Java SDK definierten Builder zu verbessern und sie in Kotlin idiomatischer zu machen. Nehmen wir zum Beispiel die Application API. Jede Vonage Application kann mehrere Capabilities haben, eine von jedem Typ. Jede Capability hat einen oder mehrere Webhooks, und jeder Webhook hat einen Typ, wie z.B. antwort_url, status_url, ereignis_url usw. Je nach Art der Capability sind jedoch nur bestimmte Webhooks anwendbar. Zum Beispiel hat die Verify-Fähigkeit nur status_urlwährend bei der Voice-Fähigkeit answer_url, fallback_answer_url und ereignis_url. Zum Zeitpunkt der Erstellung dieses Artikels ist die Implementierung des Java-SDKs ziemlich klobig. Zur Veranschaulichung sehen Sie hier ein Beispiel für die Aktualisierung des Namens einer bestehenden Anwendung, das Entfernen der Nachrichtenfunktion und die Aktualisierung der Webhooks für Verify und Voice. Beachten Sie, dass zum Aktualisieren einer Anwendung diese zunächst abgerufen werden muss, da die bereitgestellte Konfiguration die vorhandene Anwendung überschreibt. Hier wird sie mit dem Java SDK geschrieben:
val ac = javaClient.applicationClient
val existing = ac.getApplication(appId)
val updated = ac.updateApplication(Application.builder(existing)
.name("My Updated Application")
.addCapability(Verify.builder()
.addWebhook(Webhook.Type.STATUS, Webhook.builder()
.address("https://example.org/webhooks/verify/status")
.method(HttpMethod.POST)
.build()
)
.build()
)
.addCapability(Voice.builder()
.addWebhook(Webhook.Type.ANSWER, Webhook.builder()
.address("https://example.org/webhooks/voice/answer")
.method(HttpMethod.POST)
.build()
)
.addWebhook(Webhook.Type.EVENT, Webhook.builder()
.address("https://example.org/webhooks/voice/event")
.method(HttpMethod.GET)
.build()
)
.build()
)
.removeCapability(Capability.Type.MESSAGES)
.build()
)Das ist eine Menge von Buildern! Man kann sich leicht verirren, und es gibt nichts im Design, das verhindert, dass man den falschen Webhook-Typ für eine Fähigkeit angibt. Vergleichen Sie das mit dem Kotlin SDK:
val ac = vonage.application
val application = ac.application(appId)
application.update {
name("My Updated Application")
verify {
status {
url("https://example.org/webhooks/verify/status")
method(HttpMethod.POST)
}
}
voice {
answer {
url("https://example.org/webhooks/voice/answer")
method(HttpMethod.GET)
}
event {
url("https://example.org/webhooks/voice/event")
method(HttpMethod.POST)
}
}
removeCapability(Capability.Type.MESSAGES)
}Beachten Sie, dass wir die Anwendung nicht einmal über den Endpunkt abrufen müssen - das SDK übernimmt dies für Sie. Darüber hinaus schränken die für jede Capability definierten Erweiterungsfunktionen die Webhooks ein, die definiert werden können, so dass sie konstruktionsbedingt korrekt sind. Dies macht mehr Sinn, wenn man es in einer IDE mit Autovervollständigung betrachtet, aber grundsätzlich, wenn man z.B. in der Voice Blocks befinden, sind die einzigen Optionen die erscheinen werden Antwort, fallbackAntwort und Ereignisweil diese die einzigen sind, die auf dem Builder als Erweiterung definiert sind. Nirgendwo wird "build" erwähnt, und Sie müssen nicht einmal den Webhook-Typ direkt angeben: Sie deklarieren einfach das entsprechende Element.
Es sind Kleinigkeiten wie diese, die die Erfahrung und Produktivität der Entwickler verbessern können. Da wir bei Vonage keines unserer SDKs automatisch generieren, könnte dies natürlich auch in Java angewendet werden. Im Zuge der Entwicklung des Kotlin-SDKs habe ich eine Liste mit kleinen und großen Änderungen am Java-SDK erstellt. Zum Zeitpunkt des Schreibens könnte diese Liste in 55 JIRA-Tickets umgewandelt werden! Es ist jedoch eine nette Geste, dass man mit Erweiterungsfunktionen einfache Erfolge erzielen kann. Natürlich können und sollten nicht alle Verbesserungen im Kotlin-SDK in das Java-SDK zurückportiert werden.
Dokumentation
Das Kotlin SDK ist mit KDocs dokumentiert. Jede einzelne Funktion und Klasse verfügt über eine handschriftliche Dokumentation zu Parametern, Rückgabetyp, Ausnahmen und einer Beschreibung ihrer Funktion. Darüber hinaus werden diese im modernen Dokka-HTML-Format veröffentlicht, das dem Stil der Kotlin-API-Dokumentation entspricht, im Gegensatz zum vergleichsweise veraltet wirkenden Javadocs-Format. Sie können die Dokumentation mit jedem Dienst durchsuchen, der Dokumentationen aus JAR-Dateien rendern kann, wie z.B. Javadoc.io. Natürlich ist die Dokumentation auch direkt in Ihrer IDE verfügbar.
Code-Muster
Code-Snippets für alle unterstützten APIs finden Sie auf unserem Entwickler-Portal. Gehen Sie einfach zu dem Produkt, das Sie interessiert, und unter "Build Your Solution" finden Sie die Schnipsel, bei denen Kotlin eine der Sprachen ist. Sie können sie auch direkt auschecken und mit dem Vonage Kotlin Code Snippets Repo auf GitHub. Ein Beispiel, hier ist ein "Hello World" Text-to-Speech Snippet, das die Voice API im Kotlin SDK verwendet. Jedes Code Snippet, wie es auf der Dokumentationsseite dargestellt wird, hat auch einen Link zum zugehörigen Quellcode auf GitHub. Um die Beispiele auszuführen, müssen Sie nur das Repo auschecken und die Umgebungsvariablen setzen und es dann über Gradle oder Ihre IDE ausführen. Anleitungen dazu finden Sie in der Repository README.
Prüfung
Das SDK hat 99% Code-Abdeckung zum Zeitpunkt des Schreibens. Jede einzelne Funktion wird getestet, mit erforderlichen und optionalen Parametern. Selbst Elemente, die im Java-SDK enthalten sind, werden auf Vollständigkeit getestet. Der gewählte Ansatz ist ein End-to-End-/Integrationstest, da das Java SDK bereits das Datenmodell und die Parametervalidierung testet. Ich habe mich entschieden, hierfür WireMock zu verwenden, ein Framework für API-Tests.
Ich habe eine eine kleine Bibliothek von High-Level-Funktionen um die Überprüfung von Anforderungs- und Antwortkörpern und Kopfzeilen zu erleichtern. Das Ergebnis ist, dass sich jeder Test wie eine Spezifikation liest, so wie es alle guten Tests tun sollten. Die Anatomie eines Tests besteht darin, die erwartete Endpunkt-URL, die HTTP-Methode, den Request Body (JSON oder Query Params), die Header (Auth, Content Type, User Agent), die erwarteten Response-Parameter (falls vorhanden, im JSON-Format) und den HTTP-Statuscode zu simulieren. Dies spiegelt im Wesentlichen die API-Spezifikation im Code wider. Um das Schreiben von Tests weniger langwierig und fehleranfällig zu machen, werden die Request- und Response-Bodies nicht direkt als JSON geschrieben, sondern als eine Map<String, Any>. Diese kann mit Jackson serialisiert werden, so dass nur noch die korrekten Eigenschaftsnamen und erwarteten Werte angegeben werden müssen.
Hier ist ein Beispiel das das Senden einer neuen Anfrage an einen Benutzer in der Verify API. Sie können hier alle Elemente sehen, die im Spiel sind, den deklarativen Ansatz bei der Definition der Spezifikation und wie er alle Elemente der OpenAPI-Spezifikation erfasst. In der Praxis verwenden die meisten Tests im SDK sogar Methoden auf höherer Ebene, die in derselben Datei deklariert sind, um Doppelarbeit und Komplexität weiter zu reduzieren. Außerdem wird jeder Parameter getestet, so dass jeder Endpunkt oft zwei Testmethoden hat: eine für alle Parameter und eine nur für die erforderlichen Parameter. Am komplexesten sind die Tests der Voice APIdennoch sind diese durch den deklarativen Ansatz viel lesbarer und wartbarer als die vergleichsweise ausführlichen Tests, die JSON direkt im Java SDK verwenden. Vergleichen Sie zum Beispiel die Tests der Video API im Java SDK und Kotlin SDKIch bin sicher, Sie werden zustimmen!
Der Vorteil von Tests, die von Grund auf unabhängig von der zugrunde liegenden Implementierung geschrieben werden, besteht darin, dass in Zukunft jeder das SDK in reinem Kotlin neu schreiben könnte, ohne das Java-SDK zu verwenden. Die Tests beschreiben die Spezifikation, so dass nur die tatsächliche Verwendung des SDKs geändert werden muss, nicht aber die Mocks. Das Einzige, was das Kotlin-SDK nicht testet, ist die Parametervalidierung, d. h. ob bestimmte Kombinationen von Parametern gültig sind oder ob sie in Buildern erforderlich sind. Die Validierung des Datenmodells wird im Java-SDK getestet und im Kotlin-SDK absichtlich nicht dupliziert. Manche mögen sogar argumentieren, dass das API-Backend die Validierung durchführen und eine Fehlerantwort zurückgeben sollte, nicht das SDK. Um eine Duplizierung der Validierungslogik und eine weitere Aufblähung der Tests und der Entwicklungszeit zu vermeiden, wurde dies absichtlich nicht in den Anwendungsbereich aufgenommen, da es sich dabei um ein orthogonales Anliegen handelt.
Nächste Schritte
Obwohl das SDK jetzt offiziell mit Implementierungen aller Vonage-APIs im Status der allgemeinen Verfügbarkeit unterstützt wird, ist dies erst der Anfang. Neben der Entwicklung neuer Funktionen und APIs in Verbindung mit dem Java-SDK müssen auch Tutorials geschrieben, Integrationen erstellt und verschiedene Verbesserungen auf der Grundlage von Benutzerfeedback vorgenommen werden. Apropos, wir freuen uns sehr über Anregungen und Vorschläge aus der Community, auch wenn dies zu Änderungen führt. Testen Sie das SDK und lassen Sie uns wissen, was Sie davon halten!
Verabschiedung
Das war's für den Moment. Wenn Sie auf irgendwelche Probleme stoßen oder Verbesserungsvorschläge haben, können Sie gerne einen Fehler auf GitHub zu meldenoder kontaktieren Sie uns auf X (früher Twitter) oder schauen Sie bei unserem Gemeinschaft Slack. Ich hoffe, Sie haben eine angenehme Erfahrung mit dem Kotlin SDK und freue mich über jedes Feedback.
Teilen Sie:
Sina ist Java Developer Advocate bei Vonage. Er hat einen akademischen Hintergrund und ist generell neugierig auf alles, was mit Autos, Computern, Programmierung, Technologie und der menschlichen Natur zu tun hat. In seiner Freizeit geht er gerne spazieren oder spielt Videospiele.