Bernd: API Schnittstelle

Hallo,

ich habe mal eine Frage zum Thema API. Wie wird so eine API angesprochen? Ich möchte gerne Daten aus einem fremden System auslesen, dazu gibt es auch eine Option:

https://developers.timeular.com/public-api/

Hier benötige ich wenn ich es richtig verstanden habe diese Option

/time-entries/{stoppedAfter}/{startedBefore} .
Find Time Entries in given range

Aber leider gibt es kein Beispiel. Ich möchte gerne die Daten auf meiner Seite ausgeben also mit PHP. Hat jemand von euch mit einer API Erfahrung?

  1. Tach!

    ich habe mal eine Frage zum Thema API. Wie wird so eine API angesprochen?

    Das hängt von der API ab. API ist ein sehr allgemeiner Begriff. Die konkrete Implementation kann beliebig gestaltet sein.

    Hier benötige ich wenn ich es richtig verstanden habe diese Option

    Laut der Beschreibung brauchst du erstmal ein Access Token. Das bekommst du, wenn du dich mit einem Key und Secret über /developer/sign-in anmeldest. Wo du Key und Secret herbekommst, ist dort sicher irgendwo dokumentiert.

    Du stellst dann HTTP-Requests mit dem Access Token in einer HTTP-Hader-Zeile namens Authorize. Diese Bearer Authorization ist ein gängiges Verfahren.

    /time-entries/{stoppedAfter}/{startedBefore} .
    Find Time Entries in given range

    Aber leider gibt es kein Beispiel.

    Die Angaben in geschweiften Klammern sind Platzhalter für Parameterwerte. Die verlinkte Dokumentationsseite schreibt dazu etwas. Zum einen steht davor, welches HTTP-Verb zu verwenden ist, in dem Fall GET. Also ist diese URL mit einem GET-Request anzusprechen. Klickt man auf die Zeile gibts weitere Informationen. Nach der Beschreibung der Parameter wird beschrieben, welche Responses mit welchem Statuscode es geben kann und wie diese aussehen. Das ist also JSON, das du mit den entsprechenden PHP-Funktionen parsen lassen kannst.

    Die Dokumentation ist gleichzeitig ein Testsystem, mit dem du auch Requests an das System absetzen und die Antwort sehen kannst. Ich nehme dazu aber lieber den Postman, der bietet mehr Komfort.

    Ich möchte gerne die Daten auf meiner Seite ausgeben also mit PHP. Hat jemand von euch mit einer API Erfahrung?

    Dazu musst du dich belesen, wie du Requests absetzt, wie du denen HTTP-Header mitgibst (für das Authorize), wie du das Ergebnis bekommst. Ich kann dir dazu noch das Stichwort REST-API auf den Weg geben, denn die vorliegende API arbeitet nach diesem Prinzip.

    Man kann sowas grundsätzlich in PHP realisieren über cURL oder über Dateisystem-Funktionen wie file_get_contents() oder mit Low-Level-Netzwerk-Funktionen. Ich würde wohl file_get_contents() bevorzugen. Die Einzelheiten des Requests kann man da über den Parameter context steuern, dem man einen so genannten Stream-Context mitgibt. Dazu gibts aber Beispiele im PHP-Handbuch.

    dedlfix.

    1. Hallo,

      danke für deine Erklärung. Meinst du ich würde mit diesem Kurs weiter kommen?
      https://de.linkedin.com/learning/php-webservices/willkommen-zu-dem-kurs-php-webservices

      1. Tach!

        Meinst du ich würde mit diesem Kurs weiter kommen?
        https://de.linkedin.com/learning/php-webservices/willkommen-zu-dem-kurs-php-webservices

        Die Vorstellung des Kurses hört sich brauchbar an. Auf die Teile, die sich mit XML und SOAP und dem Erstellen eines Servers beschäftigen, brauchst du für deinen Zweck kein Augenmerk zu legen. Zu sehen war auch kurz eine API-Dokumentation, wie du sie schon bei deinem gewünschten Service kennengelernt hast, so dass sie vielleicht auch darüber etwas zeigen.

        dedlfix.

      2. Ah. So allgemeine Informationen wolltest Du.

        Also, die "API-Geschichte" läuft auf folgendes hinaus:

        Einerseits hast Du einen Server, der - hier via http[s] Informationen oder Aktionen feilbietet wenn man ihm nur richtig fragt. Andererseits einen Client. Ein solcher Client kann ein Browser (in diesem Javascript) sein, aber auch eine Software, z.B. ein PHP-Skript oder halt jedes andere Programm. Einziger Bedingung: In Falle einer Web-API (Man kann sowas auch mit ssh oder telnet "stricken", scheitert dann aber gerne an Firewalls) muss es http[s]-Requests senden und auswerten können.

        Der Trick ist also, dass ein Programm mit einem Server kommuniziert. Bei HTTP gehören zu diesem "richtig fragt" folgende Informationen:

        • die im Header hinterlegte Methode. Kandidaten sind GET, POST aber auch auch PATCH und DELETE.
        • die URL selbst, damit also verbunden die Request-Daten.
        • POST-Daten, die auch mit dem HTTP-Header gesendet werden.
        • Freilich lässt sich auch alles bis zu x-headern (das 'x-' zeigt an, dass der Header nicht genormt ist, vom Webserver (wenn nicht für ihn bestimmt) zumeist ignoriert aber CGI-Anwendungen (wie PHP) oder Modulen (wie eben auch PHP) mitgeteilt wird.

        Also bekommt der Server eine Anfrage und wird darauf hin hoffentlich antworten.

        Diese Antwort setzt sich zusammen aus dem HTTP-Header und dem Payload. Payload kennt man z.B. als Webseite. In Falle einer API wird das am häufigsten Text sein, der allerdings - eben so wie anderer Payload komprimiert gesendet werden und gecached werden darf - wie eben eine Webseite auch. Ebenso wird der Server weitere Informationen wie den HTTPS-Status (404 Not Found, 403 Forbidden, 301 Moved Permanently, 500 Internal Error, …) übertragen.

        Der Text aus dem Payload wiederum kann - je nach Lust, Laune, Erfordernissen oder betrieblicher Übung als JSON, XML, CSV oder auch in einem proprietären Format formuliert sein. Serverseitig ist regelmäßig Programm, z.B. ein PHP-Skript für die Erzeugung zuständig. Genau wie man das von normalen webseiten kennt.

        Es folgt die Praxis an Hand dieses simplen Beispiels mit GET.

        Der Server sendet entsprechend der zwischen meinereinerselbst und meiner Wenigkeit getroffenen Vereinbarung nach einem Abruf der nachfolgenden URL je nach Betriebszustand folgendes JSON, dessen innere Struktur auch zwischen meiner Wenigkeit und meinereinerselbst vereinbart wurde:

        https://home.fastix.org/Tests/sysview.api.php?q=TEMP_BANANA_PI,UPTIME,LOAD

        {
            "TEMP_BANANA_PI": {
                "dataType": "ARRAY",
                "data": {
                    "VALUE": "35.4",
                    "STRING": "35.4°C",
                    "WARN_MAX_VALUE": 85,
                    "WARN_MAX_STRING": "85°C",
                    "WARN_MIN_VALUE": 10,
                    "WARN_MIN_STRING": "10°C",
                    "DEAD_VALUE": 90,
                    "DEAD_STRING": "90°C",
                    "CPUFREQ_VALUE": "600000",
                    "CPUFREQ_STRING": "0,60 GHz"
                }
            },
            "UPTIME": {
                "dataType": "ARRAY",
                "data": {
                    "Sekunden absolut": 1541237,
                    "Tage": 17,
                    "Stunden": 20,
                    "Minuten": 7,
                    "Sekunden": 17,
                    "STRING": "17d 20:07:17"
                }
            },
            "LOAD": {
                "dataType": "ARRAY",
                "data": {
                    "s": "0.00 0.00 0.00 1\/115 25138",
                    "avg1min": "0.00",
                    "avg5min": "0.00",
                    "avg15min": "0.00",
                    "Prozessoren": 4,
                    "Last": {
                        "cpu0": "0.8%",
                        "cpu1": "0.9%",
                        "cpu2": "0.9%",
                        "cpu3": "0.9%",
                        "Gesamt": "0.9%"
                    }
                }
            }
        }
        

        Man kann das mit Javascript auswerten, wie das in diesem einfachen Fall geht siehst Du hier im Quelltext.

        Du willst aber etwas anderes, bei Dir ist PHP der Client.

        Anders als dedlfix würde ich würde ich dazu neigen, gleich die curl-Funktionen von PHP zu benutzen. Freilich kann es sein, dass wenige, einzelne Hoster diese nicht installiert oder (warum auch man immer jemand sowas tut) zwar installiert aber in der PHP.ini blockiert haben:

        <?php
         // erzeuge einen neuen cURL-Handle
         $ch = curl_init();
        
         // setze die URL und andere Optionen
         $dummy = curl_setopt( $ch, CURLOPT_URL, "https://home.fastix.org/Tests/sysview.api.php?q=TEMP_BANANA_PI,UPTIME,LOAD" );
         $dummy = curl_setopt( $ch, CURLOPT_HEADER, 0 );
         // Muss gesetzt werden, damit der Payload in die Variable geschrieben werden kann - Sonst erfolgt Ausgabe von 1 (Erfolg) oder 0 (Fehler).
         $dummy = curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
        
         // führe die Aktion aus und gib die Daten an den Browser weiter
         $result = curl_exec( $ch );
        
         // Der Einfachheit halber decodiere JSON und gebe die Daten aus:
         header('Content-Type: text/plain; charset=utf-8');
         echo "==============================================================\n";
         echo "EMPFANGENE DATEN:\n";
         echo "==============================================================\n";
         print_r (json_decode( $result ) );
         echo "==============================================================\n";
         // schließe den cURL-Handle und gib die Systemresourcen frei
         $dummy = curl_close( $ch );
        

        Abruf dieses Tests.

        Warum curl?

        curl kann Post-Daten, HTTP-Methode, HTTP-Header manipulieren und, ähnlich wie der "xmlHttpRequest" auch auswerten. Die anderen Methoden insbesondere die eigentlich zum Öffnen von Dateien gedachten, stehen da hinten an. APIs (insbesondere von dritten) sind "lebende Standards" - ändern sich also manchmal. Und dann von einem "Dateiöffner" auf Curl umzusteigen (weil der Anbieter plötzlich POST-Daten statt GET-Requests und eine Authorisierung durch Cookies will) wird teuer.

        Hinweis:

        Das Beispiel hat (in den Daten selbst) ein paar Mängel in der Datenstruktur, z.B. fehlt ein Datenpunkt für Errors (mit Code und Beschreibungstext) der bei der Auswertung zu beachten sein wird. Ich habe es aber bewusst gewählt um - für den Anfang - was einfaches zu vorzulegen.

        ** Weitere Beispiel **

        Auch wenn ich die serverseitigen Skripte "nicht für zitierfähig" halte und deshalb nicht zeige sollte das hier Deine Phantasie beflügeln.

        1. Tach!

          Warum curl?

          curl kann Post-Daten, HTTP-Methode, HTTP-Header manipulieren und, ähnlich wie der "xmlHttpRequest" auch auswerten. Die anderen Methoden insbesondere die eigentlich zum Öffnen von Dateien gedachten, stehen da hinten an. APIs (insbesondere von dritten) sind "lebende Standards" - ändern sich also manchmal. Und dann von einem "Dateiöffner" auf Curl umzusteigen (weil der Anbieter plötzlich POST-Daten statt GET-Requests und eine Authorisierung durch Cookies will) wird teuer.

          Alles was curl kann und hier wichtig ist, kann PHP auch mit dem Filesystemfunktionen (nebst Stream-Context), inklusive andere HTTP-Methoden als GET verwenden sowie Header und Payload mitschicken. Es ist hier also keine Frage der technischen Möglichkeiten.

          Ich finde curl mit seinen Funktionsaufrufen zu verwenden umständlicher als ein Array mit den Optionen zu bilden. Am Ende wird Bernd aber wohl zu dem greifen, was man ihm in dem Video erzählen wird, was auch immer es sein mag.

          dedlfix.

          1. Alles was curl kann und hier wichtig ist, kann PHP auch mit dem Filesystemfunktionen (nebst Stream-Context), inklusive andere HTTP-Methoden als GET verwenden sowie Header und Payload mitschicken. Es ist hier also keine Frage der technischen Möglichkeiten.

            Tut mir leid, aber ein paar Kleinigkeiten habe ich bei den Filesystemfunktionen (nebst Stream-Context) zumindest nicht gefunden. Die Fehlerauswertungsmöglichkeiten (und wir propagieren hier immer wieder, die Fehler auszuwerten) sind offenbar besch…eiden.

            <?php
            // erzeuge einen neuen cURL-Handle
            $ch = curl_init();
            
            // setze die URL und andere Optionen (Auswahl durch Kommentieren/Aktivieren):
            $dummy = curl_setopt( $ch, CURLOPT_URL, "https://home.fastix.org/Tests/sysview.api.php?q=TEMP_BANANA_PI,UPTIME,LOAD" );
            #$dummy = curl_setopt( $ch, CURLOPT_URL, "https://home.fastix.org/Error404.php" );
            #$dummy = curl_setopt( $ch, CURLOPT_URL, "https://gibtesnicht/" );
            #$dummy = curl_setopt( $ch, CURLOPT_URL, "http://home.fastix.org/Tests/sysview.api.php?q=TEMP_BANANA_PI,UPTIME,LOAD" );
            
            $dummy = curl_setopt( $ch, CURLOPT_HEADER, 0 );
            // Muss gesetzt werden, damit der Payload in die Variable geschrieben werden kann - Sonst erfolgt Ausgabe von 1 (Erfolg) oder 0 (Fehler).
            $dummy = curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
            
            // führe die Aktion aus und gib die Daten an den Browser weiter
            $result = curl_exec( $ch );
            
            header('Content-Type: text/plain; charset=utf-8');
            	
            if ( $errno = curl_errno( $ch ) ) {
            		echo "==============================================================\n";
            		$error_message = curl_strerror( $errno );
            		echo "Error:  ({$errno}):\n {$error_message}";
            		echo "\n==============================================================\n";
            }
            echo "==============================================================\n";
            print_r( curl_getinfo( $ch ) );
            echo "\n";
            
            $httpResponceCode = curl_getinfo( $ch, CURLINFO_RESPONSE_CODE );
            
            if ( 200 == $httpResponceCode ) {
            	echo "==============================================================\n";
            	echo "EMPFANGENE DATEN:\n";
            	echo "==============================================================\n";
            	// Der Einfachheit halber decodiere JSON und gebe die Daten aus:
            	print_r ( json_decode( $result ) );
            	echo "==============================================================\n";
            } elseif ( 0 == $httpResponceCode ) {	
            	echo "==============================================================\n";
            	echo "DER SERVER IST NICHT ERREICHBAR ODER DIE DNS-AUFLÖSUNG SCHLUG FEHL.\n";
            	echo "==============================================================\n";
            } elseif ( 301 == $httpResponceCode or 302 == $httpReturnCode ) {
            	echo "==============================================================\n";
            	$redirectURL = curl_getinfo( $ch, CURLINFO_REDIRECT_URL );
            	echo "EMPFANG SCHLUG FEHL. REDIRECT MIT CODE {$httpResponceCode} zu {$redirectURL} \n";
            	echo "==============================================================\n";	
            } else {
            	echo "==============================================================\n";
            	echo "EMPFANG SCHLUG FEHL. STATUSCODE WAR {$httpResponceCode}\n";
            	echo "==============================================================\n";
            }	
            	
            // schließe den cURL-Handle und gib die Systemresourcen frei
            $dummy = curl_close( $ch );
            
            1. Tach!

              Tut mir leid, aber ein paar Kleinigkeiten habe ich bei den Filesystemfunktionen (nebst Stream-Context) zumindest nicht gefunden. Die Fehlerauswertungsmöglichkeiten (und wir propagieren hier immer wieder, die Fehler auszuwerten) sind offenbar besch…eiden.

              Woran konkret dachtest du? file_get_contents() liefert false im Fehlerfall und $http_response_header enthält alle Header-Zeilen. Curl kann auch keine darüber hinausgehenden Informationen haben.

              dedlfix.

              1. Woran konkret dachtest du?

                Neben dem 301er/302er und der Möglichkeit auch den ETag auszuwerten und miot dem Request zu senden (sowie auf einen 304er zu hoffen), vor anderem an diese Fälle:

                # Error:  (6):
                # Couldn't resolve host name
                $dummy = curl_setopt( $ch, CURLOPT_URL, "https://gibtesnicht/" );
                
                # Error:  (7):
                # Couldn't connect to server
                $dummy = curl_setopt( $ch, CURLOPT_URL, "https://10.1.1.254" );
                
  2. Hier benötige ich wenn ich es richtig verstanden habe diese Option

    /time-entries/{stoppedAfter}/{startedBefore} .
    Find Time Entries in given range

    Aber leider gibt es kein Beispiel. Ich möchte gerne die Daten auf meiner Seite ausgeben also mit PHP. Hat jemand von euch mit einer API Erfahrung?

    Auf der selben Seite fand ich

    All timestamps are in format 'YYYY-MM-DDTHH:mm:ss.SSS' in UTC, eg. '2017-12-31T23:59:59.999'.

    Wolltest Du das wissen?