Hallo Habr. Mein Name ist Anton Potapov, ich bin ein iOS-Entwickler bei
FINCH . Heute möchte ich ausführlich darüber sprechen, wie ein mobiles Projekt in GraphQL übersetzt werden kann, und die Vor- und Nachteile dieses Ansatzes beschreiben. Fangen wir an.
Kurze Einführung
"Vermächtnis." Ich denke, jeder hat dieses schreckliche Wort gehört und die meisten haben ihn von Angesicht zu Angesicht getroffen. Daher müssen Sie nicht sagen, wie schwierig es ist, neue und großartige Funktionen in Ihr Projekt zu integrieren.

Eines unserer Projekte ist eine Bewerbung für ein großes Lotterieunternehmen (ich kann seit der NDA keinen Namen mehr nennen). Vor kurzem musste ich es in GraphQL übersetzen, ohne den Verstand zu verlieren.
Das Projekt ist sehr umfangreich - auf den ersten Blick mussten mindestens 200 bis 300 Stunden aufgewendet werden, dies geht jedoch über alle möglichen zweiwöchigen Sprints hinaus. Wir konnten auch nicht den gesamten Sprint nur einer Aufgabe zuordnen, da es auch Nebenfunktionen gab, die nicht weniger wichtig waren als GraphQL.
Wir haben lange überlegt, was wir tun sollen, und beschlossen, das Projekt Schritt für Schritt Modell für Modell zu übersetzen. Mit diesem Ansatz wird der Übergang reibungslos verlaufen und 200 bis 300 Stunden werden auf mehrere Sprints verteilt.
Technische Punkte
Um an dem Projekt zu arbeiten, habe ich die Apollo-Bibliothek verwendet.
Es gibt bereits einen Artikel über Habré , in dem alle Feinheiten der Arbeit beschrieben werden, sodass ich ihn nicht noch einmal wiederholen werde. Ich warne Sie im Voraus - die Arbeit mit einem Code-generierten Modell ist nicht sehr praktisch und es ist besser, es als "Netzwerk" zu behalten. Jede Entität enthält ein Feld __typename: String, das seltsamerweise einen Typnamen zurückgibt.
Aufgabenzerlegung
Als erstes müssen Sie bestimmen, welches Legacy-Modell in GraphQL übersetzt werden soll. In meinem Fall war es logisch, eines der massiven GameInfo-Modelle und das darin eingebettete DrawInfo zu übersetzen.
- GameInfo - enthält Informationen zu Lotteriespielen und Ziehungen.
- DrawInfo - enthält Daten zur Auflage
Nachdem ich die Auswahl getroffen hatte, entschied ich mich, die alten Legacy-Modelle mit den neuen zu initialisieren, die mit GraphQL erhalten wurden. Bei diesem Ansatz ist es nicht erforderlich, die Teile der Anwendung zu ersetzen, in denen das alte Modell verwendet wird. Die vollständige Fertigstellung der Vorgängermodelle war riskant - nicht die Tatsache, dass das Projekt wie zuvor funktionieren und zu lange dauern würde.
Insgesamt können drei Phasen der GraphQL-Implementierung unterschieden werden:
- Kundenerstellung;
- Erstellen eines Initialisierers für das Legacy-Modell;
- API-Anforderungen durch GraphQL ersetzen.
GraphQLClient
Wie bei jedem Client sollte GraphQLClient über eine Abrufmethode verfügen, nach der die benötigten Daten geladen werden.
Meiner Meinung nach sollte die Abrufmethode für GraphQLClient eine Aufzählung enthalten, auf deren Grundlage die entsprechende Anforderung ausgeführt wird. Dieser Ansatz ermöglicht es uns, einfach Daten für die gewünschte Entität oder sogar den Bildschirm zu empfangen. Wenn die Anforderung Parameter akzeptiert, werden diese als zugehörige Werte übergeben. Mit diesem Ansatz ist es einfacher, GraphQL zu verwenden und flexible Abfragen zu erstellen.
enum GraphQLRequest { case image(ImageId?) }
Unser angepasster GraphQL-Client sollte ApolloClient enthalten, der an vorhandene Funktionen angepasst ist, sowie die oben erwähnte Methode zum Laden von Abrufen.
func fetch<Response>(requestType: GraphQLRequest, completion: @escaping (QLRequestResult<Response>) -> Void)
Was ist QLRequestResult? Es ist gewöhnlich
typealias QLRequestResult<Response> = Result<Response, APIError>
Mit der Abrufmethode können Sie über das Protokoll auf den Client zugreifen und requestType umschalten. Abhängig von requestType können Sie die entsprechende private Lademethode verwenden, mit der Sie das resultierende Modell in das alte konvertieren können. Zum Beispiel:
private func fetchGameInfo<Response>(gameId: String? = "", completion: @escaping (QLRequestResult<Response>) -> Void) {
Als Ergebnis erhalten wir ein fertiges, altes Modell, das von GraphQL erhalten wurde.
Skalartyp
In der GraphQL-Dokumentation wird ein Skalartyp wie folgt beschrieben: "Ein Skalartyp ist eine eindeutige Kennung, die häufig zum erneuten Auswählen eines Objekts oder als Schlüssel für einen Cache verwendet wird." Für eine schnelle Skalierung kann ein Skalartyp leicht mit Typealien verknüpft werden.
Beim Schreiben eines Clients stieß ich auf das Problem, dass es in meinem Schema einen Skalartyp Long gab, der im Wesentlichen vorhanden war
typealias Long = Int64
Alles wäre in Ordnung, aber Apollo wandelt automatisch alle Benutzerskalare in String um, was zu einem Absturz führt. Ich habe das Problem folgendermaßen gelöst:
In Zukunft müssen Sie für jeden Skalartyp neue Typealien hinzufügen. Mit Apollo Version 14.0 wurde "Unterstützung für benutzerdefinierte Int-Skalare" hinzugefügt. Wenn Sie diesen Ansatz und das Flag im Codegen vermeiden möchten, lesen Sie die Lösung für dieses Problem im
Apollo-Git .
Vorteile und Nachteile
Warum ist dieser Ansatz gut? Ein ziemlich schneller Übergang zur Verwendung von GraphQL, was den Ansatz betrifft, alle alten Modelle zu entfernen.
Wenn wir in Zukunft Daten für einen Bildschirm / ein Modell abrufen müssen, können wir uns an GraphQLClient wenden und die erforderlichen Daten abrufen.
Von den Minuspunkten:
- Wenn man den Modelltyp im Client konvertiert, kann man seitdem auf eine andere Entität übertragen Die Arbeit mit Daten liegt nicht in der Verantwortung des Kunden.
- Weitläufiger GraphQLClient. Nach dem Hinzufügen neuer Abfragen wird unsere Klasse immer größer. Eine der Lösungen sind Erweiterungen, in denen Lademethoden beschrieben werden, über die ich im Kapitel GraphQLClient gesprochen habe.
Schlussfolgerungen
Im Allgemeinen kann der Wechsel zu GraphQL mit einem gut geschriebenen Client schnell und problemlos sein. Ich habe ungefähr drei Tage = 24 Arbeitsstunden gebraucht. In dieser Zeit konnte ich einen Client erstellen, das Modell übersetzen und das GameInfo-Modell neu erstellen. Der beschriebene Ansatz ist kein Allheilmittel, sondern eine reine Entscheidung, die in kurzer Zeit umgesetzt wird.
Wenn Sie einen GraphQL-Guru unter sich haben, empfehle ich Ihnen, Ihre Erfahrungen mitzuteilen und zu erläutern, wie bequem es ist, GraphQL + Apollo in großen Projekten zu verwenden. Oder ist das Spiel die Kerze nicht wert?
Vielen Dank für Ihre Aufmerksamkeit!