JSON-RPC 2.0 und PHP

    Wenn Sie ein Entwickler sind und ein Projekt in PHP haben und er endlich seine eigene API implementieren musste - dieser Artikel ist definitiv für Sie;).

    JSON-RPC v1.0 erschien im Jahr 2005, nach 5 Jahren erschien die zweite Version . Im Zeitalter von Javascript und mobilen Anwendungen verwenden viele Entwickler immer noch ihre eigenen Fahrräder anstelle eines vorgefertigten einfachen Standards.

    Warum JSON-RPC und sogar 2.0?


    Ich werde versuchen, die wichtigsten Funktionen hervorzuheben:
    • Es ist zumindest ein Standard. Eine große Auswahl an Bibliotheken für verschiedene Plattformen.
    • Schnelles, einfaches Parsen. JSON-RPC ist nicht so monströs wie XML-RPC oder SOAP.
    • Eingebaute Fehlerbehandlung. Bei REST-Motorrädern müssen Sie herausfinden, wie Sie die Antwort erstellen und was als Nächstes zu tun ist.
    • Queue Support anrufen. Jetzt können 5 HTTP-Anfragen in einer verpackt werden :).
    • Ein einzelner Punkt für die API. Zum Beispiel wird /rpc-server.php in der Lage sein, verschiedene Methoden zu handhaben.
    • Unterstützung für benannte und optionale Parameter beim Aufruf von Methoden.

    Für diejenigen, die mit Version 1.0 vertraut sind, wurden die wesentlichen Neuerungen in 2.0 als Parameter und Aufrufwarteschlangen bezeichnet.
    Eine einfache Anfrage / Antwort lautet wie folgt:
    --> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}
    <-- {"jsonrpc": "2.0", "result": 19, "id": 3}
    --> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}
    <-- {"jsonrpc": "2.0", "result": 19, "id": 1}
    --> [
            {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
            {"jsonrpc": "2.0", "method": "foobar", "id": "2"}
        ]
    <-- [
            {"jsonrpc": "2.0", "result": 7, "id": "1"},
            {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found."}, "id": "2"}
        ]
    


    In dieser komplexen "kreativen" Programmierwelt stellt sich immer die Frage: etwas fertig machen oder etwas Eigenes schreiben?

    Die perfekte Welt. Was brauchen wir


    Wie üblich definieren wir die Kriterien für das Tool, das Sie suchen / erhalten möchten:
    • Vollständige Einhaltung der Spezifikationen. In Anbetracht dieses Faktors wird es höchstwahrscheinlich keine Probleme mit anderen Client / Server-Lösungen geben
    • Einzelne Datei unabhängige Implementierung. Ich möchte kein Framework a la Zend oder PEAR ziehen
    • Verfügbarkeit von Tests. Zumindest eine Garantie dafür, dass die Open-Source-Lösung korrekt funktioniert;)
    • Schöne Umsetzung im Inneren. Alles sollte so einfach, klar und logisch wie möglich sein.
    • Das Vorhandensein eines automatischen Erkennungsmechanismus. JSON-RPC-Server muss in der Lage sein, Metainformationen zu seinen Methoden bereitzustellen
    • Einfache Verbindung Ich habe die Datei verbunden, ein paar Methoden genannt, alles funktioniert.
    • Generierung von Client-Proxy-Klassen. Warum einen Client schreiben, wenn wir bereits einen vorgefertigten Server mit Metadaten haben? ;)

    Genug für den Anfang.

    Ein bisschen Theorie


    Weil JSON-RPC ist ein relativ junges Protokoll, es gibt jedoch noch Momente, die nicht vollständig genehmigt sind. Eine davon ist die von Dojo vorgeschlagene Service-Mapping-Beschreibung . SMD kann einen Webdienst vollständig beschreiben, beginnend mit seinen Methoden bis hin zu implementierten Rückgabetypen. Leider unterstützen nur sehr wenige Lösungen die Implementierung, zum Beispiel Zend_Json_Server , das inputEx Framework ( Generieren von Testformularen ) und das Dojo Framework selbst .

    Fahren wir mit der Suche nach vorhandenen Lösungen fort.

    Bestehende Implementierungen für PHP


    Ich habe die Liste der Kunden von einem Tablet auf Wikipedia genommen .
     php-json-rpcjsonrpc2phptivokajuniorjson-rpc-phpJSONRpc2Zend
    Json
    Server
    zoServices
    Server        
    Compliance-Korrekte Unterstützung für Benachrichtigungen im Stapelmodus.
    +Keine optionalen benannten Parameter+++Keine optionalen benannten Parameter
    Anzahl der Dateien-2> 7361> 56
    SMD-Schaltung------+-
    Tests-+-+-++-
    Interne Implementierung (1..5)-4
    Manuelle Zuordnung der exportierten Funktionen
    3. Zu komplizierte Implementierung für solch eine einfache Aufgabe44. Schwierig4. Magie nach innen!4+. Zend3.
    Kunde        
    ComplianceKeine Charge und Benachrichtigung -+++Keine Charge-Meldung fehlt
    Anzahl der Dateien1-> 7421-6
    Tests---+-+--
    Interne Implementierung (1..5)4-3. Zusätzliche Schritte zum Aufrufen von Methoden444+. :)-3
    Automatische Erzeugung--------

    Ein intelligenter Leser kann argumentieren, welchen Unterschied es macht, wie viele Dateien für die Implementierung verwendet werden, Sie können immer noch alles in eine kleben. Ja, das können Sie, aber dies ist eine zusätzliche Aktion.

    Wie wir sehen, gibt es keine „ideale“ Lösung, die zu uns passt und die ohne Feile sicher verwendet werden kann. Ich hoffe, dass die Dinge auf anderen Plattformen viel besser sind :)
    Es gibt ein allgemeines Gefühl von unvollendeten Projekten, keine Lösung kann einen vollständigen Zyklus der Verwendung der exportierten API (Server, SMD-Schema, Client-Generierung) bieten.
    Ich verstehe auch nicht wirklich diejenigen Entwickler, die versuchen, PHP zu machen, sagen wir Java oder C #. Zum größten Teil wird PHP im Anforderungs- / Antwortschema und nicht im Anwendungsserverschema mit seinen Zuständen verwendet. Ein Skript ist keine kompilierte private Bibliothek.

    Die Antwort auf die Frage „Benutze etwas Fertiges“ oder „Schreibe dein eigenes“ liegt auf der Hand.

    Einfaches JSON-RPC 2.0


    Projekt auf GitHub . Alle zuvor genannten Anforderungen sind implementiert :)

    Server

    Es gibt zwei Anwendungsfälle: entweder von der BaseJsonRpcServer-Klasse erben oder eine Instanz davon erstellen und das exportierte Objekt an den Konstruktor übergeben:
    Execute();
    

    Daher haben wir alle öffentlichen Methoden der DateTimeRpcService-Klasse verfügbar gemacht. Das SMD-Schema kann über den Parameter smd GET abgerufen werden (z. B. eazyjsonrpc / example-server.php? Smd ). Beim Erstellen eines Schemas werden phpDoc-Blöcke berücksichtigt.
    Welche Art von Schaltung gibt es ...
    {"transport":"POST","envelope":"JSON-RPC-2.0","SMDVersion":"2.0","contentType":"application\/json","target":"\/example-server.php","services":{"GetTime":{"parameters":[{"name":"timezone","optional":true,"type":"string","default":"UTC"},{"name":"format","optional":true,"type":"string","default":"c"}],"description":"Get Current Time","returns":{"type":"string"}},"GetTimeZones":{"parameters":[],"description":"Returns associative array containing dst, offset and the timezone name","returns":{"type":"array"}},"GetRelativeTime":{"parameters":[{"name":"text","optional":false,"type":"string","description":"a date\/time string\r"},{"name":"timezone","optional":true,"type":"string","default":"UTC"},{"name":"format","optional":true,"type":"string","default":"c"}],"description":"Get Relative time","returns":{"type":"string"}},"Implode":{"parameters":[{"name":"glue","optional":false,"type":"string"},{"name":"pieces","optional":true,"type":"array","default":["1","2","3"]}],"description":"Implode Function","returns":{"type":"string","description":"string"}}},"description":"Simple Date Time Service"}



    Client

    Es gibt wieder zwei Verwendungsmöglichkeiten: Erstellen Sie entweder eine Instanz der BaseJsonRpcClient-Klasse und übergeben Sie ihr den Webdienst-Link im Konstruktor, oder verwenden Sie den Generator:
    GetRelativeTime( 'yesterday' );
    


    Generator

    Basierend auf dem SMD-Schema können wir eine Klasse für die Arbeit mit dem Server generieren (siehe Beispiel DateTimeServiceClient.php ). Rufen Sie dazu den Generator auf:
    php JsonRpcClientGenerator.php http://eazyjsonrpc/example-server.php?smd DateTimeServiceClient
    

    Das Ergebnis des Befehls ist eine DateTimeServiceClient.php-Datei mit den von uns benötigten Methoden.

    Fliege in der Salbe

    Eine unausgesprochene Regel zum Aufrufen von class-> method () in JSON-RPC verwendet class.method als Namen der Methode (durch den Punkt).
    In der aktuellen Implementierung wird eine solche Funktionalität nicht bereitgestellt. Es wird angenommen, dass url eine exportierte Klasse ist, dann verschwindet die gepunktete Option :). Was den Client betrifft, können Sie hier jederzeit hinzufügen, dass dies nur PHP ist.

    Auch in SMD ist es möglich, Rückgabetypen in Form von Objekten mit ihren Eigenschaften zu beschreiben, aber angesichts der Komplexität der Implementierung werden wir diesen Moment weglassen.

    Für diejenigen, die eine detaillierte Dokumentation suchen, kann ich vorschlagen, die Namen der Methoden, PHP-Kommentare zu ihnen und den Quellcode von Server oder Client zu lesen.

    Leben hackt


    Was haben wir mit der Authentifizierung?

    Es gibt mehrere Implementierungsoptionen:
    1. Verwenden Sie HTTP Basic Auth. Fügen Sie im Client einfach den Benutzernamen und das Passwort zum Array $ CurlOptions hinzu :)
    2. Verwenden Sie Token über HTTP-Header. Um Token zu erhalten, können Sie die erforderliche Methode schreiben.
    3. Verwenden Sie Token als Methodenparameter.

    Was ist mit dem Hochladen von Dateien?

    Einige Leute bieten eine seltsame Möglichkeit, eine Datei in base64 zu codieren und an ein bestimmtes Feld zu senden.
    Eine mehr oder weniger normale Lösung besteht darin, eine Methode zu implementieren, die Ihnen mitteilt, an welcher Adresse Sie mit dem Herunterladen einer Datei beginnen können.
    Beispiel
    --> {"jsonrpc": "2.0", "method": "send_image", "params": ..., "id": 1}
    <-- {"jsonrpc": "2.0", "result": {"URL": "/exampleurl?id=12345", "maxsize": 10000000, "accepted-format":["jpg", "png"]}, "id": 1}
    --> загрузим постом файл по заданному адресу.
    ну и в конце можно проверить, все ли хорошо
    --> {"jsonrpc": "2.0", "method": "send_done", "params": {"checksum": "1a5e8f13"}, "id": 2}
    <-- {"jsonrpc": "2.0", "result": "ok"}
    

    Fehlerbehandlung

    Das Protokoll selbst sieht bereits das Vorhandensein eines Fehlerobjekts mit den Feldern Code , Nachricht und Daten vor . Wenn Sie BaseJsonRpcServer in der aufgerufenen Methode verwenden, können Sie eine Ausnahme auslösen, in die Code und Daten übergeben werden . Sie können Ihre Nachricht mit einem bestimmten Code zum Array $ errorMessages hinzufügen .

    Exportieren Sie nur Objekte mit bestimmten Feldern

    Es hängt alles ganz von Ihnen ab, wie Sie es umsetzen werden. Ich kann Ihnen nur raten, eine Klasse ObjectToJsonConverter zu erstellen , in der die Konvertierung des Objekts in das erforderliche Array implementiert wird.
    Beispiel
     $city->cityId
                    , 'name'   => $city->title
                    , 'region' => $city->region->title 
                );
            }
        }
           // где-то в конце экспортируемого метода
        return array_map( 'ObjectToJsonConverter::GetCity', $cities );
    


    In clientseitige Objekte konvertieren

    Andererseits hängt alles von Ihnen ab. Zum Beispiel können Sie die erforderlichen Klassen erstellen und einige einfache Konverter zurückschreiben (Ideen für die Konvertierung können in MyShowsClient.php übernommen werden ).

    Fazit


    Ich hoffe, dass JSON-RPC nach dem Lesen des Artikels bei der Auswahl eines Interaktionsprotokolls nicht an Aufmerksamkeit verliert.
    Auch nach Tests> 89% des Codes kann ich nur sagen: "Es scheint zu funktionieren" :)

    Jetzt auch beliebt: