• Книга: проектирование API
    +1

    Действительно, пропущен id в ответе search. поправлю, спасибо.

  • Ещё 8 правил проектирования API
    0

    Так вот чтобы никого не оскорблять, должен быть явный пункт «предпочту не говорить» вместо неявного null.

  • Ещё 8 правил проектирования API
    0

    Я, если честно, устал спорить с утверждением «10 десятичных цифр лучше чем 32 шестнадцатеричные». Окей, можете форкнуть репозиторий и исправить в своей копии.

  • Так ли токсичен синтаксис Rust?
    –1
    Ну да, очень интересное: str[i..j].chars().count()

    thread 'main' panicked at 'byte index 1 is not a char boundary
    Прекрасный способ отстрелить себе ногу.


    Чтобы работать с utf-8 строками без лишних конвертаций, используя заложенные в utf-8 возможности. Очевидно же.

    Да каких конвертаций? Что станет хуже, если str[i] указывает на char, а не byte?

  • Так ли токсичен синтаксис Rust?
    –2

    Остаётся только один вопрос — зачем?
    В мире нет ни одной реальной задачи, в которой доступ к уникодной строке требуется побайтно. В Расте банально вычислить количество уникодных символов между двумя байтовыми позициями — интересное такое занятие с неопределённым результатом.

  • Так ли токсичен синтаксис Rust?
    –5

    … поэтому будем массив байтов давать, ага.
    Если разбить уникодную строку по графеме, получатся хотя бы две валидные уникодные строки, в отличие от.

  • Так ли токсичен синтаксис Rust?
    –3
    Returns the byte index

    Оперировать UTF-8 строкой как массивом уникодных символов невозможно в Rust. Ты можешь оперировать ей как набором указателей на место в буфере, где начинается какой символ.


    В реальной жизни же уметь работать с UTF-8 строкой как с набором байтов не нужно вообще никогда.

  • Ещё 8 правил проектирования API
    0

    А можно примеры продуманных решений в GraphQL? Единственное, что он умеет из списка — возвращать пустые массивы без ошибки.

  • Ещё 8 правил проектирования API
    0

    Так я и пишу, что надо разрабатывать API так, чтобы у вебмакаки не было этой проблемы. Указывать дефолтное состояние чекбокса то бишь. И руки оторвать тому, кто придумал неинициализированное состояние системного чекбокса.

  • Ещё 8 правил проектирования API
    0

    Хинт: если взять последние, ну скажем 6 знаков uuid-а — получится ровно то же самое длинное число. Админки, которые я видел, именно так и делали — последние n знаков показывали, полный uuid за спойлером.

  • Так ли токсичен синтаксис Rust?
    –4

    Лично для меня Rust закончился, когда я осознал, что он не умеет в UTF-8. Совсем. Инженеры просто не подумали, им по традиции наплевать на неанглоязычных пользователей.


    Найти подстроку, вставить подстроку, заменить подстроку, разбить по подстроке — пиши всё сам, итератор по символам к твоим услугам.

  • Ещё 8 правил проектирования API
    0

    Спасибо.

  • Ещё 8 правил проектирования API
    +1

    Последний абзац прочитайте, пожалуйста.

  • Ещё 8 правил проектирования API
    +3

    Вот что меня всегда поражало, можно даже сказать, восхищало, в русскоязычных форумах, так это апломб, с которым дилетанты излагают свою критику.
    С вашего позволения, на сообщения в такой форме я отвечать не буду.

  • Ещё 8 правил проектирования API
    0

    Так ровно это REST и предполагает ;) Принцип code-on-demand.
    Следующая глава будет про интерфейсы, а вот через неделю планирую взяться за главу ‘Deconstructing the REST myth’

  • Ещё 8 правил проектирования API
    +1

    Ну как «разработано». Операции «сдвинь элемент массива на n позиций влево» там нет, например. Если б любая предметная логика описывалась просто правкой JSON-ов, я бы давно помер с голода.

  • Ещё 8 правил проектирования API
    0

    Ну и не могу не отметить, что поле, принимающее три значения — true, false и null — это какой-то кадавр, независимо от наличия в языке удобных конструкций для работы с такой псевдотроичной логикой.

  • Ещё 8 правил проектирования API
    +2

    API (как и контрактное программирование в целом) нужен в том числе для того, чтобы разработчики клиента были свободны в выборе технологий и не зависели от моих личный желаний и предпочтений.

  • Ещё 8 правил проектирования API
    0

    Не очень понимаю, что вы этим хотели сказать.


    Хороший тон при разработке API — использовать для идентификаторов сущностей глобально уникальные строки, либо семантичные (например, "lungo" для видов напитков), либо случайные (например UUID-4). Это может чрезвычайно пригодиться, если вдруг придётся объединять данные из нескольких источников под одним идентификатором.
  • Ещё 8 правил проектирования API
    0
    Set all the other bits to randomly (or pseudo-randomly) chosen values.
    https://tools.ietf.org/html/rfc4122#page-14

    Попробуйте взять другой генератор энтропии.

  • Ещё 8 правил проектирования API
    0
    Я взял uuid сгенеренные по RFC.

    Согласно какому RFC, если не секрет?

  • Ещё 8 правил проектирования API
    +1
    Для пустых результатов поиска часто используют 204 No Data. Это как 404, но без ошибки)

    204 подразумевает пустое тело ответа — а значит, ничего полезного (например, предложение исправить опечатку) в нём не передать. Плюс пустое тело — невалидный json, клиентам придётся обрабатывать его отдельно.


    Если программист клиента не может отличить null от false, ну так может гнать такого из профессии?

    Если разработчик API предлагает отличать null от false, может его нужно гнать из профессии?
    Популярным API чисто статистически будут пользоваться тысячи, может десятки тысяч разработчиков. Они будут допускать ошибки, а результатом этих ошибок будут проблемы реальных людей. Сознательно провоцировать ошибки, мол, нечего джунов нанимать — не очень конструктивная позиция.

  • Ещё 8 правил проектирования API
    +1
    Вот несколько UUID попробуйте понять есть ли среди них одинаковые:

    Во-первых, необходимо использовать рандомные идентификаторы, похожих не будет.
    Во-вторых, решительно не понимаю, в чем преимущество числовых идентификаторов. Они удобны, пока их мало. Когда счет на миллионы-миллиарды идёт — точно так же поди разбери, в каком знаке отличие.

  • Хабрастыд-2020
    +25

    В конце не хватает приписки «один я д'Артаньян».

  • Ещё 8 правил проектирования API
    0

    Заголовки я поправил, а как спойлеры делать в новом редакторе я не нашёл.

  • Ещё 8 правил проектирования API
    +2

    Выше правильно ответили. Но должен заметить, что REST никак не регламентирует такие вопросы, это семантика самого HTTP.

  • Ещё 8 правил проектирования API
    +3

    48 полей — это уже проблема само по себе, такие объекты надо декомпозировать.
    Но вообще с т.з. разработчика клиента как раз удобнее все 48 посылать, чем выбирать изменившиеся.


    Хорошая статья, хочу больше.

    Дык собсно https://twirl.github.io/The-API-Book/docs/API.ru.html#chapter-11

  • Постановка проблемы обратной совместимости
    0

    Я в главе с советами даже хотел использовать WinAPI как пример плохого дизайна


    HWND hwnd = CreateWindowEx(
        0,                              // Optional window styles.
        CLASS_NAME,                     // Window class
        L"Learn to Program Windows",    // Window text
        WS_OVERLAPPEDWINDOW,            // Window style
    
        // Size and position
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    
        NULL,       // Parent window    
        NULL,       // Menu
        hInstance,  // Instance handle
        NULL        // Additional application data
        );

    Ну кто, скажите на милость, мешал размер и положение в одну структуру объединить, зачем 4 отдельных параметра? Зачем два разных window style?


    Но потом я понял, что хорошего примера не могу найти, все визуальные либы примерно одинаково рукожопно сделаны.

  • Постановка проблемы обратной совместимости
    0

    Да, Win API, с одной стороны, хороший пример — ребята продолжают волочь этот крест уж не знаю, лет 30 поди.
    С другой — само API, конечно, отвратительнейшее. Функции с 12 аргументами и прочие чудеса индусского кода.

  • Проблема статус-кодов HTTP
    0

    Так ничем, я как раз и говорю, что в идеальном мире что залогировано (какая причина ошибки), то и передано должно быть в ответе (заголовком ли, боди, неважно).

  • Проблема статус-кодов HTTP
    0
    А как RFC должно с этим помогать?

    Например вот так:


    От этой ошибки клиентам нет абсолютно никакого толку, если только в ответе не указано, какое конкретно поле имеет недопустимое значение — и вот как раз именно это стандарт и не стандартизирует!

    или вот так:


    Самый очевидный пример — это ошибка 401 Unauthorized: по спецификации она обязана сопровождаться заголовком WWW-Authenticate — чего, в реальности, конечно никто не делает, и по очевидным причинам, т.к. единственное разумное значение этого заголовка — Basic (да-да, это та самая логин-парольная авторизация времён Web 1.0, когда браузер диалоговое окно показывает). Более того, спецификация в этом месте расширяема, никто не мешает стандартизовать новые виды realm-ов авторизации — но всем традиционно всё равно.

    На прочие ваши вопросы также есть ответы в тексте.


    Отдельно хотелось бы отметить, что:


    Я не представляю, если бы на каждую ошибку в НТТР-заголовке был бы свой код ошибки — был бы вообще протокол НТТР юзабелен сколь-нибудь.

    Тем не менее, в HTTP полно ошибок на невалидное значение одного конкретного параметра запроса — 405, 411, 414, 416, например. HTTP юзабелен?

  • Проблема статус-кодов HTTP
    0

    Что изменилось-то от этого? Разнородные ошибки все равно под одним кодом.

  • Проблема статус-кодов HTTP
    +1

    «Заказ» = «переведи корзину из статуса драфт в статус коммит». Эта операция возможна, только если клиент обладает полной информацией о статусе ресурса «корзина».
    Ну и вообще, стандарт недвусмысленно заявляет, что


    This code is used in situations where the user might be
    able to resolve the conflict and resubmit the request. The server
    SHOULD generate a payload that includes enough information for a user
    to recognize the source of the conflict.

    что автоматически делает 409 дефолтным кодом для ошибок в бизнес-логике.

  • Проблема статус-кодов HTTP
    0
    Это абсолютно одно и то же.
    Есть ресурс «корзина» с каким-то id. В корзине лежит N предметов по определённой цене. У корзины есть ревизия, которую может менять как внутреннее, так и внешнее API.
    Цена предмета изменилась → пришёл callback → ревизия корзины увеличилась. Клиент получит 409.
    От того, что «ревизия» корзины меняется не по callback-у, а по запросу, смысл ошибки не меняется.
  • Проблема статус-кодов HTTP
    +1
    > Так что всё-таки прямое назначение HTTP — прикладное, а не транспортное.

    Не могу не отметить, что сама модель OSI является сферическим конём в вакууме, описывающим какой-то выдуманный сетевой стек (достаточно сказать, что TCP/IP в него не ложится, т.к. формально и TCP, и IP являются протоколами транспортного уровня). В данном случае прикладной уровень надо делить на два — прикладной уровень протокола (HTTP) и прикладной уровень бизнес-логики.
  • Проблема статус-кодов HTTP
    0
    Во-первых, 409 подходит под все описанные кейсы. Он означает буквально следующее: пока ты собирал корзину, кто-то другой модифицировал разделяемый ресурс (остаток товара, цену, количество текущих заказов), и теперь операция невозможна до разрешения конфликта.

    Во-вторых, предлагаемые вами решения не решают проблему, а усугубляют. Теперь под `403` будут свалены и ошибки авторизации (кулхацкеры, которые пытаются найти дырки в безопасности) и чистая бизнес-логика (пользователю не разрешено иметь больше 3 одновременных заказов). Под `401` теперь живут и те же кулхацкеры, и протухшие токены. Ну и замена 409 на 422 ничего не меняет в постановке задачи.

    > Если авторизация выполняется средствами HTTP и запрос «запрещён» именно из-за авторизации, то надо отвечать кодом 401.

    Авторизация не может выполняться средствами HTTP, т.к. авторизация — это логическая процедура. Вероятно, вы путаете авторизацию с аутентификацией.

    > Код 403 из-за авторизации возвращают только тогда, когда авторизация делается не средствами HTTP. Т.е. не через заголовок Authorization или другие заголовки, URL или параметры в теле запроса. А например авторизация по IP-адресу или SSL сертификату.

    Вы точно читали стандарт?


    The 403 (Forbidden) status code indicates that the server understood
    the request but refuses to authorize it. A server that wishes to
    make public why the request has been forbidden can describe that
    reason in the response payload (if any).

    If authentication credentials were provided in the request, the
    server considers them insufficient to grant access. The client
    SHOULD NOT automatically repeat the request with the same
    credentials. The client MAY repeat the request with new or different
    credentials. However, a request might be forbidden for reasons
    unrelated to the credentials.


    В отношении 403 RFC не предписывает вообще ничего. Креденшалы могут присутствовать в любом виде.

    А вот 401 как раз регламентирован другим RFC tools.ietf.org/html/rfc7235
    Формально 401 можно использовать если, и только если авторизация устроена согласно этому RFC. Я, кстати, написал об этом в тексте явно, вот здесь: «Многие разработчики просто не читают спецификации ¯\_(ツ)_/¯. Самый очевидный пример — это ошибка 401 Unauthorized: по спецификации она обязана сопровождаться заголовком WWW-Authenticate — чего, в реальности, конечно никто не делает» и далее.

    > Логировать важные ошибки непосредственно в самом приложении и настроить мониторинг этих логов, а не только смотреть на access-логи, например nginx-а, который стоит перед приложением. Или использовать access-логи, которые пишет само приложение — ему то ведь известны все детали и оно может добавить их в свои access-логи.

    Вы сейчас пересказываете мою же статью. Я начал с того, что не существует решения, которое ошибки веб-приложения агрегирует по семантике, а не по статус-кодам, его надо писать самому. И уж если писать, то зачем исключать эти данные из HTTP-ответа? Кому станет хуже, если ошибка есть *и* в логе, *и* в заголовке ответа?
  • Проблема статус-кодов HTTP
    0
    Во-первых, грань, где здесь «бизнес»-логика, а где не бизнес — весьма тонка. Тот же 403 как пример.
    Во-вторых, конечно, выдавать клиенту наружу детали 500-ки почти никогда не нужно. А вот 400-ки редко лишними бывают.
    В-третьих, один из пойнтов следующий: мониторинг все равно нужен, и мониторинг как-то группировать ошибки все равно должен, одних подробных логов недостаточно.
  • Проблема статус-кодов HTTP
    0
    > Хотя есть и чисто технические косяки в плане понимания предназначения конкретных статусов ответа и для чего они подходят, а для чего — нет.

    Я бы оценил конкретные примеры.
  • Проблема статус-кодов HTTP
    0
    > А каких действий вы ожидаете от абстрактной прокси, в ответ, например, на ошибку, когда клиент передал значение выходящее за пределы допустимого?

    Ну, например, на 429 и на разные виды 403-х вполне можно ожидать реакции от прокси.

    > Не вижу пока причин придумывать что-то совершенно новое.

    Так вроде никто и не выдумывает ничего нового.

    > Если тут 404 заменить на 200, то ситуация кардинально не поменяется. Поэтому в той ситуации, которую автор «разгребал», в большей степени виноват не «дизайн» кодов, а сервис, который ошибочно возвращает не те коды.

    А если б 400, то поменялась бы. Проблема была в том, что разработчики не в курсе, что 400 и 404 по-разному кэшируются.

    > Я за несколько лет разработки так называемого RESTful API не встретил случая, когда не получилось подобрать стандартный HTTP-статус для классификации конкретной ситуации.

    Это выглядит очень странно. Для всей бизнес-логики в номенклатуре HTTP-кодов по сути есть один 409, которым приходится покрывать кучу разных кейсов. На примере банального интернет-магазина:
    * заказ уже был создан — 409
    * заказ нельзя создать, потому что не разрешается иметь более N заказов одновременно — 409
    * заказ нельзя создать, потому что товар в корзине закончился — 409
    * заказ нельзя создать, потому что цена товара изменилась — 409
    Скажете, эти кейсы не надо различать?

    Ну или вот абсолютно практический пример: протухание токенов. В структуре 403-х ошибок какая-то доля — токены с истекшим сроком жизни. Я разгребал факап, когда на клиенте неправильно обновлялись токены. На фоне потока 403-х никто эту проблему не видел. Она копилась-копилась потихоньку, а потом набралась критическая масса, и пришлось срочно хотфиксить.

    > Гораздо проще в том месте где случилась ошибка, отправить подробности о ней в логи или в сервис типа Sentry, а не пытаться «угадать» ошибку по HTTP-ответу, предназначенному в первую очередь для клиента, и только во вторую — для мониторинга.

    Так а как оперативный мониторинг-то строить? На примере тех же 403-х — как сделать, чтобы мониторинг начинал орать, если превышено критическое значение протухающих токенов?
  • Проблема статус-кодов HTTP
    0
    > Как именно «большое количество ПО» должно трактовать какой-нибудь отдельно взятый HTTP API? Что конкретно имеется ввиду?

    Имеется в виду следующее: когда вы пишете proxy_pass в конфигурации nginx — nginx начинает как-то трактовать стандарт. Он не пересылает запрос как есть. То же касается, скажем, используемого на клиенте фреймворка работы с сетью, и особенно API Gateway-ев, без которых микросервисную архитектуру не построишь.

    > Не существует такого разделения. В чем именно состоит разница между REST 2000 и REST 2008?

    В 2000 Фьелдинг написал абстрактно. Под «hypermedia as the engine of application» можно много чего понимать. Собственно так и вышло — каждый немедленно истрактовал REST в свою степь.