Demontarea REST

Nu, nu este un articol care vă încurajează să dormiți mai mult! Cu toate acestea, dacă aceasta a fost prima dvs. înclinație, atunci textul următor a fost personalizat pentru tine! Este un adevăr nefericit, totuși, că principiile REST sunt cu totul complexe. Au fost publicate cărți complete despre acest subiect. Nu voi fi atât de îndrăzneț să presupun că pot îmbina un subiect atât de complicat în câteva mii de cuvinte.

Acestea fiind spuse, REST, ca și alte tehnologii, cum ar fi Git și CSS, este una în care un pic de înțelegere vă va duce mult. Pentru a vă deplasa cât mai repede posibil, acest articol se va concentra mai puțin pe istoricul și filosofia din spatele REST (precum și pe modul în care aceasta diferă de alte tehnologii, cum ar fi SOAP) și mai mult despre aspectele practice. Cum puteți implementa astăzi arhitectura REST??


Ce este REST?

Stai acolo, partener. Înainte de a putea sari în câteva exemple de coduri, ar trebui să discutăm mai întâi ce se referă la REST sau la Reprezentarea statului de transfer.

REST, definit cu peste un deceniu în urmă de Roy Fielding în disertația sa doctorală, oferă o modalitate simplă de a organiza interacțiunile dintre sisteme, cel mai adesea prin HTTP și browserul web. În perspectivă, această coeziune are sens perfect: Roy este, de asemenea, unul dintre autorii principali ai HTTP!

Să discutăm despre URI pentru o clipă. Un URI este în esență un identificator pentru o resursă. Luați în considerare următorul exemplu:

GET / prieteni

Am putea numi aceasta resursă. Când această rută este declanșată, urmând modelul REST, toți prietenii ar trebui să fie preluați, probabil dintr-o bază de date, și prezentați.

Dar cum putem specifica o cerere pentru un singur prieten? Ce zici:

GET / prieteni / joe

Lizibil, nu-i așa? Aceasta este una dintre componentele cheie ale unei arhitecturi RESTful. Permite structuri URI, care sunt la fel de ușor de citit atât de oameni, cât și de mașini.

Gândiți-vă la o resursă ca la un substantiv plural. Contactele, statutele, utilizatorii, fotografiile - toate acestea ar fi alegeri perfecte.

Până în prezent, avem cârlige pentru a identifica o colecție, precum și un singur element din această colecție:

/ prieteni / prieteni / joe

De fapt, veți descoperi că aceste două segmente sunt tot ceea ce trebuie vreodată să aveți nevoie! Apoi, putem folosi puterea HTTP pentru a desemna modul în care serverul ar trebui să răspundă acestor URI-uri. Lasă-mă să explic:

Orice solicitare HTTP specifică o metodă sau un verb în interiorul anteturilor. Probabil sunteți familiarizați cu câțiva dintre ei, cum ar fi OBȚINE și POST. Poate un exemplu este în ordine. Deschideți Google Chrome și navigați la http://net.tutsplus.com. Apoi, deschideți Instrumentele de dezvoltator Chrome (printr-un clic dreapta) și vizualizați fila Rețea. Este posibil să aveți nevoie să actualizați pagina pentru a vedea diferitele elemente care au fost preluate. Selectați primul element din listă și vizualizați antetele.

"Instrumentele de dezvoltare ale Google Chrome pot fi folosite, printre altele, pentru a inspecta anteturile pentru o anumită solicitare."

Așteptați un minut; chiar dacă nu am specificat-o, metoda de solicitare, OBȚINE, a fost setat automat! Din aceasta, putem deduce (draga Watson) asta OBȚINE este verbul implicit, când vizualizați pagini web.

Pentru orice URI dat, putem menționa patru metode diferite de solicitare: OBȚINE, POST, A PUNE, și ȘTERGE.

GET / prieteni POST / prieteni PUT / prieteni DELETE / prieteni

În esență, aceste verbe HTTP instruiesc serverul ce trebuie să facă cu datele identificate de URI. Încă confuz? Ar trebui să fii! O modalitate ușoară de a descifra aceste verbe este de a le compara cu acronimul CRUD comun sau Create-Read-Update-Delete.

GET => READ POST => CREAȚI PUT => UPDATE DELETE => DELETE

