Bedste fremgangsmåder ved design af API'er i Laravel

Stjålet herfra.

Dette indlæg har en lydversion takket være Miguel Piedrafitas Blogcast-app.

Jeg er ikke kun DevOps Engineer, men jeg er også startet fra jorden nul med PHP, siden jeg var et lille barn, tilbage i de dage, hvor jeg var i 5. klasse. Siden da har jeg løbende forbedret min kode, og jeg fandt ud af, at folk vedtog en slags standarder for renere kode, bedre visualisering, og da de er standarder, kunne alle forstå bedre, hvad enhver anden udvikler skrev i den samme kodebase.

Jeg har altid elsket at kode mere i backend snarere end i frontend. Jeg prøvede at være en fuld stak, men det passede ikke mig. Så jeg er faldet tilbage til at skrive backend, især API'er. Denne gang taler jeg ikke om kodningsstandarder generelt, men jeg vil tale om, hvad API'er faktisk fungerer, og hvordan man lettere kan udvikle dem, fra sikkerhed til tip til, hvordan man gør det bedre.

Grundlæggende er en API en grænseflade, der returnerer data i et specielt format, som enhver form for applikation, enten det er en Android-app eller en webapp, kan forstå.

JSON er vidt brugt, da det næsten er overalt. Den anden mulighed er at bruge XML, men jeg havde problemer med nogle tredjeparts API'er (især betalingsudbydere nede i mit land), der brugte XML over JSON, og udviklingen var en total crap. Jeg anbefaler at udvikle JSON API'er hele tiden, medmindre nogen anmoder om et XML API.

Når du udvikler en API, skal du tage nogle ting i betragtning i denne bestemte rækkefølge:

  • sikkerhed - at sikre det ved hjælp af OAuth, en API-nøgle eller CORS er et must. Valgfrit skal du bruge en throttler til at begrænse anmodningerne til din app.
  • headers - sørg for, at dine apps sender den rigtige indholdstype. En overskrift på indholdstypen er en smule information, der fortæller klienten, der modtager dataene: "denne ting, jeg sender dig, er JSON" eller "der herover er XML. parse det ordentligt ”, så browseren eller din klient ved, hvordan man korrekt afkoder den.
  • kodningsstandarder og navngivning - dette er rent backend. Sørg for, at du er konsekvent i dine svar. Hold dig til kun en slags navngivning og korrekt formatering.

Jeg elsker at kode API'er i Laravel, da du ønsker at skalere yderligere med Event Broadcasting eller de andre manglende Lumen-funktioner, der gør det flammende hurtigt, du kan gøre det uden at omskrive hele projektet fra bunden. Hvis du forbliver på et minimum, skal du gerne bruge Lumen.

Sikkerhed

Det største problem, du skal passe på, er sikkerhed. Det er let at sikre det, men hvis du ikke gør det ordentligt, får du muligvis uønsket adgang. I Laravel ønsker du måske at bruge Laravel Passport - det hører til Laravel-økosystemet, understøtter godkendelse gennem det App-ID - App Secret-ting for at få et adgangstoken, enten for at efterligne nogen eller en server, enten er det backend eller frontend. Grundlæggende vil du anmode om med din App ID og App Secret til et OAuth-endpoint om at modtage et token, der enten kan genereres af en server (dvs. adgang til en API fra en kommando, der kører i en cronjob hver dag) eller af en bruger, der er logget ind på din app.

Alternativt kan du bruge en JWT-token-godkendelse, der kører næsten den samme, men måske er det lettere at forstå. Vælg dit valg, og se, hvilken der passer bedre til dig, både i implementering og dine behov.

headers

Webanmodninger er bare normale samtaler mellem en klient og en server eller mellem to servere. De er afhængige af en anmodning og et svar, medmindre det er en slags internetforespørgsel, men det er bare en anden historie. Når du anmoder om eller sender tilbage ting, er der en smule information kaldet Headers, der skal tages hånd om - nogle af dem fortæller serveren, hvordan de behandler de informationer, der har modtaget, eller hvordan klienten gerne vil modtage svaret.

Det er som din mor fortæller dig: "gå til at købe mælk fra butikken, men kun købe fra X-mærket mælk". Du ved hvad du skal gøre, men du skal kun vælge den ene type mælk. Det er det samme som anmodningerne: “Jeg vil have listen over brugere, men giv mig dem i JSON” eller “Jeg vil have alle brugere, men send mig i bunker på 20” (i tilfælde af at du specificerer en GET-parameter ). Til dette er der en overskrift kaldet Accepter, som kan være applikation / json, hvis du ønsker svaret som JSON. Det er ikke et must, men for nogle apps som AJAX, hvis den opdager denne header, afkoder den automatisk svaret for klienten uden at skulle gøre noget lignende:

var data = JSON.parse (respons.data);

En anden overskrift, du skal være opmærksom på, er indholdstypen, det er lidt forvirrende, men det er modsat accepteret: det fortæller serveren, hvordan han skal behandle det indhold, han får. Hvis du f.eks. Vil sende RAW-data, som en JSON-streng, kan du indstille Content-Type til applikation / json, men hvis du vil modtage indholdet via variablen $ _POST, skal du indstille den til x-www -form-urlenkodet. Dette vil hjælpe dig ikke kun med at analysere indholdet direkte gennem $ _POST, men det skal bruges i HTML-formularer, fordi det er let tilgængeligt. Hvis du f.eks. Sender data som binært gennem filindgange, skal du sørge for at sende indholdsmultipart / formdata.

I Laravel vil dette ikke være et problem, da du kan få adgang til data direkte.

