Как стать автором
Поиск
Написать публикацию
Обновить

Дао Вебсервиса. (Или да хватит же изобретать велосипеды!)

Время на прочтение12 мин
Количество просмотров59K
image Недавно на Хабре была опубликована статья под провокационным заголовком и призывом к прекращению изобретений велосипедов в API-строении. Поскольку тема мне интересна, то я просто не мог пройти мимо.
Увы, реальность за хабракатом меня сильно разочаровала — я увидел очередной велосипед, да еще и с квадратными колесами. (Коллеги, ничего личного, только техническое обсуждение.) Правда, авторы честно сказали, что увидели на нескольких сайтах модное слово REST и решили сделать по нему. Только вот поняли они этот «РЭСТ» по-своему, примерно как Дед Щукарь читал и понимал толковый словарь.
В этом топике я призываю по-настоящему покончить с велосипедами в API сайтов. Ведь получается какой анекдот: АПИ разрабатывается для упрощения доступа к сайту и легкости подключения внешних систем, а получается такой, что с ним еще сложнее, чем без него :)

Чуть ниже под катом я подпишу смертный приговор всем велосипедам в универсальных API. Чтобы не быть голословным, я все проиллюстрирую примерами.
Но должен предупредить сразу — после прочтения статьи вы не сможете без рвотного рефлекса смотреть на очередной велосипед Васи Пупкина под гордым названием «универсальное API сайта».

В повествовании будут рассмотрены следующие вопросы:
  1. Базовые технологии: XML-RPC, REST, SOAP и краткое сравнение
  2. Дао вебсервиса
  3. Просветленные API
  4. Как отличить сайтовое API от говна
  5. Выводы



Итак на сегодня наиболее распространенными способами доступа к API сайтов являются:
1. XML-RPC.
2. REST (с оговоркой, что это не протокол, а подход).
3. SOAP.


Базовые технологии и сравнение



XML-RPC

Думаю, не сильно ошибусь, если скажу, что XML-RPC — прародитель всей этой галиматьи, которую мы сейчас называем громкими словами «веб-сервисы» и «сайтовое api». Разрабатывался в 1998 году по заказу Микрософта. По своей сути это реинкарнация старого доброго RPC с использованием форматирования сообщений в XML. Несомненным преимуществом протокола является его простота, и как следствие, легкость реализации.
Вот пример типичного XML-RPC запроса:
<?xml version="1.0"?>
 <methodCall>
   <methodName>examples.getAirportCode</methodName>
   <params>
     <param>
         <value><i4>567</i4></value>
     </param>
   </params>
 </methodCall>

На что можно получить такой же простой ответ:
<?xml version="1.0"?>
 <methodResponse>
   <params>
     <param>
         <value><string>SVO</string></value>
     </param>
   </params>
 </methodResponse>


Примерно так же просто выглядят сообщения об ошибках. Такой ответ легко распарсить даже человеку, не говоря уже про машину. Такая простота сослужила ему двоякую службу: с одной стороны он не был принят заказчиком и не стал стандартом, а с другой — понравился толпе простых незамороченных программистов. Этим ребятам нужно было простое и надежное средство обмена информацией между системами, они не хотели заморачиваться на такую хрень как красивый УРЛ, схема документа и прочие академизмы. Первое, что они хотели получить — простую работающую систему. И до сих пор XML-RPC помогает им в этом.
Итак:
+ : простота, краткость сообщений, минимальная проверка формата данных,
— : недостаточная строгость, требуется отдельное описание сервиса.

REST

Наверное, Рой Филдинг был первым, кто сказал «хватит изобретать велосипеды» и «все уже украдено до нас» применительно к веб-сервисам. А может и не первым, в любом случае его слова прозвучали наиболее громко. В своей диссертации Architectural Styles and the Design of Network-based Software Architectures он описал базовые принципы REST (Representational State Transfer) — архитектура веб-сервисов, изменившая представления разработчиков на 180 градусов**. Он сказал, что «танцевать надо не от угла, а от печки» — иными словами — надо не процедуру вызывать и передавать ей объект, а обращаться к объекту. Не надо наворачивать велосипед на мопед. Ведь самом протоколе HTTP уже есть ряд методов работы с объектами: GET (получить), POST (отправить/создать), PUT (обновить), DELETE (удалить).
Зачем заниматься тавтологией и вызывать
POST /api/object.php?object_id=445&action=delete&user_id=255&auth_key=0Jf4tet5 HTTP/1.1

Когда можно просто:
DELETE /objects/445 HTTP/1.1

Или еще практикуется вариант, когда делается POST на сам ресурс, а delete передается отдельно параметром:
POST /objects/445 HTTP/1.1