Am stabilit asta OBȚINE este metoda implicită de solicitare, dar cu siguranță sunteți familiarizați cu POST de asemenea. Ați creat vreodată un formular HTML care, atunci când este trimis, POSTs datele pe serverul dvs.? Ei bine, atunci când formularul se prezintă, metoda de solicitare este folosită POST, nu OBȚINE. Ca atare, pentru a adăuga, de exemplu, o nouă stare la un tabel de tweets din baza dvs. de date, formularul ar trebui să fie POST la / tweet-uri, mai degrabă decât ceva de-a lungul liniilor /tweets/addNewTweet.php.

De fapt, un soner mort pentru o aplicație non-RESTful este de a căuta verbe în URI. Metoda de solicitare HTTP ar trebui să definească modul în care ar trebui să interacționeze serverul cu URI, nu o masă de fișiere PHP fără sens!

Toate cele ce urmează reprezintă URI non-RESTful (și prost conceput).

/tweets/addNewTweet.php /friends/deleteFriendByName.php /contacts/updateContact.php

Pentru a canaliza sinele meu mai tânăr! Nu face asta. Totuși, aceasta ridică întrebarea: care ar fi URI-ul corect pentru a prezenta un formular unui utilizator, în scopul adăugării sau editării unei resurse?

În aceste situații, este logic să adăugați încă două URI.

GET / prieteni / noi GET / prieteni / joe / editare

Prima cale, / Prieteni / noi, ar trebui să prezinte un formular utilizatorului pentru a adăuga un nou prieten. La prezentarea formularului, a POST cererea ar trebui utilizată, deoarece adăugăm un nou prieten.

Pentru al doilea, / Prieteni / Joe / edita, acest formular ar trebui să fie utilizat pentru a edita o înregistrare existentă în baza noastră de date. Atunci când actualizați o resursă, este necesară o solicitare PUT.

Mă întreb cum să faci A PUNE cererile de la un formular HTML? Rămâneți aproape.


verbele

Înainte de a merge mai departe cu câteva exemple concrete de cod, să consolidăm în continuare ceea ce reprezintă fiecare dintre aceste verbe.

OBȚINE

După cum sa menționat anterior, OBȚINE este HTTP metodă de solicitare cu care suntem cu toții cei mai familiarizați: verbul implicit. Un avertisment, sau cele mai bune practici, atunci când este vorba OBȚINE este că ar trebui să fie întotdeauna tratate ca fiind sigure și idempotent. Cu alte cuvinte, a OBȚINE solicitarea ar trebui să fie "numai pentru citire".

Este important să rețineți că, în calitate de inginer, sunteți liber să faceți tot ce doriți, când aceste rute sunt declanșate. Nimic nu vă interzice să modificați datele de pe server când a OBȚINE cererea este declanșată. Este doar o bună practică să se abțină de la a face acest lucru.

O metodă sigură se referă la o metodă care nu va modifica niciodată o resursă. Termenul, idempotent, se referă la o metodă care va obține același rezultat, indiferent de câte ori este solicitat. OBȚINE, A PUNE, și ȘTERGE tipurile de solicitări sunt idempotent - adică dacă respectați regulile.

POST

Cea de-a doua metodă de solicitare cu care vă cunoașteți probabil este POST. În zilele noastre, acest tip este folosit cel mai adesea pentru a desemna când trebuie adăugate date noi unei resurse. De exemplu, atunci când adăugați un nou prieten, metoda POST ar fi alegerea corectă.

POST / prieteni

A PUNE

În mod tradițional, a A PUNE ar trebui să utilizați o solicitare atunci când trebuie să creați sau să actualizați o resursă. Cu toate acestea, probabil rezultatul convențiilor Ruby on Rails, în majoritatea aplicațiilor web moderne, A PUNE este folosit exclusiv pentru actualizarea unei resurse.

Să ne imaginăm că trebuie să actualizăm vârsta prietenului nostru, Joe. După actualizarea informațiilor sale, printr-un formular, metoda corectă de cerere ar fi, A PUNE.

ȘTERGE

Așa cum ați fi ghicit, ȘTERGE ar trebui să fie utilizat atunci când trebuie să ștergeți resursa identificată de un anumit URI.

Dacă nu mai suntem prieteni cu Susan, urmând principiile REST, ea poate fi distrusă, prin intermediul unui ȘTERGE cerere.

DELETE / prieteni / susan

Odată executate, toate datele asociate cu Susan ar trebui eliminate din baza de date.


Punerea în aplicare

