Pull to refresh

Немного о том как организовывать API веб-службы

Reading time 3 min
Views 20K
Возникла задача организовать веб-службу, к которой будут обращать обычные клиенты из браузера и другие веб-службы.

Предположим, я продаю билеты в театр клиентам. Клиентом может быть только агентство, которое имеет свою учётную запись у меня на сервисе. Агентства бывают маленькие, в котором сидит тетёчка и ручками в личном кабинете с помощью барузера осуществляет покупку билета, а также большие, у которых всё автоматизированно. Большие хотят иметь возможность подсоединиться ко мне с помощью API и осуществить покупку.

На билеты можно смотреть цены, предварительно бронировать, выкупать бронь, возвращать купленные и удалять бронь.

Вопрос: как лучше всего организовать API?

Я собираюсь организовывать веб-службу и вообще сервис на Ruby on Rails, но постараюсь излагать общие принципы, там где это возможно обходить реализацию. Я постараюсь конспективно изложить прочтённое в процессе подготовки к созданию API, а также привести ссылки на первоисточники.

Принципы организации API


По архитектуре\идеологии варианты: REST, SOAP, XML-RPC и другие.

Много почитав, я выбрал REST, т.к. он даёт меньше свободы в тех местах, где она не нужна: наименование методов и способ вызова этого метода. Кратко: мои билеты теперь — это ресурсы. Каждое действие с билетом доступно по уникальному сочетанию HTTP-метод + URL. Например, предварительное бронирование (по сути, создание заказа на билет): POST /orders.xml, удаление заказа на билет DELETE /orders/1.xml, а просмотр цен GET /prices.xml.

Подробнее про REST на хабре и в википедии.

Лучшая статья про API REST и Ruby on Rails, в открытом доступе — это глава про ActiveResource в книге Rails 3 in a Nutshell, любезно предоставленной издательством O'Reilly. Там описывается ситуация с точки зрения и клиента REST API и сервера. Очень полезно почитать, чтобы понять, почему надо использовать именно RESTful API. Кроме того, там описывается очень интересная реализация клиента REST API ActiveResource, включённая в состав Ruby On Rails. ActiveResource портирован на некоторые другие языки и будет полезен не только рубистам.

Остальные прочтённые статьи, за вычетом мелочей вкладываются в ту, выше.

Реализация

По реализации мне очень понравилась концепция предлагаемая Rails по-умолчанию, и вовсю эксплуатирующая принцип DRY: генерация API-ответов (XML, JSON) в тех же контроллерах, что и генерация ответов пользователю (html).

Кстати, для реализации DRY существует полезный плагин acts_as_api, позволяющий сильно сэкономить на XML-шаблонах и новая фича Ruby on Rails 3.

Существует несколько толковых веток на Stackoverflow на эту тему, например эта.

Реализация API как отдельного модуля

Есть несколько DSL для организации API. Например, Grape и, если кому надо интегрировать Grape и Ruby on Rails, то ему сюда: martinciu.com/2011/01/mounting-grape-api-inside-rails-application.html

Аутентификация


Вариантов аутентификации\авторизации масса: Basic, с помощью токенов, с помощью сертификатов, Oauth.

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

Самым надёжным в плане безопасности, но, видимо, и самым сложным в реализации, как на клиенте, так и на сервере, является аутентификация, основанная на сертификатах.

Самым базовым вариантом — basic (по сути логин и пароль: user:password@api.myserver.ru/orders.xml).

Я выбрал вариант аутентификации по stateless token'ам, поскольку это позволяет авторизовываться пользователю в браузере под логином и паролем и создавать заказы и, одновременно с этим, под этим же пользователем (но посредством токена) создавать заказы с помощью автоматизированной веб-службы. Мне хочется, чтобы каждый мой агент имел ровно одного пользователя на моём сервере.

Да, конечно, не забываем, что раз уж мы начали авторизовываться, то наше API должно быть завёрнуто в HTTPS, чтобы избежать утечек данных авторизации. Я планирую дать возможность моим агентам перегенерировать API-ключ в их личных кабинетах, если они сочтут, что уже пора.

Кроме того, я выбрал вариант stateless token, передаваемый как POST или GET параметр. Есть ещё вариант пихать token в HTTP заголовки, а не параметром (это более REST-вариант, но чуть сложнее в реализации), как сделано у Amazon. Но мне показалось, что в этом случае игра по реализации не стоит свеч. Особого выигрыша у такого варианта нет (ну, может быть, разве что структура запроса
станет чуть более RESTful), а морока есть.

Литература по поводу организации авторизации\аутентификации веб-службы:
stackoverflow.com/questions/6134082/restful-web-service-how-to-authenticate-requests-from-other-services
stackoverflow.com/questions/939836/service-based-authentication-using-tokens

Реализация

Для Ruby on Rails существует замечательный плагин devise, для которого есть модуль для аутентификации по токену. Буквально, пара строчек — и всё готово.

UPD. Коллеги, минусующие топик, вы хоть отпишитесь с чем несогласны. А то половина ценности топика — в дискуссии, а вы отмалчиваетесь!
Tags:
Hubs:
+34
Comments 19
Comments Comments 19

Articles