69
Проектирование API Игорь Кузнецов, Undev, 2013 [email protected], @igkuz 1 пятница, 14 июня 13 г.

Api devconf 2013

Embed Size (px)

Citation preview

Page 1: Api devconf 2013

Проектирование API

Игорь Кузнецов, Undev, [email protected], @igkuz

1

пятница, 14 июня 13 г.

Page 2: Api devconf 2013

План

• Что такое API?• С чего начать проектирование?• Какими должны быть формат и структура ответа?

• Валидация больших структур• Обработка исключений

• Версионирование• Как написать клиент к вашему API?• Зачем все это нужно?

2

пятница, 14 июня 13 г.

Page 3: Api devconf 2013

Что такое API?

3

пятница, 14 июня 13 г.

Page 4: Api devconf 2013

Что такое API?

Application Programming Interface

3

пятница, 14 июня 13 г.

Page 5: Api devconf 2013

Что такое API?

Application Programming InterfaceНабор методов, предоставляемых приложением(сервисом, классом, модулем) для использования во внешних программных продуктах

3

пятница, 14 июня 13 г.

Page 6: Api devconf 2013

Что такое API на самом деле?

4

пятница, 14 июня 13 г.

Page 7: Api devconf 2013

Интерфейс должен быть

5

пятница, 14 июня 13 г.

Page 8: Api devconf 2013

Интерфейс должен быть

• Интуитивно понятным

5

пятница, 14 июня 13 г.

Page 9: Api devconf 2013

Интерфейс должен быть

• Интуитивно понятным• Идеально продуманным с самого

начала

5

пятница, 14 июня 13 г.

Page 10: Api devconf 2013

Интерфейс должен быть

• Интуитивно понятным• Идеально продуманным с самого

начала

5

пятница, 14 июня 13 г.

Page 11: Api devconf 2013

С чего начать проектирование?

6

пятница, 14 июня 13 г.

Page 12: Api devconf 2013

С чего начать проектирование?

6

пятница, 14 июня 13 г.

Page 13: Api devconf 2013

Просто начать

7

пятница, 14 июня 13 г.

Page 14: Api devconf 2013

Просто начать

• Отделить API от остальной части проекта– /api

7

пятница, 14 июня 13 г.

Page 15: Api devconf 2013

Просто начать

• Отделить API от остальной части проекта– /api

• rails generate controller api/posts

7

пятница, 14 июня 13 г.

Page 16: Api devconf 2013

Бездумное следование

8

пятница, 14 июня 13 г.

Page 17: Api devconf 2013

Бездумное следование

• В книгах и документации:

def  index        @people  =  People.all          respond_to  do  |format|            format.html            format.xml  {  render  xml:  @people.to_xml  }        end    end

8

пятница, 14 июня 13 г.

Page 18: Api devconf 2013

Приводит к проблемам  if  @category.save

           respond_to  do  |format|                format.html  do                    flash[:notice]  =  l(:notice_successful_create)                    redirect_to_settings_in_projects                end                format.js                format.api  {  render  :action  =>  'show',  :status  =>  :created  }            end        else            respond_to  do  |format|                format.html  {  render  :action  =>  'new'}                format.js      {  render  :action  =>  'new'}                format.api  {  render_validation_errors(@category)  }            end        end

9

пятница, 14 июня 13 г.

Page 19: Api devconf 2013

Правильный путь

10

пятница, 14 июня 13 г.

Page 20: Api devconf 2013

Правильный путь

10

• respond_with + ( jbuilder || RABL || Action Model Serializers)

пятница, 14 июня 13 г.

Page 21: Api devconf 2013

Правильный путь

10

• respond_with + ( jbuilder || RABL || Action Model Serializers)

• структура и формат определяются во view или отдельном объекте

пятница, 14 июня 13 г.

Page 22: Api devconf 2013

Возможный ответ

11

GitHub Instagram Foursquare

пятница, 14 июня 13 г.

Page 23: Api devconf 2013

Возможный ответ

12

GitHub Instagram Foursquare

пятница, 14 июня 13 г.

Page 24: Api devconf 2013

Что взять?

13

Foursquare + Instagram

json.meta  do  |json|    json.total                @lists.total_count    json.num_pages        @lists.num_pages    json.per_page          @per_page    end  json.items  @lists  do  |json,  list|    json.partial!  "maillist",  maillist:  listend