Toată această teorie este minunată, dar, în cele din urmă, este inutilă, dacă nu înțelegem cum să aplicăm această arhitectură proiectelor noastre. Există câteva moduri. În următoarea secțiune, vom folosi cadrul popular Slim PHP pentru a organiza rutarea necesară, totuși, veți găsi cu siguranță că majoritatea cadrelor din aceste zile includ o formă de integrare RESTful, inclusiv Ruby on Rails și Laravel.

Pentru a utiliza Slim, primul pas este să îl instalați prin Compozitor.

"Compozitorul este un instrument pentru gestionarea dependenței în PHP. Acesta vă permite să declarați bibliotecile dependente de proiectul dvs. are nevoie și le va instala în proiectul dvs. pentru tine.

Stai, nu ești familiar cu Compozitorul? Opriți ce faceți acum și căutați-l. Compozitorul ne permite să folosim comunitatea PHP, specificând și instalând pachetele pe care o cere o aplicație. Nu mai reinventează roata!

Instalarea Composer la nivel global necesită doar două comenzi rapide.

$ curl -s https://getcomposer.org/installer | php $ sudo mv compozitor.phar / usr / local / bin / compozitor

Asta e! Acum aveți acces la compozitor comanda.

Următorul pas este să specificați Slim ca un pachet necesar pentru aplicația dvs. Acest lucru poate fi realizat, prin intermediul unui a composer.json în rădăcina proiectului dvs..

"necesită": "slim / slim": "2. *"

Cu această cerință stabilită, trebuie doar să fugim compozitorul instala pentru a descărca dependențele necesare. Uşor!

Datorită câtorva linii de cod - și comunității PHP - acum avem o modalitate elegantă de a înregistra rute. Iată un exemplu simplu, pe care îl puteți plasa în interior index.php.

get ('/ friends', function () echo 'Preluarea tuturor prietenilor';); $ App-> run ();

Amintiți-vă: toate aceste funcții sunt gratuite!

"Slim este un framework micro PHP care vă ajută să scrieți rapid aplicații web simple și puternice și API-uri.

Să stabilim acum traseele necesare. Vom alege simplu ecou declarații pentru a descrie ce fel de acțiune ar trebui executată într-o aplicație din lumea reală.