Til anvendelse / json:

funktionsindeks (Anmod om $ anmodning)
{
   $ var = $ anmodning-> variabel;
}

I applikation / json kan du imidlertid ikke se ved hjælp af metoden -> alle () JSON:

funktionsindeks (Anmod om $ anmodning)
{
   $ data = $ anmodning-> alle (); // dette er tom matrix, selv vi har data.
}

Hvis det er indstillet til x-www-form-urlencoded eller multipart / form-data, kan du se alle variabler ved hjælp af -> alle ().

Når du svarer tilbage i Laravel, kan du bruge det indbyggede JSON-svar, ELLER du kan regne det bedre ud og bruge en pakke som Laravel Fractal eller Laravel Responder. Fra min egen erfaring gjorde Laravel Responder arbejdet bedre, på en mere semantisk måde. Lad mig vise dig:

funktion getUsers (anmodning om $ anmodning)
{
   return responder () -> succes (User :: all ()) -> respond ();
}

Dette returnerer alle brugere med status OK 200 og formateret som JSON. Sej, ikke? For fejl skal du gøre sådan noget, som giver dig mulighed for at sende en kode og en meddelelse:

funktion getUsers (anmodning om $ anmodning)
{
   $ brugere = Bruger :: alle ();

   if ($ brugere-> tæller () === 0) {
      return responder () -> error ('no_users', 'Der er ingen brugere.') -> respond ();
   }
   return responder () -> succes ($ brugere) -> svare ();
}

Denne pakke understøtter meget mere, så gå over til dokumenterne, fordi den let kan integreres med transformere og tilpassede data sendt.

Kodningsstandarder

Hvad jeg elsker at se er mennesker, der holder sig med nogle standarder, der passer til dem eller er rene. Her er nogle tip, der kan hjælpe dig med at opbygge renere kode og strukturere dine API-ruter bedre.

Brug ruter / api.php-fil til API-ruter

Laravel leveres med en separat ruter / api.phpfile, der forsvarer sig fra den sædvanlige ruter / web.php-fil, der bruges til web routing. api.php-fil oprettes for at gemme dine API-ruter. Det har en on-board anvendt middleware (som kan ses i app / Http / Kernel.php, i $ middlewareGroups-variablen, under api) og et præfiks af / api, så alle definerede ruter er allerede tilgængelige for / api

Brug rutenavnene

Hvad jeg gerne gør, er at indstille en som indstilling til hele API, så jeg kan få adgang til ruterne ved deres navn med api. præfiks.

Rute :: get ('/ brugere', 'API \ UserController @ getUsers') -> navn ('get.users');

Denne rutes URL kan fås ved hjælp af rute ('get.users'), men den kan komme i konflikt med web.php.

Rute :: gruppe (['som' => 'api.'], Funktion () {
   Rute :: get ('/ brugere', 'API \ UserController @ getUsers') -> navn ('get.users');
});

På denne måde har du den på rute ('api.get.users').

Hvis du bruger rutenavnene, behøver du ikke at udskifte URL-adressen overalt, hvis du skriver test, hvis du planlægger at ændre URL-placeringen og beholde rutenavnet.

Beskrivende, men alligevel enkle ruter

En god praksis er at gruppere ruterne i sektioner, som brugere, indlæg osv. Og bruge de enkleste ting, du kan tænke på:

Rute :: gruppe (['som' => 'api.'], Funktion () {
   Rute :: gruppe (['som' => 'konto.', 'Præfiks' => '/ konto'], funktion () {
         Rute :: get ('/ brugere', 'API \ UserController @ getUsers') -> navn ('get.users');
         Rute :: get ('/ bruger / {id}', 'API \ UserController @ getUser') -> navn ('get.user');
         Rute :: post ('/ bruger', 'API \ UserController @ createUser') -> navn ('create.user');
         // etc.
   });
});

Brug :: get () til at hente data, :: post () til oprettelse, :: patch () eller :: put () til redigering og :: delete () til sletning af data. Som dette ender du med at bruge det samme slutpunkt, men med den forskellige type anmodninger vil du være i stand til at udløse andre handlinger.

Inde i din controller skal du bruge enkel kodning og gøre brug af anmodningsklasserne, som jeg har forklaret i Pushing Laravel yderligere - bedste tip og god praksis for Laravel 5.7

funktion getUsers (anmodning om $ anmodning)
{
   $ brugere = Bruger :: alle ();
   return responder () -> succes ($ brugere) -> svare ();
}
funktion getUser ($ id, anmodning om $ anmodning)
{
   $ bruger = Bruger :: findOrFail ($ id);
   return responder () -> succes ($ user) -> respond ();
}
funktion createUser (CreateUserRequest $ anmodning)
{
    $ user = User :: create ($ request-> all ());
    return responder () -> succes ($ user) -> respond ();
}
// etc.

Sørg også for at holde dig til de samme navngivninger for alle handlinger, så du finder dem hurtigere, og alle kan komme ind i kodebasen og gøre det let at vedligeholde eller oprette indhold. Forpligt ikke API-nøgler eller følsomme data til repoen, skriv ren kode og vær ivrig efter at lære af de andre.

For svært at forstå? Nå mig!

Hvis du har flere spørgsmål om Laravel, hvis du har brug for hjælp til oplysninger angående DevOps eller bare vil sige en tak !, kan du finde mig på Twitter @rennokki!

Deltag i vores community Slack og læs vores ugentlige Faun-emner ⬇

Hvis dette indlæg var nyttigt, skal du klikke på klappen knappen nedenfor et par gange for at vise din støtte til forfatteren! ⬇