При этом, если XML-RPC использует из HTTP-протокола только транспортную часть для передачи XML-ки запроса/ответа, то REST задействует HTTP по-полной: здесь и авторизационные заголовки, content-negotiation — предпочтения по формату, языку, кодировке и виду ответа, различные служебные заголовки, безгеморная передача бинарных данных и т.п. Ошибки хорошо описываются кодами HTTP 4xx и 5xx. Можно видеть, что REST — органичная надстройка над HTTP. Это неудивительно ведь Рой — один из разработчиков протокола HTTP. Вообще, чем больше я разбираюсь с этим протоколом тем больше мне кажется, что он опередил свое время лет на 20, и чем дальше развивается веб, тем больше возможностей мы из него используем.
Само тело сообщения может передаваться в разных форматах: классическом XML либо гиковском JSON. Вообще, REST это не протокол, это подход, и как раз здесь заключена его гибкость, он как бы говорит нам: «Ребята, берите базовые принципы, а дальше делайте как вам удобно». Близость к HTTP-протоколу упрощает и ускоряет его обработку веб-серверами.
Итак:
+ : гибкость, простота, скорость обработки (особенно важно для крупных сайтов), органичность протоколу, мультиформатность, компактность.
— : отсутствие строго контроля данных, из практических соображений приходится выходить за рамки идеальной модели.

SOAP

Вот мы и добрались до него — протокол-подарок! Но именно на нем я постиг дао всех веб-сервисов и сайтовых апи. Думаю, все в курсе, что значит аббревиатура SOAP — Simple Object Access Protocol. Именно так в представлении Микрософта должен выглядеть идеальный протокол для веб-сервисов. Давайте посмотрим на что похожи типовой запрос:
Copy Source | Copy HTML
  1. <soapenv:Envelope
  2.     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  3.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.     xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/
                            schemas.xmlsoap.org/soap/envelope">
  5.   <soapenv:Body>
  6.     <req:echo xmlns:req="http://localhost:8080/axis2/services/MyService/">
  7.       <req:category>classifieds</req:category>
  8.     </req:echo>
  9.   </soapenv:Body>
  10. </soapenv:Envelope>


и ответ:
Copy Source | Copy HTML
  1. <soapenv:Envelope
  2.     xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
  3.     xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5.     xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/
                            schemas.xmlsoap.org/soap/envelope">
  6.   <soapenv:Header>
  7.     <wsa:ReplyTo>
  8.       <wsa:Address>schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:Address>
  9.     </wsa:ReplyTo>
  10.     <wsa:From>
  11.       <wsa:Address>localhost:8080/axis2/services/MyService</wsa:Address>
  12.     </wsa:From>
  13.     <wsa:MessageID>ECE5B3F187F29D28BC11433905662036</wsa:MessageID>
  14.   </soapenv:Header>
  15.   <soapenv:Body>
  16.     <req:echo xmlns:req="http://localhost:8080/axis2/services/MyService/">
  17.       <req:category>classifieds</req:category>
  18.     </req:echo>
  19.   </soapenv:Body>
  20. </soapenv:Envelope>


— Фак май мозг! — воскликнете вы и будете абсолютно правы — Это что же, ради передачи фитюльки на 10 байт мне надо всю эту лабуду писать?
— Да — скажет Логика, и вы, засучив рукава пойдете учить всю эту кучу технологий.

— Сюда еще и XML Schema приплели зачем-то? Какого хрена? А вы уверены, что эти ребята правильно понимают смысл слова «Simple»? — такие мысли будут вас посещать, и это хорошо — вы на верном пути.

Но и это не все: чем больше копаешься в SOAP тем больше всяких разных технологий вылазит на тебя. Когда вы дойдете до WSDL (Язык описания веб-сервисов), вы поймете почему, начиная с какой-то версии, разработчики перестали воспринимать название SOAP как аббревиатуру, а начали понимать буквально — soap («мыло»). В этот момент ваши мысли будет занимать одна идея: почему во всем этом зоопарке технологий отсутствует технология rope («веревка»).

Еще через какое-то время вы воскликните: «Ну нафиг, давайте уж без меня: сами придумали — сами и возитесь. Я вам не машина мегабайты иксэмеля в мозгу парсить!».
Поздравляю: теперь вы постигли дао вебсервисов!

Да! Дао веб-сервиса именно в этом и состоит: это язык общения машин и человеку нафиг не надо туда лезть. Надо просто его использовать. Ведь когда вам нужна какая-то программа, вы ее запускаете, а не лезете в бинарный код, чтобы исполнять его в мозгу. Точно так же вы не отправляете HTTP-запросы руками в командной строке, а используете браузер. Так зачем здесь лезть в эту гопу голыми руками, да еще хвастаться кто залез по локоть, а кто по самое плечо? Надо просто его использовать.


Просветленные API


API сайта и веб-сервисы — это не что-то милостиво спущенное на нас с небес создателями сайта! Это банальная библиотека функций, которую мы можем встроить в свою программу. Этот вывод становится совершенно естественным, когда вы начинаете мыслить глобально за пределами своего компьютера.
Если вам нужна новая уже готовая либа в проекте, что вы делаете? Скорее всего просто скачиваете, устанавливаете и используете? Пишете в начале программы use/require/import/include/… а дальше просто вызываете функции. Почему же работа с веб-библиотекой должна быть сложнее?
Вот теперь, просветлившись, мы можем начать работать с просветленным API.

