python client api
DESCRIPTION
This slide cover the how to implement of an python client api and it's DescriptionTRANSCRIPT
茴香豆的茴有几种写法记Python的⼀一个客户端实现
dreampuf Jul, 2012
main
printf scanf
本地调用
远程调用
Client
ServerA ServerB
Protocol Stream
class MockAPI(API): api_url = 'http://host' api_version = 'v1' def etsy_home(self): return Test.scratch_dir def get_method_table(self, *args): return [{'name': 'testMethod', 'uri': '/test/{test_id}', 'http_method': 'GET', 'params': { 'limit': 'int', 'test_id': 'user_id_or_name', 'offset': 'int', 'fizz': 'enum(foo, bar, baz)', 'buzz': 'float', 'blah': 'unknown type', 'kind': 'string', }, 'type': 'int', 'description': 'test method.'}] def _get_url(self, url, http_method, content_type, body): return '{ "count": 1, "results": [3] }'
Esty-python
class MockAPI(API): api_url = 'http://host' api_version = 'v1' def etsy_home(self): return Test.scratch_dir def get_method_table(self, *args): return [{'name': 'testMethod', 'uri': '/test/{test_id}', 'http_method': 'GET', 'params': { 'limit': 'int', 'test_id': 'user_id_or_name', 'offset': 'int', 'fizz': 'enum(foo, bar, baz)', 'buzz': 'float', 'blah': 'unknown type', 'kind': 'string', }, 'type': 'int', 'description': 'test method.'}] def _get_url(self, url, http_method, content_type, body): return '{ "count": 1, "results": [3] }'
Esty-python
重用不依赖URL
类型验证
不直观缺乏语法检查
不易调试URL拓展
GuokrAPI v1
class GuokrAPI(API): HOST = "http://localhost/" METHODS = [{ "name": "get_tag", "url": "tags", "method": "GET", "description": "Get the tag instance list", }, { "name": "get_tags", "url": "tags/%(tagname)s", "method": "GET", "description": "Get a tag instance", }]
GuokrAPI v1
class GuokrAPI(API): HOST = "http://localhost/" METHODS = [{ "name": "get_tag", "url": "tags", "method": "GET", "description": "Get the tag instance list", }, { "name": "get_tags", "url": "tags/%(tagname)s", "method": "GET", "description": "Get a tag instance", }]
不直观缺乏语法检查
不易调试
重用不依赖URL
URLLIB3
URL拓展类型验证
GuokrAPI v2
mercury.group.mixin(minerva.taggable)
# POST on url /tagscall = resources.tags.create().format('jsonp')
# POST on url /taggings/tags/科学/group/654321call = resources.taggings.update({ 'tag': '科学', 'taggable': group, 'user': 'afsrgx',})
tagging = guokr.type( 'tagging').fields({ 'id': 'int', 'tag': 'string', 'taggable': 'taggable', 'tag': 'string', 'user': 'ukey', 'date_create': 'datetime', 'date_deleted': 'datetime',}).keys([ 'id']).end()
import guokrimport minerva.types as minerva
tags = guokr.resources([ minerva.tag])
taggings = guokr.resources([ minerva.tag, minerva.taggable,]).namespace( 'taggings')
GuokrAPI v2
tagging = guokr.type( 'tagging').fields({ 'id': 'int', 'tag': 'string', 'taggable': 'taggable', 'tag': 'string', 'user': 'ukey', 'date_create': 'datetime', 'date_deleted': 'datetime',}).keys([ 'id']).end()
import guokrimport minerva.types as minerva
tags = guokr.resources([ minerva.tag])
taggings = guokr.resources([ minerva.tag, minerva.taggable,]).namespace( 'taggings')
mercury.group.mixin(minerva.taggable)
# POST on url /tagscall = resources.tags.create().format('jsonp')
# POST on url /taggings/tags/科学/group/654321call = resources.taggings.update({ 'tag': '科学', 'taggable': group, 'user': 'afsrgx',})
URL拓展抽象繁多
重用类型验证链式语法清晰
GuokrAPI v2
GuokrAPI v2
Python
GuokrAPI v2
Pythonic
GuokrAPI v3
TUPLE_TAGGINGABLE = ("article", "post", "blog", "group", "question")class GuokrAPI(API): HOST = "http://localhost:5000/" @GET("tags/%(tag)s") def get_tag(tag): pass @GET("tags/%(tag)s/feeds") def get_tag_feeds(tag, filter=str): pass @POST("tags/") def add_tag(tag, synonym=str, logo=str, description=str): pass @POST("tag/%(tag)s") def post_tag(tag, logo=str, description=str): pass
class GuokrCMSAPI(GuokrAPI): @GET("cms/tags/filter:%(prefix)s") def get_tag_prefix(prefix): pass #Duplicate #@POST("cms/tags") #def add_tag(self, tag, synonym=None, logo=None, description=None): pass @POST("cms/tags/%(tag)s") def post_tag(tag, logon=str, synonyms=str): pass #synonyms VS synonym @POST("cms/tags/%(tag)s/lock")
GuokrAPI v3
重用类型验证清晰调试/直观
TUPLE_TAGGINGABLE = ("article", "post", "blog", "group", "question")class GuokrAPI(API): HOST = "http://localhost:5000/" @GET("tags/%(tag)s") def get_tag(tag): pass @GET("tags/%(tag)s/feeds") def get_tag_feeds(tag, filter=str): pass @POST("tags/") def add_tag(tag, synonym=str, logo=str, description=str): pass @POST("tag/%(tag)s") def post_tag(tag, logo=str, description=str): pass
class GuokrCMSAPI(GuokrAPI): @GET("cms/tags/filter:%(prefix)s") def get_tag_prefix(prefix): pass #Duplicate #@POST("cms/tags") #def add_tag(self, tag, synonym=None, logo=None, description=None): pass @POST("cms/tags/%(tag)s") def post_tag(tag, logon=str, synonyms=str): pass #synonyms VS synonym @POST("cms/tags/%(tag)s/lock")
•统⼀一 随时注意前后接口⼀一致•抽象 隐藏不必要的细节•充要 只接受充分且必须的参数•直观 对人友好,对机器友好(调试)•原生 Pythonic
结论
DATA ENTRY
Data Entry v1
a = (1, 2, 3)
Data Entry v2
a = {“a”:1, “b”:2, “c”:3)
Data Entry v3
class uDict(dict): def __getattr__(self, name): return self.__getitem__(name)
Data Entry v4
class uDict(dict): def __getattr__(self, name, default=None): try: return self.__getitem__(name) except KeyError: return default
a = uDict(a=1, b=2, c=3)print a.bprint a.g
Data Entry v5
class Entry(object): def __init__(self, a, b, c): self.a = a self.b = b self.c = c
Data Entry v6
from collections import namedtupleEntry = namedtuple("Entry", "a b c")a = Entry(a=1, b=2, c=3)
Data Entry v7
class Entry(namedtuple("Entry", "a b c")): def __new__(cls, a=None, b=None, c=None): return super(Entry, cls).__new__(cls, a, b, c)
谢谢!
REFERENCE
•Etsy-python https://github.com/mcfunley/etsy-python•Lambda Picturehttp://www.flickr.com/photos/rofi/2097239111/