Razvoj

Architecting APIs for Resilient Systems Beyond Temporary Trends

Arhitektura API-ja za otporne sustave izvan prolaznih trendova

Većinu kvarova API-ja ne uzrokuje nepoznati okvir ni nedostajuća usluga u oblaku. Počinju malim prečacima koji djeluju bezazleno: krajnja točka koja vraća bilo što što baza podataka sadrži, ponovnim pokušajem koji ponavlja neidempotentno plaćanje, vremenskim ograničenjem bez jasnog vlasnika ili odgovorom na pogrešku koji svakih nekoliko mjeseci mijenja oblik.

Otporni API-ji ne grade se predviđanjem svakog trenda. Grade se donošenjem nekoliko trajnih odluka o ugovorima, neuspjehu, vlasništvu nad podacima i operacijama. Te se odluke nastavljaju isplaćivati kada promet raste, timovi se mijenjaju i trenutačno moderno alatno okruženje krene dalje.

Počnite s ugovorom, a ne s kontrolerom

API je obećanje dano drugom sustavu. Taj sustav može biti preglednik, mobilna aplikacija, partnerska integracija, pozadinski radnik ili druga usluga. Implementacija se može slobodno mijenjati samo kada obećanje ostaje razumljivo i pouzdano.

Definirajte resurse i radnje pojmovima koje korisnici prepoznaju. Kupac ne bi trebao razumjeti strukturu vaših internih tablica da bi izradio narudžbu. Izbjegavajte otkrivanje sporednih detalja poput naziva stupaca, ORM odnosa ili identifikatora specifičnih za pohranu u javnim odgovorima.

Stabilan odgovor ima predvidljiva polja, tipove, statusne kodove i semantiku pogrešaka. Ne mora izložiti svako moguće polje već prvog dana. Zapravo, suzdržani se odgovori lakše razvijaju jer se nova neobavezna polja mogu dodati bez prisiljavanja korisnika na prilagodbu.

{
  "data": {
    "id": "ord_8f3a",
    "status": "pending",
    "total": {
      "amount": 2499,
      "currency": "USD"
    }
  }
}

Prikazivanje novca kao cijelog broja u njegovoj najmanjoj jedinici izbjegava iznenađenja s brojevima s pomičnim zarezom. Još važnije, grupiranje iznosa i valute čini značenje eksplicitnim. Ugovor bi trebao otežati nepravilnu upotrebu, a ne samo dokumentirati ispravnu upotrebu.

Neka neuspjeh bude ponašanje API-ja prvog reda

Svaki mrežni poziv može ne uspjeti, stići kasno ili biti ponovljen. Svaka baza podataka može privremeno biti nedostupna. Otporan dizajn pretpostavlja ta stanja prije nego što ih produkcija nametne.

Vremenska ograničenja trebaju biti namjerna. Bez njih jedna spora ovisnost može zauzeti radnike aplikacije sve dok nepovezani zahtjevi ne počnu neuspijevati. Uz pretjerano agresivna vremenska ograničenja, zdrav se rad može prerano napustiti. Postavite razumno ograničenje na temelju budžeta pozivatelja, a zatim učinite neuspjeh vidljivim kroz zapise, metrike i odgovor na koji klijent može reagirati.

Tijela pogrešaka zaslužuju jednaku pažnju kao i uspješni odgovori. Korisna pogreška pruža stabilan strojno čitljiv kod, ljudima čitljivu poruku i relevantne pojedinosti o poljima bez otkrivanja internih informacija.

{
  "error": {
    "code": "validation_failed",
    "message": "The request contains invalid fields.",
    "details": {
      "email": ["A valid email address is required."]
    }
  }
}

Nemojte vraćati neobrađene poruke iznimki ni pogreške baze podataka. One su u najboljem slučaju nestabilni ugovori, a u najgorem sigurnosni rizici. Interno zadržite bogat dijagnostički kontekst s identifikatorom zahtjeva. Izvana vratite dovoljno informacija da klijent može ispraviti zahtjev ili odlučiti treba li pokušati ponovno.

Ponovni pokušaji zahtijevaju idempotentnost

Ponovni pokušaji vrijedni su kod prolaznih neuspjeha, ali su opasni kada radnja stvara nešto sa stvarnim posljedicama. Ako klijent istekne nakon slanja narudžbe, ne može znati je li poslužitelj dovršio rad neposredno prije prekida veze.

Za radnje stvaranja koje moraju tolerirati ponovne pokušaje prihvatite ključ idempotentnosti i trajno pohranite njegovu povezanost s rezultirajućom radnjom. Ponovljeni zahtjev s istim ključem trebao bi vratiti izvorni rezultat umjesto stvaranja druge narudžbe. Ključ mora biti odgovarajuće ograničenog opsega, trajno pohranjen i provjeren u odnosu na zahtjev kako ne bi slučajno ponovio drugu radnju.

U PHP-u to često znači tretirati idempotentnost kao aplikacijsku logiku, umjesto nadati se da će sama HTTP metoda pružiti sigurnost. Ograničenje jedinstvenosti u bazi podataka može biti dio rješenja, ali treba biti upareno s transakcijskim rukovanjem i definiranim odgovorom za duplicirane pokušaje.

Održavajte granice baze podataka poštenima

