Рекомендации по устранению ошибок в RESTful API


Каковы наилучшие методы возврата кодов состояния HTTP в RESTful API? Я использую Laravel 4 для своего PHP-фреймворка.

В случае ошибки следует ли мне использовать

return Response::json('User Exists', 401);

Или

Включить флаг для success

return Response::json([
    'success' => false,
    'data' => 'User Exists'],
    401
);

Или

Используйте 200 вместо 4xx, полагаясь на success, чтобы определить, есть ли ошибка

return Response::json([
    'success' => false,
    'data' => 'User Exists'],
    200
);

И в случае успеха и отсутствия необходимости возвращать какие-либо данные, вы все равно возвращаете что-нибудь?

Код PHP API

public function getCheckUniqueEmail() {
    // Check if Email already exist in table 'users'
    $uniqueEmail = checkIfEmailExists();

    // Return JSON Response
    if($uniqueEmail) {
        // Validation fail (user exists)
        return Response::json('User Exists', 401);
    } else {
        // Validation success
        // - Return anything?
    }
}
Author: Nyxynyx, 2013-03-24

3 answers

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

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

Другая часть: Как коды состояния HTTP могут помочь различать определенные состояния ошибки (и успеха)?

Эта последняя часть на самом деле сложнее, чем может показаться. Есть очевидные случаи, когда 404 используется для указания "не найдено". И 500 за любые ошибки на стороне сервера.

Я бы не использовал статус 401, если только я действительно не хочу, чтобы операция прошла успешно, если присутствуют учетные данные для аутентификации HTTP. 401 обычно запускает диалоговое окно в браузере, что плохо.

В случае, если ресурс уникален и уже существует, статус "Конфликт 409" кажется подходящим. И если создание пользователя завершится успешно, статус "201 создано" тоже будет хорошей идеей.

Обратите внимание, что существует намного больше кодов статуса, некоторые из них связаны с расширениями протокола HTTP (например, DAV), некоторые полностью нестандартизированы (например, статус "420 Улучшит ваше спокойствие" из API Twitter). Взгляните на http://en.wikipedia.org/wiki/List_of_HTTP_status_codes чтобы посмотреть, что использовалось до сих пор, и решить, хотите ли вы использовать что-то подходящее для ваших случаев ошибок.

По моему опыту, легко просто выбрать код статуса и использовать его, но трудно сделать это последовательно и в соответствии с существующими стандартами.

Однако я бы не стал останавливаться на этом только потому, что другие могут пожаловаться. :) Правильное выполнение интерфейсов RESTful само по себе является сложной задачей, но чем больше интерфейсы существуют, тем больше опыта было собрано.

Редактировать:

Что касается управления версиями: Считается плохой практикой добавлять тег версии в URL-адрес, например: example.com/api/v1/stuff Это будет работать, но это нехорошо.

Но прежде всего: как ваш клиент определяет, какое представление он хочет получить, т.Е. Как он может решить получить JSON или XML? Ответ: С заголовком Accept. Он мог бы отправить Accept: application/json для JSON и Accept: application/xml для XML. Он мог бы даже согласиться несколько типов, и именно сервер должен решить, что затем возвращать.

Если сервер не предназначен для ответа с использованием более чем одного представления ресурса (JSON или XML, выбранного клиентом), у клиента действительно нет большого выбора. Но все равно хорошо, чтобы клиент отправил хотя бы "приложение/json" в качестве своего единственного выбора, а затем вернул заголовок Content-type: application/json в ответ. Таким образом, обе стороны ясно дают понять, чего они ожидают от другой стороны, чтобы увидеть контент, подобный.

Теперь перейдем к версиям. Если вы помещаете версию в URL-адрес, вы фактически создаете разные ресурсы (v1 и v2), но на самом деле у вас есть только один ресурс (= URL) с различными способами доступа к нему. Создание новой версии API должно происходить, когда происходит критическое изменение параметров запроса и/или представления в ответе, которое несовместимо с текущей версией.