Сейчас в качестве примера мы 1 минуту сделаем работу с API Аэрофлота, будем подглядывать за табло Шереметьево без отрыва задницы от стула. Я беру свой любимый язык и на нем пишу все примеры. Уверен, в вашем языке есть аналогичные модули. Ну а если их там нет, то самое время задуматься, так ли взаимна ваша любовь ;-)

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

Copy Source | Copy HTML
  1. <pre>
  2. from ZSI.ServiceProxy import ServiceProxy #  импортируем замечательную либу Zolera Soap Infrastructure
  3. api = ServiceProxy('http://webservices.aeroflot.ru/flightstatus.asmx?WSDL')
  4. # ... и все! API сайта полностью готово к работе.
  5. # наш объект api содержит методы 
  6. AirportInfo() Departure()
  7. AirportList()         FlightInfo()
  8. Arrival()               FlightSearch()
  9.  
  10. # то есть все те, что описаны в доке. 
  11. # Нам осталось лишь вызвать их с нужными параметрами:
  12. airport_list = api.AirportList()
  13. airport_list
  14. {'AirportListResult': {'Airport': [{'city': 'Colombo',
  15.                                     'code': 'CMB',
  16.                                     'id_country': 'SRI',
  17.                                     'name': 'Bandaranayake'},
  18.                                    {'city': 'Belfast',
  19.                                     'code': 'BFS',
  20.                                     'id_country': 'UK',
  21.                                     'name': 'Belfast Intl'},
  22.                                     .....
  23. # Обратите внимание насколько все просто. Мы в 2 команды подключились к API и легко вызываем его методы - сразу получаем результат отпарсенный и подготовленный к работе в нашем языке.
  24. # Работать мне с ним так же легко и просто, словно это обычная библиотека на моем компе. 
    # Для моей программы это абсолютно прозрачно.
  25. # Нас интересует табло прибытия за 15 число:
  26. import datetime
  27. date1 = datetime.date(2009, 11, 15)
  28.  
  29. arrival = api.Arrival(code='SVO', date=date1, order_field='airport', order='asc')
  30. arrival
  31. {'ArrivalResult': {'Flight': [{'airport': 'Adler/Sochi',
  32.                                'calc': (1, 1, 1,  0,  0,  0,  0,  0,  0),
  33.                                'company': 'SU',
  34.                                'fact': (1, 1, 1,  0,  0,  0,  0,  0,  0),
  35.                                'flight_no': '874',
  36.                                'flt_pk': '2009101359805123',
  37.                                'is_board':  0,
  38.                                'is_check':  0,
  39.                                'plan': (2009, 11, 15, 10, 55,  0,  0,  0,  0),
  40.                                'real': (1, 1, 1,  0,  0,  0,  0,  0,  0),
  41.                                'sched': (2009, 11, 15, 10, 55,  0,  0,  0,  0),
  42.                                'status': ''},
  43.                                ......
  44. </pre>


Стойте-стойте, а как же вся эта лабуда с XML, REST, передачей параметров, парсингом ответов и всеми прочими атрибутами «крутого» API?
Лучше всего на это отвечает фильм «Матрица», кадр из которого мне захотелось вынести в заголовок:
— Нет никакой ложки, Нео.

Только перестав думать о ложке сайтовом API как о чем-то реальном, сложном, можно начать гнуть ее комфортно использовать.
Это и есть просветленное API — прозрачное и светлое настолько, что вы его не замечаете, когда работаете. Для вас это просто локальная библиотека. А вся остальная механика с сетевыми заморочками происходит где-то внутри и вас не напрягает.

Как отличить сайтовое API от говна.


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

Выводы


В наше время наличие API для сайта претендующего на внимание программистов, всевозможные интеграции и прочее — не повод для гордости, а предмет первой необходимости. Но мало сделать API, даже если вы используете самые модные принципы — надо его сделать удобным и прозрачным. И технология передачи данных здесь имеет значение 10-й важности — это вообще не нужно прикладному программисту. Он должен просто взять и использовать вашу библиотеку.
Если вы хотите получить его внимание, чтобы он потратил свое время на интеграцию с вами — сделайте первый шаг — потратьте время на него. Дайте ему очень простую и понятную библиотеку.
Не надо кивать на то, что «мы сделали как твиттер — дали REST-подобный интерфейс». Вы забываете главное — у твиттера на каждый язык программирования по 5-10 библиотек, которые можно просто скачать и использовать не заморачиваясь на протокол rest/xmlrpc/soap.

Удачи и приятных интерфейсов!
Теги:
Хабы:
Всего голосов 313: ↑288 и ↓25+263
Комментарии206

Публикации

Ближайшие события