Baze podataka izvrsne su u provođenju činjenica koje uvijek moraju ostati istinite. Koristite ograničenja za jedinstvene vanjske identifikatore, obavezne odnose, valjane raspone i referencijalni integritet gdje je to prikladno. Validacija u aplikacijskom kodu poboljšava povratne informacije korisniku; ograničenja baze podataka štite ispravnost kada drugi put koda, radnik ili buduća usluga zaobiđu tu validaciju.

Transakcije bi trebale obuhvatiti jednu koherentnu jedinicu lokalnog rada. Na primjer, stvaranje narudžbe i rezerviranje lokalnog inventara mogu pripadati jednoj transakciji. Slanje e-pošte, pozivanje pružatelja plaćanja ili objavljivanje poruke drugoj usluzi ne bi trebalo nepromišljeno smjestiti unutar te transakcije. Vanjski pozivi mogu biti spori, vaša ih baza podataka ne može poništiti i mogu stvoriti zbunjujuće djelomične ishode.

Praktičan obrazac je odlazni spremnik: poslovnu promjenu i zapis događaja zapišite u istoj transakciji, a zatim prepustite radniku objavljivanje događaja na čekanju. Radnik također mora tolerirati dupliciranu isporuku, jer pouzdano objavljivanje obično znači prihvaćanje mogućnosti da korisnik vidi događaj više puta.

Dizajnirajte za performanse bez skrivanja rada

Rad na performansama počinje znanjem o tome kamo odlaze vrijeme i kapacitet. Brza krajnja točka nije ona s najviše predmemorija; to je ona čiji je skupi rad namjeran, izmjeren i ograničen.

Pazite na uobičajene zamke pozadinskog sustava:

  • N+1 upita: učitavanje povezanih podataka po jedan redak umjesto njihova namjernog dohvaćanja.
  • Neograničenih popisa: vraćanje svakog odgovarajućeg zapisa umjesto zahtijevanja paginacije.
  • Skupog serijaliziranja: učitavanje velikih grafova objekata samo da bi se odbacila većina polja.
  • Nejasnoće predmemorije: posluživanje zastarjelih podataka bez jasne politike svježine ili puta invalidacije.

Paginacija bi trebala uspostaviti stabilan poredak. Paginacija s pomakom jednostavna je za mnoge administrativne prikaze, dok se paginacija temeljena na pokazivaču može bolje ponašati za velike zbirke koje se često mijenjaju. Nijedan izbor nije univerzalno superioran; odaberite na temelju oblika upita, potreba korisnika i dosljednosti koju korisnici očekuju tijekom listanja stranica.

Docker pomaže učiniti pretpostavke o izvođenju eksplicitnima, ali spremnik nije arhitektura. Konfiguraciju aplikacije držite izvan slike, pažljivo koristite postavke specifične za okruženje i osigurajte da spremnik ispravno odgovara na signale prekida. Implementacija koja naglo prekida radnike može duplicirati poslove ili prekinuti zahtjeve čak i kada je aplikacijski kod inače ispravan.

Odaberite jednostavna razdvajanja i jasno vlasništvo

Održivost je uvelike sposobnost promjene jednog područja bez straha od njih pet. U PHP pozadinskom sustavu to obično ide u prilog jasnim slojevima: HTTP rukovanje prevodi zahtjeve i odgovore, aplikacijske usluge koordiniraju slučajeve upotrebe, domenska logika izražava poslovna pravila, a infrastrukturni prilagodnici rukovode bazama podataka, redovima i vanjskim API-jima.

Ovo nije argument za ceremoniju oko svake klase. Ovo je argument za smještanje složenosti tamo gdje se može imenovati, testirati i zamijeniti. Kontroler prepun autorizacije, validacije, SQL-a, poziva za plaćanje i oblikovanja odgovora možda danas radi, ali nema sigurno razdvajanje za sutrašnju promjenu.

Verzionirajte API-je samo kada je promjena koja narušava kompatibilnost uistinu nužna. Prije stvaranja nove verzije razmotrite zadržava li dodatno polje, neobavezan parametar, oznaka mogućnosti ili nova krajnja točka postojeće obećanje. Verzije su skupe jer stvaraju paralelne ugovore koje treba podržavati, dokumentirati, nadzirati i na kraju povući.

Otpornost je navika eksplicitnosti

Privremeni trendovi obećavaju prečace. Trajna arhitektura API-ja postavlja jasnija pitanja: Što se događa ako se ovaj zahtjev ponovi? Tko je vlasnik ovih podataka? Što ovdje može ne uspjeti? Kako se klijent oporavlja? Koja invarijanta štiti ovo pravilo kada se kod promijeni?

Najjači sustavi rijetko su oni s najsloženijim dijagramima. To su oni u kojima su ugovori namjerni, neuspjesi nisu iznenađujući, pravila o podacima se provode, a operativno ponašanje razmotreno je prije incidenta. Ugradite te navike u svaku krajnju točku i vaš će API nadživjeti mnogo više od jednog tehnološkog ciklusa.

Portret autora bloga

Mihajlo

Ja sam Mihajlo — programer vođen znatiželjom, disciplinom i stalnom željom da stvorim nešto smisleno. Dijelim uvide, tutorijale i besplatne usluge kako bih pomogao drugima da pojednostave svoj rad i rastu u svijetu softvera i umjetne inteligencije koji se neprestano razvija.