Комментарии 19
Спасибо за статью! Вот просто ощущение, что в наши кодовые массы смотрели :(
Ловите 11 прикол из вк-бот-апи: тела ответов всех эндпоинтов копируется в utf8. Кроме одного, который грузит файл на облако. Там ответ в windows1251. В документации этого нет
Не знаю, актуально ли сейчас, но я попался на это в 22 году, и видел статьи на эту тему, датирующиеся 18 годом
это уже задел на "# 20 ошибок API" :)
спасибо !
Так а чем сложные фильтры в get отправлять-то?
POST /api/internal/equipment
1) в этом пункте больше акцент на то, что такое именование вводит в заблуждение тк стандартная практика POST ../equipment подразумевает именно создание единицы техники
2) с другой стороны часто когда решают, что «фильтр сложный, в query-параметры не влезет» не знают, что на самом деле вполне может влезть тк ограничение длины URL ~8000 символов (в зависимости от браузера/сервера) [хотя в некоторых редких случаях 2000символов] т.е. во многих случаях вполне можно было и GET использовать
3) и в самом крайнем варианте, если фильтр реально сложный и большой, то
можно использовать POST /api/equipment/search с JSON в теле.
НО явно добавить /search чтобы именование не вводило в заблуждение.
Так делают Elasticsearch, Google Cloud API, Stripe. Это нормальная практика, но вариант все таки крайний
Если фильтров, особенно обязательных, очень много, то есть риск не уложиться в длину урла. Но это прям нужно постараться. Даже если уложишься, то сама строка с урлом выглядит как мусор, и этот мусор сложно повторить руками, если нужно быстро набрать, например. Плюс, если в фильтрах есть массивы или словари, то с ними отдельная боль. Не все форматы их передачи и не везде поддерживаются, тут нужно прям запариться чтобы объяснить чего ты ждёшь не сервере и как это передавать, и обязательно кто-то из клиентов затупит, да и сам наверняка тупить местами будешь.
Я на такие случаи готовлю отдельный урл, который принимает post с фильтрами в теле, шифрую тело в одну строку и эту строку выдаю клиенту как ответ со статусом 201. Теперь этот фильтр он может передать в строке гет запроса к целевому ресурсу, а сервер строку расшифрует и получит фильтры. Да, это всё ещё некрасивая огромная строка урла, плюс один дополнительный запрос к фильтру (откровенно, это решается шифрованием на клиенте), но такой способ идеально поддаётся документированию и не требует лишних телодвижений чтобы разъяснить клиенту как ему эти фильтры форматировать.
А почему просто не сериализовать на клиенте? Сериализация намного проще шифрования. Шифрование вообще избыточно в этом случае, ведь данные в любом случае передаются "в открытую" вначале. На мой взгляд, это уже сильный оверхед только ради красивой документации. При медленном интернете (что особенно актуально сейчас) это будет боль...
Да, могу согласиться с каждым словом. Как всегда, вопрос не в том, что правильно и что идеально подходит, а в том, на какие компромиссы мы можем пойти для получения требуемого результата.
Зашифровать я имел ввиду не в плане зашифровать с точки зрения криптографии, а в плане превратить в строку, которую удобно скопировать и вставить в урл. Тот же urlBase64 вполне подойдёт.
Ну и, на мой взгляд, чаще так бывает, что лучше хорошая дока и небольшой оверхэд, чем дока, для которой нужна отдельная дока, и отсутствие оверхэда, от которого ни холодно ни жарко.
просто для base64, мне кажется, эндпоинт всё-таки избыточен... В доке (в том же сваггере) можно написать, что "это поле принимает base64". Можно даже в названии параметра это указать: "searchQueryBase64". Вам же по-любому нужно будет это указать)) всё равно есть промежуток между сериализацией и отправкой итогового запроса
В любом случае, очень круто, что столько внимания уделяется документации
RFC 9110 просто существует...
Хорошая статья. Но хотелось бы рассмотреть тему с другой стороны.
HTTP коды не тоже самое что бизнес-коды.
HTTP методы не равны бизнес-методам.
Поэтому REST хорошо, а RESTful (в обычном пониманиии: GET -Получение, POST- Создание, PUT/PATCH - Обновление, DELETE - Удаление) это плохо.
Идемпотентность - это бизнес правило. Сейчас get /users/123 вернет одно, а через 5 минут другое. Или счетчик какой-то увеличится.
Конечно, неперехваченная ошибка - это 500, не авторизированный запрос - это 401, нет прав - 403, нет страницы - 404.
Остальное - обсуждается (или ставится не вами, например,таймаут). Обычно это 400 Bad Request.
PS. и на вентилятор, проходилось посылать/принимать даные в body для get, и в query-string для post. А еще и в header'е.
А почему RESTful - плохо? Да, всё, что Вы перечислили до этого, имеет место быть. Но это не мешает существовать корректному RESTful)
P.S. у GET методов нет body (или тут имеется ввиду не метод, а "суть" - получение данных?)
Правильней было бы так сформулиривать - требование следовать ему всегда/везде - это плохо.
имхо, есть только один паттерн - здравый смысл. но это слишком абстрактно и плохо формализуется. А restful, solid, clean code и иже с ними - нужно применять только там, где нужно (сорри за тавтологию)
если формировать HTTP request ручками (т.е. на низком уровне) - то есть и query string, и body, и header. А HTTP verb можно любой подставить.

# 10 ошибок API