Поэтому, когда вы создаете API, использующий JSON, вы не разберитесь с общим JSON. Вы имеете дело с конкретной структурой JSON, которая каким-то образом уникальна для вашего API. Вы можете и, вероятно, должны указать это в Content-type, отправленном сервером. Расширение "поставщик" предназначено для этого: Content-type: application/vnd.IAMVENDOR.MYAPI+json сообщит миру, что базовая структура данных - это приложение/json, но именно ваша компания и ваш API действительно говорят, какую структуру ожидать. И это именно то, куда вписывается версия для запроса API: application/vnd.IAMVENDOR.MYAPI-v1+json.

Поэтому вместо того, чтобы помещать версию в URL, вы ожидаете, что клиент отправит заголовок Accept: application/vnd.IAMVENDOR.MYAPI-v1+json, и вы также ответите Content-type: application/vnd.IAMVENDOR.MYAPI-v1+json. Это действительно ничего не меняет для первой версии, но давайте посмотрим, как будут развиваться события, когда в игру вступит версия 2.

Подход с использованием URL-адресов создаст совершенно не связанный набор новых ресурсов. Клиент задастся вопросом, является ли example.com/api/v2/stuff тем же ресурсом, что и example.com/api/v1/stuff. Клиент, возможно, создал некоторые ресурсы с помощью API v1 и сохранил URL-адреса для этого материала. Как он должен модернизировать все это ресурсы для v2? Ресурсы действительно не изменились, они те же самые, единственное, что изменилось, это то, что они выглядят по-другому в версии 2.

Да, сервер может уведомить клиента, отправив перенаправление на URL-адрес версии 2. Но перенаправление не сигнализирует о том, что клиенту также необходимо обновить клиентскую часть API.

При использовании заголовка accept с версией URL-адрес ресурса одинаков для всех версий. Клиент решает запросить ресурс с любой версией 1 или 2, и сервер может быть таким любезным и по-прежнему отвечает на запросы версии 1 ответами версии 1, но все запросы версии 2 с новыми и блестящими ответами версии 2.

Если сервер не может ответить на запрос версии 1, он может сообщить клиенту, отправив HTTP-статус "406 Неприемлемо" (Запрошенный ресурс способен генерировать неприемлемый контент только в соответствии с заголовками Accept, отправленными в запросе.)

Клиент может отправить заголовок "принять" с включенными обеими версиями, что позволило серверу отвечать той, которая ему больше всего нравится, т. Е. умный клиент может реализовать версии 1 и 2 и теперь отправляет обе в качестве заголовка accept и ожидает обновления сервера с версии 1 до 2. Сервер в каждом ответе сообщит, является ли это версией 1 или 2, и клиент может действовать соответственно - ему не нужно знать точную дату обновления версии сервера.

Подводя итог: Для очень простого API с ограниченным, возможно, внутренним, использование даже версии может быть излишним. Но никогда не знаешь, будет ли это правдой через год. Всегда очень хорошая идея включать номер версии в API. И лучшее место для этого находится внутри типа mime, который собирается использовать ваш API. Проверка единственной существующей версии должна быть тривиальной, но у вас есть возможность прозрачно обновить ее позже, не вводя в заблуждение существующих клиентов.

 12
Author: Sven, 2013-03-25 00:31:45

Я бы не стал использовать статус 200 для всего. Это просто сбило бы с толку.

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

Редактировать: Также я настоятельно рекомендую посмотреть этот доклад о Laravel и API разработка:

Http://kuzemchak.net/blog/entry/laracon-slides-and-video

 2
Author: msurguy, 2013-03-24 16:27:50

В Illuminate\Http\Response есть некоторый список кодов состояния HTTP, которые распространяются на Symfony\Component\HttpFoundation\Response. Вы можете использовать это в своем классе.

Например:

use Illuminate\Http\Response as LaravelResponse;
...
return Response::json('User Exists', LaravelResponse::HTTP_CONFLICT);

Это гораздо более читабельно.

 1
Author: msulhas, 2014-03-12 19:25:59