API Data ophalen

    ICTscripters maakt gebruik van cookies. Door het gebruiken en browsen naar onze site gaat je automatisch akkoord met het gebruik van cookies. Klik hier voor meer informatie

    • API Data ophalen

      Hallo,

      Zoals sommigen al weten, ben ik bezig met een API Koppeling van Versio. Dit begin aardig te lukken. Maar toch zit ik tegen enkele problemen aan. Alsook ontvang ik graag enkele tips voor eventuele verbetering.

      De API code:

      PHP Source Code

      1. <?php
      2. class Versio_API {
      3. function setApi_login()
      4. {
      5. $this->loginusername = '';
      6. $this->loginpassword = '';
      7. }
      8. function setApi_debug()
      9. {
      10. $this->debug = true;
      11. }
      12. function setApi_testmodus($testmodus)
      13. {
      14. if ($testmodus == 'true') {
      15. $this->endpoint = 'https://www.versio.nl/testapi/v1';
      16. }else{
      17. $this->endpoint = 'https://www.versio.nl/api/v1';
      18. }
      19. }
      20. function setApi_output($outputresult)
      21. {
      22. $this->output = $outputresult;
      23. }
      24. function request($requesttype, $request, $data=array())
      25. {
      26. $url = $this->endpoint.$request;
      27. $ch = curl_init();
      28. curl_setopt($ch, CURLOPT_USERPWD, $this->loginusername . ":" . $this->loginpassword);
      29. curl_setopt($ch, CURLOPT_URL, $url);
      30. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $requesttype);
      31. curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
      32. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      33. $result = curl_exec($ch);
      34. $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      35. curl_close($ch);
      36. $debugdata = array('requesttype' => $requesttype, 'url' => $url, 'postdata' => $data, 'result' => $result, 'httpcode' => $httpcode);// Debug opslaan in DB (latere fase)
      37. return $result;
      38. }
      39. }
      Laat alles zien




      De API Aanroepen:

      Source Code

      1. <?
      2. error_reporting(E_ALL);
      3. ini_set("display_errors", 1);
      4. require('class_versio_api.php');
      5. $versio = new Versio_API();
      6. $versio->setApi_login();
      7. $testmode = true;
      8. $versio->setApi_testmodus($testmode);
      9. $data = array(
      10. 'domain' => 'domin.com',
      11. );
      12. $versio->request('GET', '/domains/domin.com/availability', $data, true);
      13. ?>
      Laat alles zien

      Nu is zijn mijn vragen:
      als ik de lijn van Versio Request een echo geef. krijg ik bijvoorbeeld:

      HTML Source Code

      1. [{"domain":"domin.com","available":false,"push_required":false}]
      Hoe kan ik ze elk apart gebruiken? Dat domain bijvoorbeeld in $versio->domain; zit en $versio->available; en $versio->available; ? Of eventueel anders?

      In "function request" zit $httpcode als ik daar echo geef, krijg ik de 200 status indien het ok is of iets anders als er wat fout loopt. Hoe kan ik deze ook in $result steken?

      Tips zijn uiteraard welkom!

      Aaron
    • Misschien is het een idee om operaties te bundelen zodat de API bepaalde standaard taken kan uitvoeren? Hoe dit dan onder de motorkap is geregeld is de verantwoordelijkheid van de API. Daarom is het m.i. niet nodig om username/password op te slaan, het volstaat prima om deze als parameters mee te geven in een login() routine.

      Vervolgens zou je standaard operaties kunnen maken (afhankelijk van privileges?), dus in plaats van meteen weer terug te vallen op (rauwe) requests (heeft niet zoveel toegevoegde waarde) schrijf je routines die wat meer werk verzetten. Ik zou in een API dus eerder een methode getAvailabilty(<params>) verwachten in plaats van een semi-rauwe cURL-call via request(<params>) naar /domains/<domain>/availability, dit zou abstractie moeten zijn die de API (+initiële configuratie) verder voor je regelt.

      Verder: definieer je klasse-variabelen: debug/testMode. Vervolgens zou je iets kunnen doen met magische getters en setters, het is niet nodig om voor elk van deze variabelen een aparte methode te schrijven. Desnoods maak je een protected klasse-variabele (een array) voor configuratie. Kun je in de setter afdwingen dat het een bestaande config-key betreft.

      En laat je booleans ook echt booleans zijn, en geen strings :).

      Denk bij het ontwerp aan een meer "functioneel gedreven design", oftewel, vraag je af wat voor standaard taken iemand zou willen uitvoeren via zo'n API om werk uit handen te nemen. Daar lijken mij API's bij uitstek geschikt voor.
    • Aaron, volgens mij heb ik jou eerder geprobeerd te helpen met een koppeling tussen je website en Versio (3 jaar terug ofzo?). Werd me toen niet echt in dank afgenomen.

      Maar goed!

      Versio heeft een tijd terug hun nieuwe API gelanceerd, en daarmee direct de plank volledig mis geslagen. Zo heb ik zelf meerdere malen contact gehad met Versio, waarbij ze al een aantal extra commando's hebben toegevoegd aan de API omdat die ronduit miste. Daarnaast hebben we het ook gehad over hoe de API zijn resultaten terug geeft, waarbij mij verteld werd dat een efficiëntere manier pas in versie 2 komt van de REST API. Verder heb ik nog een ticket al geruime tijd open staan over een beveiliging issue waar ik updates over krijg (wat na weken, dan wel niet maanden, eindelijk voorruit gang in lijkt te komen).

      Terug over je vraag. Jij zoekt inderdaad json_decode. Ik je class een beetje aanpassen (persoonlijke voorkeur) naar bijvoorbeeld:

      PHP Source Code

      1. <?php
      2. /* API class. */
      3. class Versio_API
      4. {
      5. /* API inlog gegevens. */
      6. private $api_username = '';
      7. private $api_password = '';
      8. /* Plekje voor api_url. */
      9. private $api_url;
      10. /* Plekje voor debug value. */
      11. private $debug;
      12. /* Plekje voor een eventuele foutmelding. */
      13. private $last_error;
      14. /* Constructer. */
      15. public function __construct ($realm, $debug = false)
      16. {
      17. /* Is de realm test? */ */
      18. if ($realm == 'test')
      19. {
      20. /* Ja, defineer de api_url voor de test api. */
      21. $this->api_url = 'https://www.versio.nl/testapi/v1';
      22. }
      23. else
      24. {
      25. /* Nee, defineer de api_url voor de live api. */
      26. $this->api_url = 'https://www.versio.nl/api/v1';
      27. }
      28. /* Set debuggin. */
      29. $this->set_api_debug ($debug);
      30. }
      31. /* Functie om debug aan te zetten of niet. */
      32. public function set_api_debug ($value = true)
      33. {
      34. /* Defineer de value. */
      35. $this->debug = $value;
      36. }
      37. /* Functie om debug te laten zien, op te slaan, of iets anders. */
      38. public function debug_show ($data)
      39. {
      40. /* Staat debug aan? */
      41. if ($this->debug === true)
      42. {
      43. /* Ja, laat zien. */
      44. echo '<pre>';
      45. print_r ($data);
      46. echo '</pre>';
      47. }
      48. }
      49. /* Functie om de laatste foutmelding op te halen. */
      50. public function get_last_error ()
      51. {
      52. /* Geef de laatste error terug. */
      53. return $this->last_error;
      54. }
      55. /* Functie om een request uit te voeren. */
      56. public function request ($requesttype, $request, $data = array ())
      57. {
      58. /* Defineer de URL. */
      59. $url = $this->api_url . $request;
      60. /* Maak een curl object. */
      61. $ch = curl_init ();
      62. /* Defineer de request url. */
      63. curl_setopt ($ch, CURLOPT_URL, $url);
      64. /* Defineer de inlog gegevens voor de API. */
      65. curl_setopt ($ch, CURLOPT_USERPWD, $this->api_username . ':' . $this->api_password);
      66. /* Geef een custom request op. */
      67. curl_setopt ($ch, CURLOPT_CUSTOMREQUEST, $requesttype);
      68. /* Is de data array leeg? */
      69. if (count (data) > 0)
      70. {
      71. /* Nee, geef deze mee als post velden. */
      72. curl_setopt ($ch, CURLOPT_POSTFIELDS, json_encode ($data));
      73. }
      74. /* Geef aan de result terug te willen. */
      75. curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
      76. /* Voer de curl uit. */
      77. $result = curl_exec ($ch);
      78. /* Haal de HTTP code op. */
      79. $httpcode = curl_getinfo ($ch, CURLINFO_HTTP_CODE);
      80. /* Sluit het curl object. */
      81. curl_close ($ch);
      82. /* Laat de debug zien. */
      83. $this->debug_show (Array ('requesttype' => $requesttype, 'url' => $url, 'postdata' => $data, 'result' => $result, 'httpcode' => $httpcode));
      84. // https://nl.wikipedia.org/wiki/Lijst_van_HTTP-statuscodes
      85. /* Is de request gelukt? */
      86. if ($httpcode >= 200 && $httpcode <= 299)
      87. {
      88. /* Ja, geef het resultaat terug. */
      89. return Array ('http_code' => $httpcode, 'result' => json_decode ($result));
      90. }
      91. else
      92. {
      93. /* Nee, sla de array als foutmelding op. */
      94. $this->last_error = Array ('http_code' => $httpcode, 'result' => json_decode ($result))
      95. /* Nee, gooi exception. */
      96. throw new Exception ();
      97. }
      98. }
      99. }
      100. ?>
      Laat alles zien


      Wat je dan bijvoorbeeld zo uit voert:


      PHP Source Code

      1. <?php
      2. /* Include de api class. */
      3. include ('api_versio.php');
      4. /* Maak een versio object en geef aan dat we willen testen en debuggen. */
      5. $versio = new Versio_API ('test', true);
      6. /* Maak een request array. */
      7. $request_array = Array (
      8. 'domain' => 'domin.com',
      9. );
      10. /* Probeer het onderstaande. */
      11. try
      12. {
      13. /* Voer de request uit en sla results in data op. */
      14. $data = $versio->request ('GET', '/domains/domin.com/availability', $request_array);
      15. /* Print de data in je browser. */
      16. echo '<pre>';
      17. echo 'HTTP code: ' . $data['http_code'] . '<br /><br />';
      18. print_r ($data['result']);
      19. echo '</pre>';
      20. }
      21. catch (Exception $e)
      22. {
      23. /* Foutmelding gevangen, haal deze op. */
      24. $error = $version->get_last_error ();
      25. /* Laat hem zien. */
      26. echo '<pre>';
      27. echo '<strong>Error caught!!</strong><br /><br />';
      28. echo 'HTTP code: ' . $error['http_code'] . '<br /><br />';
      29. print_r ($error['result']);
      30. echo '</pre>';
      31. }
      32. ?>
      Laat alles zien

      Post werd 3x aangepast, het laatst door cakemasher ().

    • Pro tip: escape output. Data kan speciale karakters bevatten binnen de HTML-context.

      Dus in plaats van:

      PHP Source Code

      1. <?php
      2. echo '<pre>'.print_r($data, true).'</pre>';
      3. ?>
      Gebruik:

      PHP Source Code

      1. <?php
      2. echo '<pre>'.htmlspecialchars(print_r($data, true), ENT_QUOTES, 'UTF-8').'</pre>';
      3. ?>
      NB: met de tweede parameter van print_r() kun je aangeven dat de data geretourneerd moet worden als string. Op die manier hoef je je pre's niet apart te echo'en en kun je je code verder inkorten.

      In het algemeen is het handig om een functie te hebben die output "HTML safe" maakt:

      PHP Source Code

      1. <?php
      2. function escape($in) {
      3. return htmlspecialchars($in, ENT_QUOTES, 'UTF-8');
      4. }
      5. ?>
      En je kunt (dan) natuurlijk ook functies stapelen:

      PHP Source Code

      1. <?php
      2. function dump($a) {
      3. echo '<pre>'.escape(print_r($a, true)).'</pre>';
      4. }
      5. ?>
      Zodat je zaken als gebruikte character encoding maar op één plaats vastlegt (die je bijvoorbeeld uit config / een constante kunt trekken) zodat je deze vervolgens ook maar op één plaats hoeft te wijzigen (en al helemaal ideaal als dat dan de config / een constante is, je hoeft dan verder geen letter code te veranderen).