пятница, 14 июня 13 г.

Page 25: Api devconf 2013

Сложные структуры в ответе

14

пятница, 14 июня 13 г.

Page 26: Api devconf 2013

Сложные структуры в ответе

14

   #  @return  [Hash]  Updated  subscriber  object    #      @example    #          {    #              "id":  1,    #              "email":  "[email protected]",    #              "first_name":  "Name#1",    #              "last_name":  "Name#2",    #              "organization":  "Organization#1",    #              "accreditation":  "Accreditation#1",    #              "unisender_state":  "unprocessed",    #              "highrise_state":  "unprocessed"    #          }    def  update_subscriber        #  some  code    end

пятница, 14 июня 13 г.

Page 27: Api devconf 2013

15

JSON Schema

пятница, 14 июня 13 г.

Page 28: Api devconf 2013

15

       "$schema":  "http://json-­‐schema.org/draft-­‐04/schema#",        "title":  "List",        "type":  "object",        "required":  ["id",  "name  "],        "properties":  {                "id":  {                    "description":  "Lists  unique  identifier",                    "type":  "integer"                },                "name":  {                    "description":  "Lists  name  in  project",                    "type":  "string"                }        }

JSON Schema

пятница, 14 июня 13 г.

Page 29: Api devconf 2013

16

В результате

пятница, 14 июня 13 г.

Page 30: Api devconf 2013

16

В результате

   #  @return  [Hash]  Updated  subscriber  object    #      @example    #      Link:  http://yoursite.com/your_schema.json

   def  update_subscriber        #  some  code    end

• Gem: json-schema• https://github.com/hoxworth/json-schema

пятница, 14 июня 13 г.

Page 31: Api devconf 2013

Пагинация

17

пятница, 14 июня 13 г.

Page 32: Api devconf 2013

Пагинация

17

• Kaminari• https://github.com/amatsuda/kaminari

def  index        @lists  =  List.active.                                    page(params[:page]).per(params[:per])

       respond_with  @lists    end

пятница, 14 июня 13 г.

Page 33: Api devconf 2013

Выборка, сортировка

18

пятница, 14 июня 13 г.

Page 34: Api devconf 2013

Выборка, сортировка

18

• Ransack• https://github.com/ernie/ransack

   def  index        @search  =  List.ransack(params[:search])        @lists  =  @search.result.page(params[:page])            respond_with  @lists    end

пятница, 14 июня 13 г.

Page 35: Api devconf 2013

Обработка ошибок

19

пятница, 14 июня 13 г.

Page 36: Api devconf 2013

Обработка ошибок

19

• Одно из самых важных мест в API

пятница, 14 июня 13 г.

Page 37: Api devconf 2013

Обработка ошибок

19

• Одно из самых важных мест в API

• Отдавать правильные статус коды

пятница, 14 июня 13 г.

Page 38: Api devconf 2013

Обработка ошибок

19

• Одно из самых важных мест в API

• Отдавать правильные статус коды

• Присылать человеческие описания ошибок

пятница, 14 июня 13 г.

Page 39: Api devconf 2013

Обработка ошибок

19

• Одно из самых важных мест в API

• Отдавать правильные статус коды

• Присылать человеческие описания ошибок

пятница, 14 июня 13 г.

Page 40: Api devconf 2013

Состояние API

20

пятница, 14 июня 13 г.

Page 41: Api devconf 2013

Состояние API

20

• Все хорошо - success(200)

пятница, 14 июня 13 г.

Page 42: Api devconf 2013

Состояние API

20

• Все хорошо - success(200)

• Клиент прислал что-то не то - client error (400)

пятница, 14 июня 13 г.

Page 43: Api devconf 2013

Состояние API

20

• Все хорошо - success(200)

• Клиент прислал что-то не то - client error (400)

• Сервер сделал что-то не то - server error (500)

пятница, 14 июня 13 г.

Page 44: Api devconf 2013

Варианты

21

пятница, 14 июня 13 г.

Page 45: Api devconf 2013

Варианты

21

• 8-10 статус кодов на все случаи жизни

пятница, 14 июня 13 г.

Page 46: Api devconf 2013

Варианты

21

• 8-10 статус кодов на все случаи жизни

