Надвор од CRUD: Архитектирање API-ја што се размеруваат со вашите амбиции
Повеќето API-а започнуваат како разумна колекција од CRUD крајни точки. Креирај клиент, преземи нарачка, ажурирај профил, избриши запис. Тоа често е токму вистинската почетна точка. Проблемот започнува кога API-то незабележливо станува граница меѓу производи, тимови, интеграции и деловни процеси, додека неговиот дизајн сè уште претпоставува дека е само тенка обвивка околу базата на податоци.
Скалирањето на API не значи само обработка на повеќе барања. Значи да се овозможи производот да расте без секоја нова функционалност да се претвори во ризична миграција, промена што го нарушува одговорот или заплет од логика во контролерите. Архитектурата треба да ги направи важните одлуки експлицитни: што ветува API-то, каде се наоѓаат деловните правила, како податоците безбедно се менуваат и како се соопштуваат неуспесите.
Дизајнирајте околу можности, не околу табели
Шемата на база на податоци опишува како се складираат податоците. API треба да опише што можат да прават клиентите. Тоа се поврзани аспекти, но не се ист договор.
Крајна точка како POST /orders може да биде корисна почетна точка, но на зрел систем често му требаат појасни деловни дејства: поднесување нарачка, нејзино откажување, одобрување поврат на средства, резервирање залихи или издавање фактура. Овие операции имаат правила, дозволи, нуспојави и премини на состојби што не се вклопуваат удобно во „ажурирај го овој ред“.
На пример, генеричка крајна точка за ажурирање може случајно да дозволи невозможни состојби:
{
"status": "shipped",
"payment_status": "unpaid"
}
Наместо тоа, моделирајте го дејството и валидирајте го на едно место:
POST /orders/ord_123/ship
Барањето може да ги бара информациите потребни за испраќање на нарачката, додека апликациската услуга ги проверува плаќањето, залихите, тековната состојба на нарачката и овластувањето. API-то станува полесно за разбирање за клиентите бидејќи изразува намера наместо да го изложува секое внатрешно поле.
Направете го договорот траен
Клиентите зависат од повеќе од патеките на крајните точки. Тие зависат од имињата на полињата, однесувањето при валидација, правилата за пагинација, формите на грешки, барањата за автентикација и значењето на статусните кодови. Третирајте го сето тоа како договор за производот.
Трајните договори фаворизираат адитивни промени. Додавањето опционално поле во одговор обично е побезбедно од негово преименување. Воведувањето нова крајна точка обично е побезбедно од менување на значењето на постојно поле. Ако промена што нарушува компатибилност е неизбежна, верзионирајте намерно и дајте им на потрошувачите патека за миграција наместо тивко да го промените однесувањето во продукција.
Одговорите за грешка ја заслужуваат истата грижа како и успешните одговори. Клиентот треба да може да разликува невалиден влез од ресурс што недостига, неуспех при овластување и привремен проблем со услугата. Конзистентната форма исто така спречува кодот за фронтенд и интеграции да акумулира посебни случаи.
{
"error": {
"code": "validation_failed",
"message": "The request contains invalid fields.",
"details": {
"email": ["The email field must be a valid address."]
}
}
}
Не изложувајте исклучоци од базата на податоци, траги од стекот или пораки специфични за рамката на повикувачите. Безбедно евидентирајте корисен внатрешен контекст, но вратете стабилен јавен речник за грешки.
Одржувајте го HTTP тенок, а деловната логика кохезивна
Во PHP апликација, контролерите се погодна влезна точка, а не дом за деловните правила на системот. Контролерот треба да го автентицира барањето, да го валидира неговиот влез на транспортно ниво, да повика апликациска услуга и да го преобрази резултатот во HTTP одговор. Кога контролерот почнува да координира трансакции, проверки на залихи, е-пораки и ревизорски записи, станува тежок за тестирање и уште потежок за повторна употреба.
Практична поделба често изгледа вака:
- Контролери преведуваат HTTP барања и одговори.
- Апликациски услуги координираат случај на употреба, како што е поставување нарачка.
- Доменски правила ги спроведуваат инваријантите и валидните премини на состојби.
- Репозиториуми или слоеви за пристап до податоци преземаат и зачувуваат податоци без да ги протекуваат деталите за складирањето насекаде.
- Инфраструктурни адаптери управуваат со редици, е-пошта, даватели на плаќања, кешови и надворешни API-а.
Ова не е аргумент за церемонијални слоеви во мала апликација. Тоа е потсетник сложеноста да се смести таму каде што може да се именува, тестира и менува. Започнете едноставно, а потоа извлечете граница кога некоја грижа се користи повторно, е склона кон неуспех или веројатно ќе еволуира независно.
Заштитете ги запишувањата со трансакции и идемпотентност
Перформансите при читање добиваат внимание, но неточните запишувања предизвикуваат потрајна штета. Секој работен тек што менува повеќе записи или активира последователна работа има потреба од јасна стратегија за конзистентност.
Користете трансакција во база на податоци за промени што мора да успеат или да не успеат заедно. На пример, евидентирањето на нарачка, резервирањето залихи и креирањето запис за плаќање може да припаѓаат во една трансакција ако ја користат истата база на податоци и мора да останат конзистентни. Одржувајте ги трансакциите кратки: не држете заклучувања на базата на податоци додека повикувате платежен портал или испраќате е-пошта.
Надворешните нуспојави воведуваат друг проблем. Клиентот може повторно да се обиде по истек на времето дури и кога серверот го завршил првичното барање. За важни крајни точки за креирање или дејства, поддржете клуч за идемпотентност. Зачувајте го клучот со исходот од барањето и вратете го првичниот резултат кога повторно се доставува истиот клуч. Така повторниот мрежен обид од потенцијално дуплирано наплатување или дуплирана нарачка се претвора во предвидлива операција.
За асинхрона работа, евидентирајте го наменетиот настан заедно со трансакцијата, па обработете го одделно. Така се избегнува кревкиот образец на потврдување промена во базата на податоци и надевање дека веднаш следниот мрежен повик ќе успее. Работникот може безбедно да се обидува повторно, со видливост во неуспесите и дефинирана патека за операции што бараат рачно внимание.
Планирајте ги пребарувањата пред да станат инциденти
Перформансите ретко се решаваат со додавање кеш на нејасно пребарување. Започнете со образецот на пристап. Која листа му е потребна на клиентот? Како се филтрира и сортира? Кои полиња навистина се прикажуваат? Колку поврзани записи се вчитуваат по ставка?
Пагинацијата треба да биде експлицитна и ограничена. Пагинацијата со поместување е едноставна за многу административни екрани. За големи множества податоци што често се менуваат, пагинацијата базирана на курсор може да обезбеди постабилно поминување кога редоследот на сортирање е добро дефиниран. Кој пристап и да го изберете, документирајте ги редоследот и максималната големина на страница.
Внимавајте на случајни N+1 пребарувања во код управуван од ORM: едно пребарување за листа, па друго пребарување за релацијата на секоја ставка. Однапред вчитајте ги релациите што ги бара крајната точка, изберете само потребни колони и додајте индекси што поддржуваат реални комбинации на филтрирање и сортирање. Индексите не се украси; секој има трошоци за запишување и складирање, па треба да одговори на забележана потреба од пребарување.
Направете го распоредувањето намерно здодевно
Docker може да ги направи локалните средини и средините за распоредување поповторливи, но сликата на контејнер не ја отстранува оперативната одговорност. Чувајте ја конфигурацијата надвор од сликата, извршувајте миграции на базата на податоци како контролиран чекор при распоредување и осигурете се дека апликацијата може да започне само со конфигурацијата што навистина ѝ е потребна.
Проверките на здравјето треба да разликуваат „процесот работи“ од „апликацијата може да опслужува сообраќај“. Дневниците треба да бидат доволно структурирани за да поврзат барање, грешка и задача во позадина без евидентирање тајни или чувствителни товари. Метриките и трасирањето се највредни кога одговараат на практични прашања: која крајна точка е бавна, која зависност откажува и дали повторните обиди се зголемуваат.
Скалирајте ги одлуките пред инфраструктурата
Најсилната API архитектура не е онаа со најмногу обрасци. Таа ги зачувува јасните договори, ги штити важните промени на состојбата и му дава на следниот развивач очигледно место за додавање на следната можност.
CRUD е корисен јазик за перзистенција. На амбициозните системи им е потребен побогат јазик за однесување. Кога API-то зборува преку деловни дејства, ја содржи својата сложеност зад намерни граници и го третира неуспехот како нормален услов за дизајн, може да прерасне од корисен интерфејс во сигурна инфраструктура.