Архитектура restful api на pyramid — приемы проектирования...

38
Архитектура RESTful API на Pyramid приёмы проектирования

Upload: it-people

Post on 16-Apr-2017

630 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Архитектура RESTful API на Pyramid

приёмы проектирования

Page 2: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Типичный проект

API

Mobile AppsAdmin PanelWeb Site

BackgroundWorkers

Data Sources

Page 3: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Типичный проект

API

Mobile AppsAdmin PanelWeb Site

BackgroundWorkers

Data Sources

Page 4: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Слои

Данные

Бизнес логика

Представление

Page 5: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Слои

Данные

Бизнес логика

Представление

Model

Controller

View

Page 6: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Слои

Данные

Бизнес логика

Представление

Model

Controller

View

Store

Resource

View

Page 7: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Resource

Page 8: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Resource

―Унифицированный интерфейс к данным

Page 9: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Resource

―Унифицированный интерфейс к данным

―Унифицированные исключения

Page 10: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Resource

―Унифицированный интерфейс к данным

―Унифицированные исключения

―Независимость от представления

Page 11: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Traversal

Page 12: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Traversal

child = parent['child']assert child.__name__ == 'child'assert child.__parent__ is parent

Page 13: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Traversal

child = parent['child']assert child.__name__ == 'child'assert child.__parent__ is parent

GET /users/1/

root['users']['1']

Page 14: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Traversal

child = parent['child']assert child.__name__ == 'child'assert child.__parent__ is parent

GET /users/1/ -> 404 Not Found

root['users']['1'] -> KeyError

Page 15: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Traversal

class Root(object): """ API root resource """

def __getitem__(self, name): if name == 'users': return Users(name, self) raise KeyError(name)

class Users(object): """ Collection of users """

def __init__(self, name, parent): self.__name__ = name self.__parent__ = parent

Page 16: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

TraversalKit

from traversalkit import Resource, DEC_ID

class Root(Resource): # / """ API root resource """

@Root.mount('users') # /users/class Users(Resource): """ Collection of users """

@Users.mount_set(DEC_ID) # /users/{^[0-9]+$}/class User(Resource): """ Particular user """

Page 17: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Коллекции

class Articles(Resource):

def get_list(self, offset=0, limit=10): pass

def get_map(self, ids): pass

def create(self, title, body): pass

Page 18: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Элементы

@Articles.mount_set(DEC_ID)class Article(Resource):

def update(self, title, body): pass

def delete(self): pass

Page 19: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Загрузка элемента

from ..store import db

@Articles.mount_set(DEC_ID)class Article(Resource):

__not_exist__ = db.NoResultFound

def on_init(self, data=None): if data is None: # Created via __getitem__ session = db.Session() data = session \ .query(db.Article) \ .filter(db.Article.id == int(self.__name__)) \ .one() self.data = data

Page 20: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Загрузка списка

from ..store import db

class Articles(Resource):

def get_list(self, offset=0, limit=50): session = db.Session() query = session \ .query(db.Article) \ .limit(limit) \ .offset(offset) \ .order_by(db.Article.created_at)

return [ self.get(str(item.id), item) for item in query.all() ]

Page 21: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Иерархия

@Root.mount('articles') # All articlesclass Articles(Resource): """ Collection of articles """

@Article.mount('comments') # Article's commentsclass Comments(Resource): """ Collection of comments """

Page 22: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Иерархия

@Root.mount('articles') # All [email protected]('articles') # User's articlesclass Articles(Resource): """ Collection of articles """

@Article.mount('comments') # Article's [email protected]('comments') # User's commentsclass Comments(Resource): """ Collection of comments """

Page 23: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

ACL

from pyramid.security import Allow, Everyone, Authenticated

class Articles(Resource):

__acl__ = [ (Allow, Everyone, 'read'), (Allow, Authenticated, 'create'), (Allow, 'group:moderators', ('update', 'delete')), ]

@Articles.mount_set(DEC_ID)class Article(Resource):

def __acl__(self): user_id = str(self.data.user_id) return [(Allow, user_id, ('update', 'delete'))]

Page 24: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

ACL

from pyramid.security import \ Allow, Everyone, Authenticated, DENY_ALL

@Article.mount('comments')class Comments(Resource):

__acl__ = [ (Allow, Everyone, 'read'), (Allow, Authenticated, 'create'), (Allow, 'group:moderators', ('update', 'delete')), DENY_ALL, # Stop inheritance ]

Page 25: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Валидация

from .. import validation

class Articles(Resource, validation.Mixin):

@validation.set_schema(validation.schema.Article) def create(self, title, body): pass

def create_article(context, request): article = context.validated.create(request.json)

Page 26: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Views

from pyramid.view import view_config

from ..resources import Articles

@view_config(context=Articles, request_method='GET', permission='read')def list_articles(context, request): articles = context.validated.get_list(request.GET) return { 'articles': articles, }

Page 27: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Views

from pyramid.view import view_config

from ..resources import Articles

@view_config(context=Articles, request_method='GET', permission='read')def list_articles(context, request): articles = context.validated.get_list(request.GET) users = request.root['users'].get_map( set(a.data.user_id for a in articles) ) return { 'articles': articles, 'users': users, }

Page 28: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Сериализация

class Article(Resource):

def __json__(self, *_): return { 'id': self.data.id, 'title': self.data.title, 'body': self.data.body, }

Page 29: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

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

from pyramid.view import view_configfrom pyramid.security import NO_PERMISSION_REQUIRED

from ..resources import ResourceExceptionfrom ..validation import Invalid

@view_config(context=ResourceException, permission=NO_PERMISSION_REQUIRED)def resource_exception(context, request): request.response.status_int = 400 return {'error': context}

@view_config(context=Invalid, permission=NO_PERMISSION_REQUIRED)def validation_exception(context, request): request.response.status_int = 422 return {'error': context}

Page 30: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

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

400422

Ошибка бизнес логикиНевалидные данные

Page 31: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

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

400422403404

Ошибка бизнес логикиНевалидные данныеНет прав доступаРесурса не существует

Page 32: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

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

400422403404405

Ошибка бизнес логикиНевалидные данныеНет прав доступаРесурса не существуетОшибка контекста

Page 33: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

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

400422403404405500

Ошибка бизнес логикиНевалидные данныеНет прав доступаРесурса не существуетОшибка контекстаВсё сломалось

Page 34: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Тесты

ResourceViewWSGI

Page 35: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Тесты

ResourceViewWSGI

Бизнес логика, иерархия

Page 36: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Тесты

ResourceViewWSGI

Бизнес логика, иерархияВалидация, связанные данные, сессия

Page 37: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Тесты

ResourceViewWSGI

Бизнес логика, иерархияВалидация, связанные данные, сессияИнтеграция, ACL

Page 38: Архитектура RESTful API на Pyramid — приемы проектирования Дмитрий Вахрушев

Вопросы?