ИТ развој

Designing Maintainable APIs: The Art of Future-Proofing

Дизајнирање API-ја што лесно се одржуваат: Уметноста на обезбедување долгорочна отпорност

API е ветување дадено во код. Штом друга услуга, мобилна апликација, партнер или frontend ќе зависи од него, секое име на поле, статусен код и граничен случај станува дел од тоа ветување. Тешкиот дел не е изложувањето податоци. Тој е зачувувањето јасност додека барањата, тимовите и системите неизбежно се менуваат.

Подготвеноста за иднината не значи предвидување на секое барање за функционалност. Таа значи дизајнирање граници што можат да апсорбираат разумни промени без да го принудат секој потрошувач да реагира. API-јата што лесно се одржуваат ја прават вообичаената патека очигледна, неуспесите разбирливи, а подоцнежните одлуки поевтини.

Почнете со стабилни концепти, а не со табели од базата на податоци

Честа кратенка е редовите од базата на податоци директно да се претворат во JSON одговори. Тоа изгледа ефикасно сè додека не се смени шемата, некоја колона нема несреќно име или внатрешните податоци не треба да се комбинираат во покорисен ресурс. Во тој момент, API-то случајно станало јавен адаптер за база на податоци.

Моделирајте го API-то околу концептите што им се потребни на клиентите. Ресурс за нарачка наменет за клиент може да вклучува идентификатор, статус, вкупни износи и ставки, дури и ако тие вредности доаѓаат од неколку табели или услуги. Внатрешниот распоред на складирањето треба да остане слободен да еволуира.

Ова раздвојување е особено вредно во PHP апликации, каде ORM моделот може да биде практичен, но не треба автоматски да ја дефинира формата на одговорот. Користете експлицитни трансформатори на ресурси, DTO-а или сериализатори. Тие го прават договорот видлив во кодот и обезбедуваат едно место за справување со форматирање, изоставени полиња и одлуки за компатибилност.

function orderResponse(Order $order): array
{
    return [
        'id' => (string) $order->id,
        'status' => $order->status,
        'total' => [
            'amount' => $order->totalAmount,
            'currency' => $order->currency,
        ],
    ];
}

Тој мал слој може да спречи идната миграција да стане настан што го нарушува API-то.

Направете ги договорите доволно прецизни за да им се верува

Потрошувачите не треба да мораат да одгатнуваат однесување преку обиди и грешки. Дефинирајте што значи едно поле, дали може да отсуствува или да биде null, кои вредности се дозволени и што се случува кога барањето не успее. Доследноста е поважна од стилската совршеност.

На пример, изберете едно претставување за временските ознаки и користете го насекаде. Одлучете дали незадолжително поле се изоставува или се враќа како null, потоа документирајте го и зачувајте го тој избор. Користете пагинација доследно низ endpoint-ите за колекции. Клиент што може да се потпре на познати обрасци е полесен за изработка и побезбеден за одржување.

Користете ги грешките како дел од производот

Одговорите за грешки често се дизајнираат последни, иако се меѓу најкористените делови на API-то за време на интеграцијата и оперативната работа. Корисна грешка му кажува на клиентот што не успеало, каде е практично, и дали повторниот обид може да помогне.

{
  "error": {
    "code": "validation_failed",
    "message": "One or more fields are invalid.",
    "details": {
      "email": ["Must be a valid email address."]
    }
  }
}

Чувајте ги пораките безбедни за клиентите одделно од внатрешната дијагностика. Продукцискиот одговор не треба да открива SQL изрази, траги од стек, акредитиви или детали за имплементацијата. Техничкиот контекст евидентирајте го внатрешно, идеално со идентификатор на барање или корелација што персоналот за поддршка може да го користи за следење на настанот.

Дизајнирајте за дополнителни промени

Најбезбедните промени на API се дополнителни. Додавањето незадолжително поле обично е полесно за клиентите да го толерираат отколку преименување поле, менување тип или менување на значењето на постоечка вредност. „Обично“ е важно: некои строги валидатори на клиенти отфрлаат непознати својства, па важните интеграции и понатаму заслужуваат тестирање на договори и јасна комуникација за изданијата.

Пред да измените воспоставен endpoint, поставете практично прашање: дали новото однесување може да постои покрај старото однесување извесен период? Често може.

  • Додајте ново поле наместо да пренамените старо.
  • Воведете нов endpoint кога значењето на ресурсот навистина се променило.
  • Поддржете експлицитна верзија само кога компатибилноста не може чисто да се зачува.
  • Поставете и соопштете временска рамка за застарување пред да отстраните поддржан договор.

