RESTful API: Best practices, versioning, design documentation
1. Topic RESTful API
Best practices, versioning, design
documentation
Speaker Vyacheslav Mikhaylov (vmikhaylov@dataart.com)
SPB .NET Meetup #8
1
2. О чем доклад?
• Что такое API и зачем он нужен?
• Основы REST
• На чем реализовывать?
• Бест-практики
• Как проектировать?
• Документация и версионирование
2
4. Почему хороший API это важно?
• Простота использования и поддержки
• Конверсия в среде разработчиков (потребителей).
• Больше бользователей API -> выше популярность сервиса
• Лучше структура -> лучше изоляция компонентов
• API это UI для разработчиков
4
5. Какие виды API бывают?
• Web service APIs
• XML-RPC and JSON-RPC
• SOAP
• REST
• WebSockets APIs
• Library-based APIs
• Java Script
• Class-based APIs
• C# API, Java
• OS function and routines
• Access to file system
• Access to user interface
• Object remoting APIs
• CORBA
• .Net remoting
• Hardware APIs
• Video acceleration (OpenCL…)
• Hard disk drives
• PCI bus
• …
5
6. Какие виды API нас интересуют?
Web service APIs
• XML-RPC and JSON-RPC
• SOAP – Simple Object Acces Protocol
• REST
6
8. Принципы REST?
• Клиент-серверная архитектура
• Любые данные являются ресурсом
• Любой ресурс имеет ID
• Ресурсы связаны между собой
• Используются стандартные методы HTTP
• Сервер не хранит состояние
8
9. Чем REST хорош?
• Он простой!
• Переиспользуем существующие стандарты
• REST базируется на HTTP => доступны все плюшки
• Кеширование
• Масштабирование
• Минимум накладных расходов
• Стандартные коды ошибок
• Очень хорошая распространённость (даже IoT)
9
10. Best-practices (независимые от технологий)
• SSL everywhere
• Documentation & Versioning
• POST, PUT should return data
• Filtering, sorting, pagination
• Support MediaType
• Pretty print & gzip
• Standard caching by ETag & Last-Modified
• Use standard error codes and predefined error format
10
11. Свойства HTTP методов
11
HTTP Method Idempotent Safe
OPTIONS Yes Yes
GET Yes Yes
HEAD Yes Yes
PUT Yes No
POST No No
DELETE Yes No
PATCH Yes No
12. Что такое RESTful API?
Это такой сервис, который
удовлетворяет принципам REST
12
13. Выбираем технологию
WCF Services
– webHttpBinding only(а зачем
тогда остальные?)
– Поддерживаются только HTTP
Get & POST (и все)
+ Разные форматы XML, JSON,
ATOM
Web Api
+ Очень простой
+ Open source
+ Все возможности HTTP
+ Все возможности MVC
+ Легкий (не жирный )
+ Тоже поддерживает кучу
форматов
13
14. Выбираем хостинг для WebApi
•ASP.NET MVC
•OWIN – Open Web Interface for .Net
•IIS
•Self-hosted
•Azure
14
15. Идея OWIN
• Это спецификация (не библиотека и не платформа)
• Устраняет сильную связанность веб приложения с реализацией
сервера
15
16. Katana – реализация OWIN от Microsoft
[assembly: OwinStartup(typeof (Startup))]
namespace RestApiDemo
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}
}
}
16
17. Проектируем интерфейс
• Все ресурсы в REST существительные (множественное число)
• Корневые сущности API
• GET /stations - Все вокзалы
• GET /stations/123 - Информация по вокзалу с ID = 123
• GET /trains - Все поезда
• Зависимые сущности
• GET /stations/555/departures – поезда уходящие с вокзала 555
17
18. Простейший контроллер
[RoutePrefix("stations")]
public class RailwayStationsController : ApiController
{
[HttpGet]
[Route]
public IEnumerable<RailwayStationModel> GetAll()
{
return testData;
}
RailwayStationModel[] testData = /*initialization here*/
}
18
23. Примеры запросов REST
• GET /stations– получить все вокзалы
• GET /trains – расписание всех поездов
• GET /stations/555/arrivals
• GET /stations/555/departures
23
25. public static class TrainsFromControllerRoutes
{
public const string BasePrefix =
RailwayStationsControllerRoutes.BasePrefix +
"/{station:int}/departures";
public const string GetById = "{id:int}";
}
25
Константы для роутинга
27. Базовый CRUD
• POST – создать новую сущность
• POST /Stations – JSON описание сущности целиком. Действие добавляет новую сущность
в коллекцию
• Возвращает созданную сущность
• PUT – изменить сущность
• PUT /Stations/12 – Изменить сущность с ID = 12.
• Возвращает измененную сущность
• DELETE
• DELETE /Stations/12 – Удалить сущность с ID = 12.
27
28. Еще примеры CRUD
• POST /Stations – Добавляем вокзал
• POST /Stations/1/Departures – Добавляем информацию об отправлении с вокзала 1
• DELETE /Stations/1/Departures/14 – Удаляем запись об отправлении с вокзала 1
• GET /Stations/33/Departures/10/Tickets – Список проданных билетов для
отправления 10 с вокзала 33
28
29. Naming anti-patterns
• GET /Stations/?op=departure&train=11
• действия в query string
• GET /Stations/DeleteAll
• реальный пример из жизни :)
• борьба с кешированием
• POST /GetUserActivity
• пост нужен был из-за параметров запроса в body
• POST /Stations/Create
• действие указано в составе URL - избыточно
29
30. Проектируем API
• Как связаны сущности API с доменной моделью?
• Никак они не связаны
• Как проектировать API если это не CRUD
• Превращаем действия в команды на изменения
30
33. Bounded context (BC)
• Изолированный поддомен
• Независимы друг от друга
• Имеют независимые модели (разные)
• BC <= component
33
34. Aggregates
• Целостная (consistent) группа сущностей
• Цель – гарантироваться целостность и согласованность всех
объектов
• Aggregate root (AR) – самый «главный» объект в группе
• Все изменения только через AR
• Сущности из разных Aggregate Root не могут ссылаться друг на
друга
34
38. Примеры запросов
• PUT /hotels/555/rooms/105/attachedDevices – заменить всю
коллекцию привязанных устройств на новую
• POST /hotels/555/rooms/105/attachedDevices – привязать еще
одно устройство
• DELETE /hotels/12 – удалить описание отеля с ID = 12
• POST /hotels/123/reservations – создать новую резервацию в
отеле id=123
38
40. REST without PUT
• Change entity XXX => New COMMAND to change entity XXX
• Можно отслеживать статус выполнения
• Можно отменять команды (DELETE)
• Легко хранить историю изменений
• Пользователь сообщает о намерениях
40
41. Fine Grained VS Coarse Grained
• Много маленьких объектов
• Бизнес логика уходит на
сторону клиента
• Нужно знать как связаны
объекты
• Сложно делать локальные
изменения например
• POST /blogs/{id}/likes
• Нужно отслеживать состояние
на клиенте
• Большие объекты нельзя
сохранить частично
41
42. Версионирование
• Если вы однажды опубликовали контракт, то вы обязаны его
соблюдать
• Braking changes можно делать только при изменении версии
42
43. Подходы к версионированию
Type Sample Complexity
URL {host}/api/v2/… Minimum
Custom Header api-version:2 Average
Custom Accept Header Accept:application/vnd.trainmodel.v2+json Maximum
43
Набор правил, как одно приложение или компонет взаимодействует с другими.
И механизм, который обеспечивает это взаимодействие
Обычно это не про UI
Взаимодействие виде Software-to-software (Component)
RPC
RPC – это «remote procedure call», понятие очень старое, объединяющие древние, средние и современные протоколы, которые позволяют вызвать метод в другом приложении. XML-RPC – это протокол, появившийся в 1998, вскоре после появления XML. Изначально поддерживался Microsoft, но вскоре Microsoft полностью переключилась на SOAP и поэтому в .Net Framework мы не найдем классов для поддержки этого протокола. Несмотря на это, XML-RPC продолжает жить до сих пор в различных языках (особенно в PHP), видимо, заслужил любовь разработчиков своей простотой.
SOAP
SOAP также появился в 1998 году стараниями Microsoft. Он был анонсирован как революция в мире ПО. Нельзя сказать, что все пошло по плану Microsoft, было огромное количество критики из-за сложности и тяжеловесности протокола. В то же время были и те, кто считал SOAP настоящим прорывом. Сам же протокол продолжал развиваться и плодиться десятками новых и новых спецификаций, пока в 2003 года W3C не утвердила в качестве рекомендации SOAP 1.2, который и сейчас является последним. Семейство у SOAP получилось внушительное: WS-Addressing, WS-Enumeration, WS-Eventing, WS-Transfer, WS-Trust, WS-Federation, Web Single Sign-On
You do need rest )
«передача состояния представления» – и что? Что это такое? Ничего не понятно.
«представление данных в удобном для клиента формате»
Рой Филдинг в своей работе 2000го года. Мысль в том, что каждое обращние к сервису переводит клиентское приложение в новое состояние.
Позволяет запускать приложения на любой платформе, поддерживающей OWIN, без изменений.
Спецификация очень проста, это просто Dictionary из параметров и их значений. Базовые параметры определены в спецификации.
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»
После подключения нескольких библиотек через NuGet достаточно такого кода, чтобы наш сервер «взлетел»