Beste praksis for å designe APIer i Laravel

Stjålet herfra.

Dette innlegget har en lydversjon takket være Miguel Piedrafitas Blogcast-app.

Jeg er ikke bare DevOps Engineer, men jeg har også startet fra grunnen null med PHP siden jeg var liten, tilbake i dagene da jeg gikk i 5. klasse. Siden den gang har jeg kontinuerlig forbedret koden min, og jeg fant ut at folk vedtok en slags standarder for renere kode, bedre visualisering, og siden de er standarder, kunne alle forstå bedre hva enhver annen utvikler skrev i samme kodebase.

Jeg har alltid elsket å kode mer i backend fremfor i frontend. Jeg prøvde å være en Full Stack, men det passet ikke meg. Så jeg har falt tilbake til å skrive backend, spesielt APIer. Denne gangen vil jeg ikke snakke om kodingsstandarder generelt, men jeg vil snakke om hva API-er som faktisk fungerer og hvordan du kan utvikle dem enklere, fra sikkerhet til tips om hvordan du kan gjøre det bedre.

I utgangspunktet er et API et grensesnitt som returnerer data i et spesielt format som alle slags applikasjoner, enten det er en Android-app eller en webapp, kan forstå.

JSON er mye brukt, siden det er nesten overalt. Det andre alternativet er å bruke XML, men jeg hadde problemer med noen tredjeparts APIer (spesielt betalingsleverandører nede i mitt land) som brukte XML over JSON, og utviklingen var en total dritt. Jeg anbefaler å utvikle JSON APIer hele tiden, med mindre noen ber om XML API.

Når du utvikler en API, må du ta hensyn til noen ting, i denne bestemte rekkefølgen:

  • sikkerhet - å sikre den ved hjelp av OAuth, en API-nøkkel eller CORS er et must. Eventuelt bør du bruke gasspedal for å begrense forespørslene til appen din.
  • headers - sørg for at appene dine sender riktig innholdstype. En innholdstypeoverskrift er litt informasjon som forteller klienten som mottar dataene: “denne tingen jeg sender deg er JSON” eller “det her her er XML. parse det ordentlig ”, slik at nettleseren eller klienten din vet hvordan de kan avkode den på riktig måte.
  • kodingsstandarder og navngiving - dette er rent backend. Forsikre deg om at du er konsekvent i svarene dine. Hold deg til bare en slags navngiving og riktig formatering.

Jeg elsker å kode API-er i Laravel siden du vil skalere videre med Event Broadcasting eller de andre manglende Lumen-funksjonene som gjør at det brenner raskt, du kan gjøre det uten å skrive hele prosjektet fra bunnen av. Hvis du vil holde deg på et minimum, kan du gjerne bruke Lumen.

Sikkerhet

Det største problemet du bør ta vare på er sikkerhet. Det er enkelt å sikre det, men hvis du ikke gjør det ordentlig, kan du få uønsket tilgang. I Laravel kan det være lurt å bruke Laravel Passport - det hører til Laravel-økosystemet, støtter godkjenning gjennom den app-ID - App Secret-ting for å få et tilgangstegn, enten for å etterligne noen eller en server, enten er det backend eller frontend. I utgangspunktet vil du sende en forespørsel med App ID og App Secret til et OAuth-endepunkt om å motta et token, som enten kan genereres av en server (dvs. tilgang til et API fra en kommando som kjøres i en cronjob hver dag) eller av en bruker som har logget på appen din.

Alternativt kan det være lurt å bruke en JWT Token-godkjenning, som kjører nesten den samme, men kanskje det er lettere å forstå. Velg ditt valg, og se hvilken som passer bedre for deg, både i implementering og dine behov.

overskrifter

Nettforespørsler er bare normale samtaler mellom en klient og en server, eller mellom to servere. De er avhengige av en forespørsel og et svar, med mindre det er en slags forespørsel på nettet, men det er bare en annen historie. Når du ber om eller sender tilbake ting, er det litt informasjon som heter Headers som må tas vare på - noen av dem forteller serveren hvordan han skal behandle informasjonen som har mottatt eller hvordan klienten ønsker å motta svaret.

Det er som moren din forteller deg: "gå og kjøp melk fra butikken, men kjøp bare av X-merket melk". Du vet hva du skal gjøre, men du må velge den bare en type melk. Det er det samme som forespørslene: "Jeg vil få listen over brukere, men gi meg dem i JSON" eller "Jeg vil ha alle brukerne, men send meg i biter på 20" (i tilfelle du spesifiserer en GET-parameter ). For dette er det en overskrift som heter Accepts, som kan være applikasjon / json i tilfelle du vil ha svaret som JSON. Det er ikke et must, men for noen apper som AJAX, hvis den oppdager den overskriften, vil den automatisk avkode svaret for klienten, uten å måtte gjøre noe sånt:

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

En annen overskrift du må være klar over er Content-Type, det er litt forvirrende, men det er motsatt av Accepts: den forteller serveren hvordan han skal behandle innholdet han får. Hvis du for eksempel vil sende RAW-data, som en JSON-streng, kan du sette Content-Type til applikasjon / json, men hvis du vil motta innholdet gjennom varianten $ _POST, bør du stille den til x-www -form-urlencoded. Dette vil hjelpe deg ikke bare med å analysere innholdet direkte gjennom $ _POST, men det bør brukes i HTML-former fordi det er lett tilgjengelig. Hvis du for eksempel sender data som binær, gjennom filinnganger, må du forsikre deg om at du sendte innholdsmultipart / formdata.