Верзионирањето е корисно, но не е замена за внимателен дизајн. Нова верзија за секое мало приспособување создава паралелни системи што сите мора да се документираат, обезбедуваат, надгледуваат и на крај да се повлечат. Претпочитајте стабилна семантика и дополнителна еволуција; зачувајте ги главните верзии за значајни некомпатибилности.

Држете ги транспортот, доменската логика и постојаното складирање одделени

Одржливоста брзо опаѓа кога контролерот валидира влез, извршува деловни правила, ја пребарува базата на податоци, повикува услуги од трети страни, форматира одговор и обработува повторни обиди во еден метод. Таа структура може да функционира за ранен endpoint, но ги прави подоцнежните промени ризични бидејќи одговорностите се испреплетени.

Поздрав тек на backend-от е едноставен: валидирајте и авторизирајте на границата, предадете нормализирана команда на апликациската или доменската логика, зачувајте преку фокусиран инфраструктурен код и форматирајте го излезот на работ. Точната архитектура може да варира. Клучот е секој слој да има јасна одговорност.

Трансакциите со базата на податоци ја заслужуваат истата дисциплина. Одржувајте ги тесни и избегнувајте бавни мрежни повици додека трансакцијата е отворена. Ако операцијата мора да активира надворешен несакан ефект, трансакциски запишете го наменетиот настан и обработете го одделно. Ова ја намалува веројатноста да му кажете на клиентот дека дејството успеало, додека базата на податоци и надолниот систем не се согласуваат.

Перформансите се прашање на договорот

API што е точен, но непредвидливо бавен, тешко е да се користи со доверба. Работата на перформансите треба да почне со разумни форми на одговори и однесување на пребарувањата, а не со прерано кеширање.

Endpoint-ите за колекции имаат потреба од пагинација, ограничени филтри и намерно сортирање. Избегнувајте стандардно вчитување на цели графови од поврзани податоци. Во PHP апликации поддржани од релациони бази на податоци, внимавајте на N+1 пребарувања: списокот може да изгледа брз во развојната средина, но при реален сообраќај да издаде едно дополнително пребарување за секоја вратена ставка. Вчитувајте ги потребните врски намерно, мерете ги пребарувањата и враќајте само она што го ветува endpoint-от.

Кеширањето може да помогне, но додава правила за поништување и доследност. Користете го таму каде што податоците често се читаат, се менуваат предвидливо и однесувањето со застарени одговори е прифатливо. Кеш без стратегија за сопственост и истекување не е само оптимизација; тој е уште еден систем што треба да се управува.

Оперативниот дизајн припаѓа во дискусијата за API-то

Распоредувањето не треба случајно да го менува однесувањето на API-то. Контејнеризираните услуги имаат корист од експлицитна конфигурација, непроменливи артефакти за изградба, здравствени проверки што ја одразуваат подготвеноста и тајни специфични за средината доставени надвор од сликата. Docker го прави пакувањето повторливо, но не ја отстранува потребата од планирање миграции на базата на податоци, стратегија за враќање назад и набљудливост.

За endpoint-и за запишување, размислете за истекувања на времето и повторни обиди. Клиентите, прокси-серверите и работниците за задачи сите можат повторно да побараат барање. Ако создавањето плаќање, нарачка или сметка не е идемпотентно, минлив неуспех може да создаде дупликатна работа. Каде што е соодветно, прифатете клуч за идемпотентност, зачувајте го неговиот исход и вратете го оригиналниот резултат за повторено барање.

Конечно, тестирајте го договорот, не само имплементацијата. Единечните тестови ги штитат деловните правила; интеграциските тестови го проверуваат однесувањето на базата на податоци и рамката; тестовите на договори потврдуваат дека клиентите ги добиваат полињата, статусните кодови и грешките што ги очекуваат. Овие тестови ја претвораат компатибилноста од надеж во проверено својство на секое издание.

Долгорочниот поглед

API-јата што лесно се одржуваат ретко се најгенијалните. Тие се оние чии правила може јасно да се објаснат, чии неуспеси може смирено да се дијагностицираат и чија следна промена не бара кризен состанок. Третирајте го API-то како трајна граница на производот наместо како тенка рута до табела. Тој начин на размислување остава простор системот да расте без секој потрошувач да плаќа за неговиот раст.

Портрет на автор на блогот

Mihajlo

Јас сум Михајло - развивач поттикнат од љубопитност, дисциплина и постојаната желба да создадам нешто значајно. Споделувам увиди, упатства и бесплатни услуги за да им помогнам на другите да ја поедностават својата работа и да растат во постојано развивачкиот свет на софтверот и вештачката интелигенција.