• Улыбаемся и машем

пятница, 14 июня 13 г.

Page 47: Api devconf 2013

Примеры старших

22

• Facebook:

HTTP Status Code: 200

{"type" : "OauthException", "message":"(#803) Some of the aliases you requested do not exist: foo.bar"}

• Github:

HTTP/1.1 404 Not Found

{"message": "Not Found"}

пятница, 14 июня 13 г.

Page 48: Api devconf 2013

Exceptions App

23

пятница, 14 июня 13 г.

Page 49: Api devconf 2013

Exceptions App

23

• application.rb:

– config.exceptions_app = self.routes

пятница, 14 июня 13 г.

Page 50: Api devconf 2013

Exceptions App

23

• application.rb:

– config.exceptions_app = self.routes

• routes.rb:

– match  '/404',  :to  =>  "errors#not_found"

– match  '/422',  :to  =>  "errors#unprocessable_entity"

– match  '/500',  :to  =>  "errors#internal_error"

пятница, 14 июня 13 г.

Page 51: Api devconf 2013

Exceptions App

24

class  ErrorsController  <  ApplicationController

           respond_to  :json,  :html              def  not_found                #  some  code  here            end            def  internal_error                respond_with(...)            end            def  unprocessable_entity                #  some  code  here            end        end

пятница, 14 июня 13 г.

Page 52: Api devconf 2013

Версионирование

25

пятница, 14 июня 13 г.

Page 53: Api devconf 2013

Версионирование

25

• У API обязана быть версия

пятница, 14 июня 13 г.

Page 54: Api devconf 2013

Версионирование

25

• У API обязана быть версия

• Headers vs Urls

пятница, 14 июня 13 г.

Page 55: Api devconf 2013

Версионирование

25

• У API обязана быть версия

• Headers vs Urls

• Url:

– http://exmaple.com/v1/users?access_token=...

пятница, 14 июня 13 г.

Page 56: Api devconf 2013

Версионирование

25

• У API обязана быть версия

• Headers vs Urls

• Url:

– http://exmaple.com/v1/users?access_token=...

• Headers:

– X-Example-Api-Version: 1.2

пятница, 14 июня 13 г.

Page 57: Api devconf 2013

Сколько версий поддерживать

26

пятница, 14 июня 13 г.

Page 58: Api devconf 2013

Сколько версий поддерживать

26

• Минимум 1 версию назад

пятница, 14 июня 13 г.

Page 59: Api devconf 2013

Сколько версий поддерживать

26

• Минимум 1 версию назад

• Зависит от бизнес требований

пятница, 14 июня 13 г.

Page 60: Api devconf 2013

Best practices || Тест на адекватность

27

пятница, 14 июня 13 г.

Page 61: Api devconf 2013

Best practices || Тест на адекватность

27

• Библиотека для работы с API

пятница, 14 июня 13 г.

Page 62: Api devconf 2013

Best practices || Тест на адекватность

27

• Библиотека для работы с API

• Если вам сложно написать клиент для вашего API, стоит серьезно задуматься

пятница, 14 июня 13 г.

Page 63: Api devconf 2013

API Client

28

пятница, 14 июня 13 г.

Page 64: Api devconf 2013

API Client

28

• Weary

• https://github.com/mwunsch/weary

class  MyClass  <  Weary::Client

       get  :resource,  "http://host.com/path/to/"  do  |resource|            resource.required  :api_token,  :id            resource.optional  :optional_parameter        end    end

пятница, 14 июня 13 г.

Page 65: Api devconf 2013

Зачем нужно делать хорошее API?

29

пятница, 14 июня 13 г.

Page 66: Api devconf 2013

Зачем нужно делать хорошее API?

29

• Залог успешного общения с вашими пользователями

пятница, 14 июня 13 г.

Page 67: Api devconf 2013

Зачем нужно делать хорошее API?

29

• Залог успешного общения с вашими пользователями

• Неявное вложение в рекламу

пятница, 14 июня 13 г.

Page 68: Api devconf 2013

Зачем нужно делать хорошее API?

29

• Залог успешного общения с вашими пользователями

• Неявное вложение в рекламу

• Вложение в будущее проекта

пятница, 14 июня 13 г.

Page 69: Api devconf 2013

Вопросы?

30

пятница, 14 июня 13 г.