I Laravel vil dette ikke være et problem siden du kan få tilgang til data direkte.

For søknad / json:

funksjonsindeks (Be om $ forespørsel)
{
   $ var = $ forespørsel-> variabel;
}

Imidlertid kan du ikke i applikasjon / json se metoden -> alle () JSON-innholdet:

funksjonsindeks (Be om $ forespørsel)
{
   $ data = $ forespørsel-> alle (); // dette er tom matrise, til og med vi har data.
}

Hvis det er satt til x-www-form-urlencoded eller multipart / form-data, kan du se alle variabler ved å bruke -> alle ().

Når du svarer tilbake, i Laravel, kan du bruke det innebygde JSON-svaret, ELLER du kan ordne det bedre og bruke en pakke som Laravel Fractal eller Laravel Responder. Fra min egen erfaring gjorde Laravel Responder jobben bedre, på en mer semantisk måte. La meg vise deg:

funksjon getUsers (Be om $ forespørsel)
{
   return responder () -> suksess (User :: all ()) -> respond ();
}

Dette vil returnere alle brukere med status OK 200 og formatert som JSON. Kult, ikke sant? For feil må du gjøre noe sånt, som lar deg sende en kode og en melding:

funksjon getUsers (Be om $ forespørsel)
{
   $ brukere = Bruker :: alle ();

   if ($ brukere-> telle () === 0) {
      return responder () -> error ('no_users', 'Det er ingen brukere.') -> svare ();
   }
   return responder () -> suksess ($ brukere) -> respond ();
}

Denne pakken støtter mye mer, så gå over til dokumentene fordi den enkelt kan integreres med transformatorer og tilpassede data sendt.

Kodingsstandarder

Det jeg elsker å se er at folk holder seg til noen standarder som passer dem, eller som er rene. Her er noen tips som kan hjelpe deg med å bygge renere kode og strukturere API-rutene dine bedre.

Bruk ruter / api.php-fil for API-ruter

Laravel kommer med en egen ruter / api.phpfile som forsvarer seg fra de vanlige rutene / web.php-filen som brukes til webruting. api.php-filen er opprettet for å lagre dine API-ruter. Den har en innebygd mellomvare (som kan sees i app / Http / Kernel.php, i $ middlewareGroups-variabelen, under api) og et prefiks for / api, så alle definerte ruter er allerede tilgjengelige for / api

Benytt deg av rutenavnene

Det jeg liker å gjøre, er å angi en som innstilling for hele API, slik at jeg kan få tilgang til rutene ved navn, med api. prefiks.

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

URL-en til denne ruten kan fås ved bruk av ruten ('get.users'), men den kan komme i konflikt med web.php.

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

På denne måten vil du ha den i rute ('api.get.users').

Hvis du bruker rutenavnene, trenger du ikke å erstatte nettadressen overalt hvis du skriver tester, hvis du planlegger å endre URL-adressen og beholde rutenavnet.

Beskrivende, men enkle ruter

En god praksis er å gruppere rutene i seksjoner, som brukere, innlegg osv., Og bruke de enkleste tingene du kan tenke på:

Rute :: gruppe (['som' => 'api.'], Funksjon () {
   Rute :: gruppe (['som' => 'konto.', 'Prefiks' => '/ konto'], funksjon () {
         Rute :: få ('/ brukere', 'API \ UserController @ getUsers') -> navn ('get.users');
         Rute :: få ('/ bruker / {id}', 'API \ UserController @ getUser') -> navn ('get.user');
         Rute :: post ('/ bruker', 'API \ UserController @ createUser') -> navn ('create.user');
         // etc.
   });
});

Bruk :: get () for å hente data, :: post () for å opprette, :: patch () eller :: put () for redigering og :: delete () for å slette data. Som dette ender du opp med å bruke det samme endepunktet, men med den forskjellige typen forespørsler, vil du kunne utløse andre handlinger.

Inni i kontrolleren din bør du bruke enkel koding, og benytte deg av Request-klassene, slik jeg har forklart i Pushing Laravel videre - beste tips og god praksis for Laravel 5.7

funksjon getUsers (Be om $ forespørsel)
{
   $ brukere = Bruker :: alle ();
   return responder () -> suksess ($ brukere) -> respond ();
}
funksjon getUser ($ id, be om $ forespørsel)
{
   $ bruker = Bruker :: findOrFail ($ id);
   return responder () -> suksess ($ bruker) -> svare ();
}
funksjon createUser (CreateUserRequest $ forespørsel)
{
    $ user = User :: create ($ request-> all ());
    return responder () -> suksess ($ bruker) -> svare ();
}
// etc.

Sørg også for at du holder deg til de samme navnene for alle handlinger, slik at du finner dem raskere og alle kan komme inn i kodebasen og gjøre det enkelt å vedlikeholde eller lage innhold. Ikke bruk API-nøkler eller sensitive data til repoen, skriv ren kode og vær ivrig etter å lære av de andre.

For vanskelig å forstå? Nå meg!

Hvis du har flere spørsmål om Laravel, hvis du trenger hjelp med informasjon relatert til DevOps eller bare vil si takk !, kan du finne meg på Twitter @rennokki!

Bli med i samfunnet vårt Slack og les våre ukentlige Faun-emner ⬇

Hvis dette innlegget var nyttig, kan du klikke på klapp -knappen noen ganger for å vise din støtte til forfatteren! ⬇