get ('/ friends', function () echo 'Fetch all friends';); $ app-> get ('/ friends / new', function () echo 'Afișați formularul pentru a adăuga un nou prieten'; // Formulă trebuie să postați în / friends); $ app-> get ('/ friends /: friend', funcția ($ friend) echo 'Afișați un singur prieten:' $ friend;); $ app-> get ('/ friends /: friend / edit', functie ($ friend) echo 'Afiseaza formularul pentru a edita prietenul' // Formularul trebuie sa fie pus in / friends / $ friend); $ app ->; post ('/ friends', function () echo 'Adauga un nou prieten';); $ app ->; put ('/ friends /: friend', funcția ($ friend) echo 'Update friend';); $ app ->; delete ('/ friends /: friend', funcția ($ friend) echo 'Șterge prietenul';); $ App ->; run ();

Când folosim Slim, putem specifica metoda de solicitare pe care dorim să o răspundem folosind $ App-> VERB. Ca atare, pentru a șterge prietenul, Joe, am ascultat pentru un șterge cererea de a / Prieteni / Joe, ca astfel:

$ app-> delete ('/ friends /: friend', funcția ($ friend) echo 'Destroy friend';);

Testarea rutelor

Dacă sunteți ca mine, următorul dvs. gând ar putea fi legat de modul în care trebuie să testați A PUNE și ȘTERGE metode. După cum probabil știți, majoritatea browserelor oferă doar suport nativ OBȚINE și POST. Utilizarea celorlalte două metode de solicitare necesită un pic de truc, pe care o vom examina în scurt timp.

Până atunci, cea mai prietenoasă modalitate de a face cereri personalizate este printr-o extensie Google Chrome, numită Advanced Rest Client. Odată instalat, puteți specifica cu ușurință atât un URI, cât și metoda de solicitare dorită.

"Extensiile Advanced REST Client oferă un mecanism ușor de testat URI-uri.

răsuci

Dacă sunteți oarecum confortabil în linia de comandă, este recomandat să folosiți puterea cURL pentru a testa aceste rute.

curl localhost: 8888 / prieteni -X GET

X vă permite să specificați metoda de solicitare care ar trebui utilizată. Rețineți că în fragmentul anterior suntem expliciți; X nu este necesar OBȚINE cereri, deoarece acestea sunt implicit.

Iată un exemplu pentru testarea câtorva rute. Rețineți că folosim simplu ecou declarații pentru a descrie acțiunea care ar trebui să aibă loc.

$ curl localhost: 8888 / friends -X GET Obțineți toți prietenii $ curl localhost: 8888 / friends -X POST -d 'name = Jane & age = 30' Adaugă un prieten nou $ curl localhost: 8888 / friends / jane -X PUT -d 'name = Jane & age = 28' Actualizează prieten, Jane $ curl localhost: 8888 / friends / jane -X DELETE Vezi tu, Jane

Modificarea datelor de pe server va necesita cu siguranță noile date (probabil obținute dintr-un formular). Când se utilizează cURL, se pot specifica perechi cheie-valoare, folosind -d ca de exemplu:

$ curl localhost: 8888 / prieteni -X POST -d 'nume = Jane & vârsta = 30'

Această comandă poate fi împărțită în trei bucăți:

  1. Care este URI-ul?
  2. Ce metodă de solicitare ar trebui utilizată?
  3. Ce date trebuie transmise serverului?

Folosind limbajul de servere de la alegere (în cazul nostru, PHP), puteți prelua acest lucru POST date în același mod pe care l-ați procedat în mod normal:

$ app-> post ('/ friends', function () $ nume = $ _POST ['nume']; // Jane $ age = (int) $ _POST ['age' actualizați baza de date);

Suport pentru browser

Bine, înțelegem cum să specificăm o metodă de solicitare din linia de comandă, dar cum putem face același lucru dintr-un formular HTML? Din păcate, nu ne putem baza pe:

Cultură actuală de browsere nu oferă suport nativ pentru aceste tipuri de cereri. Soluția cea mai comună este să aplicați un pic de truc, prin intrări ascunse. Folosind cadrul Slim, iată cum putem actualiza un prieten.

 ... alte câmpuri de formă aici ...   

Rețineți că, din punct de vedere tehnic, metoda de solicitare este încă setată la POST. Cu toate acestea, în spatele scenei, Slim va citi valoarea de intrare ascunsă și va continua în consecință, în funcție de ce verb este specificat.

Veți găsi cu siguranță că cele mai multe cadre au un model similar pentru specificarea tipurilor de solicitări.

În această secțiune, am revizuit implementarea unei rute complexe în cadrul unui cadru. Așa cum veți descoperi, totuși, în majoritatea cadrelor din zilele noastre, acest lucru este posibil. De exemplu, dacă sunteți un artizan Laravel, puteți utiliza următoarea sintaxă (din versiunea 4):

Route :: resource ('friends', 'FriendsController');

Această metodă convenabilă privind resursele specifică faptul că dorim să generăm căile necesare pentru o prieteni resurse, și face FriendsController responsabil pentru manipularea logicii pentru fiecare dintre aceste rute.


Implementarea manuală

Dacă doriți să renunțați la un cadru, puteți implementa această funcție pe cont propriu. Din păcate, scrierea sistemului de rutare necesar de la zero este dincolo de sfera acestui tutorial, cu toate acestea, iată câteva sfaturi pentru a vă începe.

În primul rând, cea mai importantă întrebare: cum determinăm ce este verbul asociat unei anumite solicitări? Dacă lucrați împreună, creați un nou fișier PHP și adăugați:

 

Dacă rulați această pagină în browser, ieșirea ar trebui să fie OBȚINE. Excelent! Acum, avem mijloacele necesare pentru a detecta metoda de solicitare și procedați după cum este necesar.

Fragmentul următor este decisiv elementar și va necesita o structură mai bună pentru proiectele dvs., dar poate fi folosită ca punct de plecare.

# Ce metodă de solicitare? $ verb = $ _SERVER ['REQUEST_METHOD']; // GET # Ce este URI-ul? $ uri = substr ($ _ SERVER ['REQUEST_URI'], 1); // friends / joe # Creați o serie de segmente $ segments = explode ('/', $ uri); // ['friends', 'joe'] # Determinați numele controlerului $ controller = $ segments [0]; // prieteni / / Continuați după cum este necesar, pe baza comutării de tip cerere ($ verb) case 'GET': caz 'POST': cazul 'PUT': case 'DELETE'

Testarea

Există o varietate de pachete, care fac procesul de scriere a testelor de integrare cât mai simplu posibil. Cu toate acestea, hai să o păstrăm simplu și să folosim biblioteca cURL încorporată în PHP (libcurl) pentru a testa câteva dintre aceste căi.

Primul pas ar fi inițializarea cURL și specificarea URI dorit. În cazul nostru, vom continua testarea prieteni resursă.

# Init curl și specificați URI $ ch = curl_init ('localhost: 8888 / friends');

În continuare, dacă nu testați implicit OBȚINE metoda de solicitare, va trebui să specificăm tipul solicitării.

# Specificați verbul HTTP (Vom ignora datele deocamdată) curl_setopt ($ ch, CURLOPT_CUSTOMREQUEST, 'POST');

În mod implicit, această ieșire va fi imediat înregistrată. Pentru a reveni în loc de ieșire la o variabilă, mai degrabă decât să o afișăm direct, putem folosi CURLOPT_RETURNTRANSFER cadru.

// Returnați ieșirea în loc să o afișați direct curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true);

Ar trebui să o facă! Trebuie doar să executăm cererea și să preluăm rezultatele.

$ răspuns = curl_exec ($ ch); // Adaugă un prieten nou $ statusCode = curl_getinfo ($ ch) ['http_code']; // 200

PHPUnit

Să adăugăm acest lucru la un test PHPUnit - din nou, menținându-l relativ simplu, din motive de lizibilitate. Vom asigura pur și simplu că fiecare rută returnează bunul 200 cod de stare, ceea ce înseamnă că cererea a fost încheiată cu succes. Pentru a usca lucrurile, vom abroga funcționalitatea cURL departe de metoda proprie, cerere().

("prieteni", "GET"); $ this-> assertEquals ('200', $ request-> statusCode);  funcția publică testUpdateFriend () $ request = $ this-> cerere ('friends / frank', 'PUT'); $ this-> assertEquals ('200', $ request-> statusCode);  solicitarea funcției protejate ($ url, $ verb = 'GET') $ ch = curl_init ($ this-> baseUrl. $ url); curl_setopt ($ ch, CURLOPT_CUSTOMREQUEST, $ verb); curl_setopt ($ ch, CURLOPT_RETURNTRANSFER, true); $ response = new stdClass; $ răspuns-> data = curl_exec ($ ch); $ răspuns-> statusCode = curl_getinfo ($ ch) ['http_code']; returnați răspunsul $; 

Presupunând că ai instalat PHPUnit, rulați phpunit friendsTest.php. Dacă reușiți, ar trebui să vedeți verde! Simțiți-vă liber să vă angajați într-un dans privat de victorie.

Pentru a face lucrurile un pas mai departe, este logic să abrogem acest lucru cerere metoda pentru o clasă de bază pe care testele dvs. o pot extinde apoi. Sau, chiar mai bine, permiteți unui instrument terț extrem de testat (și funcțional) să se ocupe de lucrare. S-ar putea să considerați Goutte, care poate fi instalat prin Composer.

"necesită": "slim / slim": "2. *", "fabpot / goutte": "1.0.*@dev"

Odată instalat (compozitorul instala), putem ignora implementarea manuală cURL de mai devreme și, în schimb, facem uz de API-ul mai curat al lui Goutte, după cum se arată mai jos:

client = client nou;  funcția publică testFriendsCollection () $ this-> client-> request ('GET', 'http: // localhost: 8888 / friends'); $ răspuns = $ acest-> client-> getResponse (); $ this-> assertEquals ('200', $ răspuns-> getStatus ());  funcția publică testAddFriend () $ this-> client-> cerere ('POST', 'http: // localhost: 8888 / friends', []); $ răspuns = $ acest-> client-> getResponse (); $ this-> assertEquals (200, $ răspuns-> getStatus ()); 

Nu ați fi prima persoană care să considere că astfel de teste sunt inutile; cu toate acestea, vă asigur că, de îndată ce unul dintre aceste teste nu vă va salva de o gafă stupidă, veți recunoaște imediat utilitatea.


Învățarea ulterioară

Pentru a-ți continua educația, cel mai bun ghid pentru învățarea REST vine la amabilitatea celor de la Apigee. Prezentarea lor, "Învățați un câine să se odihnească", compilează o mulțime de cunoștințe în doar douăzeci de minute. Este necesară vizionarea tuturor începătorilor.

"Apigee oferă una dintre cele mai utile introduceri pentru REST pe web.

Vă mulțumim pentru lectură!

Cod