ИТ развој

Beyond the Framework: Building Maintainable APIs That Last

Надвор од рамката: Градење одржливи API-ја што траат

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

Рамката никогаш не била проблемот. Проблемот е да ѝ се дозволи да стане местото каде што живее секоја одлука.

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

Ставете ги деловните одлуки зад стабилни граници

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

Во PHP, ова често значи преместување на значајното однесување во апликациски сервиси или класи фокусирани на доменот. Имињата се помалку важни од раздвојувањето: кодот што изразува деловни правила не треба директно да зависи од објекти за барања или JSON одговори.

final class PlaceOrder
{
    public function __construct(
        private OrderRepository $orders,
        private InventoryGateway $inventory
    ) {
    }

    public function handle(PlaceOrderCommand $command): Order
    {
        $this->inventory->reserve($command->items);

        $order = Order::place(
            customerId: $command->customerId,
            items: $command->items
        );

        $this->orders->save($order);

        return $order;
    }
}

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

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

Дизајнирајте ги одговорите како договори, а не како снимки од базата на податоци

Директното изложување на модел е практично сè додека моделот не се промени. Колоните во базата на податоци се оптимизирани за складирање и внатрешни операции; API одговорите се ветувања дадени на клиентите. Тоа се различни грижи.

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

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

Направете ги одговорите при неуспех предвидливи

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

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

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

Користете ја базата на податоци како партнер

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

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

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

Претпоставете дека барањата ќе се повторат

Мрежите откажуваат откако серверот веќе обработил барање. Корисниците кликнуваат двапати. Работниците за задачи може да се обидат повторно по истек на време. За крајни точки што ја менуваат состојбата, идемпотентноста често е разликата меѓу инцидент од кој може да се закрепне и дуплирани наплати, нарачки или известувања.

Клучот за идемпотентност му дава на серверот начин да препознае повторена намера. Зачувајте го клучот со резултатот од операцијата, соодветно ограничете го на повикувачот и вратете го оригиналниот резултат за совпаѓачко повторување. Бидете прецизни за однесувањето при конфликт: повторното користење на истиот клуч со материјално различно барање не треба тивко да создаде втора операција.

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

Направете го распоредувањето намерно досадно

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

Одржувајте ја runtime сликата фокусирана: инсталирајте само што ѝ е потребно на апликацијата, експлицитно стартувајте го наменетиот процес и осигурете се дека контејнерот може да започне од чиста околина. Миграциите на базата на податоци треба да бидат намерен чекор при распоредување, а не случаен несакан ефект од стартувањето на секој веб-процес. Миграција што заклучува голема табела или препишува постојни податоци има потреба од истата проверка како и апликацискиот код.

Евидентирањето, здравствените проверки и истеците на време исто така припаѓаат во дизајнот. Структурираните логови со идентификатори на барање или корелација ги прават неуспесите проследливи низ HTTP обработувачите и работниците. Истеците на време спречуваат исцрпените ресурси да рашират прекин во надолен систем низ целата услуга. Здравствените проверки треба да покажат дали процесот може да ја извршува својата наменета улога, наместо едноставно да докажат дека порта е отворена.

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

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

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

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

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

Mihajlo

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