Building a website API with Django.docx
《Building a website API with Django.docx》由会员分享,可在线阅读,更多相关《Building a website API with Django.docx(33页珍藏版)》请在冰点文库上搜索。
BuildingawebsiteAPIwithDjango
BuildingawebsiteAPIwithDjango
--Part1:
APIfunctions
WAPIanddjango-oauthsparereachingthepointwhentheyarestartingtobecomeuseful,soIdecided#决定itwastimetowritesomearticlesexplaininghowtheyworkandhowyoucanusetheminyoursites.I'mcurrently#正确usingbothoftheminproductionatbyNotesandIhaven'trunintoanyproblemsfornow,butYMMV.
Thisarticletalksabouttheprinciples#原则behindWAPIandwalksyoutroughthecreationofasimpleAPIfunction.Nextarticlesinthisseries#系列willexplainmoreadvancedconcepts#概念likecustom#自定义serializations#序列化,userauthenticationagainstdjango.contrib.authorusingOAuth.
Design
Let'sstartbytalkingaboutthedesignideasbehindWAPI.Mymainmotivation#动机whenIstartedwritingitwasabstracting#文摘mostofthedetailsinvolved#参与inpublishingawebAPI,sincealmost100%ofsiteshavethesamerequirements:
ReSTfulresources(sometimesSOAPorXML-RPC),serialization#序列indifferentformatsanduserauthentication.Handlingallofthisasviewsisnotdifficult,butit'stedious#乏味andalotoftimesrequiresmorecodethantheAPIitself.So,whynotletthedeveloperfocusonprovidingusefulendpointsandletaframeworkdotherest?
WAPIonlyrequiresyoutowriteaclass.That'sit.EverymethodoftheclasstranslatestoanAPImethodandallyouhavetoisreturntheobjectsyouwanttobeserialized#序列化andWAPItakescareofserializingthemintheappropiate#适当format.Isn'tthatbeautiful?
Itevenwillvalidate#验证thefunctionparameters#参数foryouandtakecareofuserauthentication.Doyouwantmore?
Well,there'ssomethingmore:
WAPIwillalsoautodocumentyourAPI,so,asIsaidbefore,allyouhavetodoiswriteaPythonclass.
Thecode
Let'smovetothecode.Forthistutorial,I'mgoingtousethismodel:
classEvent(models.Model):
place_name=models.CharField(max_length=50)
what=models.CharField(max_length=50)
when=models.DatetimeField()
We'regoingtousethepredefined#预定义serialization,whichincludesallthefieldsdefinedinthemodel,sowedon'tneedtotalkaboutwapi.serializersfornow.
Afunctionwithnoparameters
So,it'stimetowritetheAPI.We'reexposing#揭露asimplefunction,listalltheeventshappeningtoday.
fromwapi.responsesimportSerializableResponse#这个模块在哪里留待后面解决
classEventApi(object):
deftoday(self,request,dct):
d=date.today()
returnSerializableResponse(Event.objects.filter(when__year=d.year,when__month=d.month,when__day=d.day)
SerializableResponseisaspecialresponse#响应,whichtakesaquerysetand,optionally#可选,serializationparameters.WAPIknowshowtotranslateSerializableResponsestotherequiredtransportandtheformat,soyoudon'thavetoworryaboutthat.
Nowit'stimetoplugyourAPIintoyoururls.py.WAPIusesabindingfordoingthis,soallyouhavetodoistellWAPIwhichbindingdoyouwantandthebaseurlforit.
fromwapi.bindingsimportRestBinding
frommysite.apiimportEventsApi
urlpatterns=patterns('mysite.myapp.views',
...
...
(r'^api/1.0/rest/%s$'%RestBinding.PATTERN,RestBinding(api=EventsApi())),
...#正则式%s什么意思
)
Asyoucansee,Ispecified#指定thetransportmethodI'musingintheURLfortheAPI.CurrentlyWAPIonlyworksoverReST,butitshouldsupportXML-RPCandSOAPsoon.
Ifyoupointyourbrowsertoyou'llgetsomethinglikethis:
[{id:
7,place_name:
"FooPlace",what:
"Writingatutorial",when:
"2008-08-1117:
21:
56"}]
Or,ifyouprefer,youcouldalsoopenorWAPIalsosupportsthem.
Afunctionwithparameters
So,let'ssupposeyouwanttoletyourAPIconsumers#消费者requestthedetailsforaneventgivenit'sid.Let'sstartwiththebasicbits:
fromwapi.responsesimportSerializableResponse
classEventApi(object):
...moremethods...
defevent(self,request,dct):
returnSerializableResponse(Event.objects.filter(id=dct['id'])
Asyousee,WAPIfunctionsreceivealltheirparametersinsideadict.Thisfunctionisprettystaight-forward,bitithassomeproblems.Forexample:
whathappenswhentheeventdoesn'texist?
orwhentheuseromitstheidparameter?
I'msureyouknowit,butforthesake#为了ofcompleteness完整性,you'llgeta500error.Notveryuser(ordeveloper)friendly.
Parametervalidation
OneofthefeaturesIpreviously#以前mentioned#提到wasparametervalidation#参数验证,solet'suseit.
fromwapi.responsesimportSerializableResponse
fromwapi.decoratorsimportrequired_parameter
fromdjango.utils.translationimportugettext_lazyas_
classEventApi(object):
...moremethods...
@required_parameter('id',int,_('Theidoftheevent'))
defevent(self,request,dct):
returnSerializableResponse(Event.objects.filter(id=dct['id'])
Sowe'recovered#覆盖thecaseswhentheparameterisabsentorit'snotanint.Asabonus#奖金,dct['id']willnowbeaintinsteadofanunicodestring(whichisusefullsometimes).
Serializingsingleobjects
SerializableResponseismeanttoserialize#序列lists(oranyiterable)ofobjects,sotheresponsetothismethodwillalwaysbealist.That'snotverypretty#漂亮whenyou'realwaysreturningasingleobject,solet'schangeittoreturnaSingleSerializableResponse:
fromwapi.responsesimportSingleSerializableResponse
fromwapi.decoratorsimportrequired_parameter
fromdjango.utils.translationimportugettext_lazyas_
#使用函数ugettext()来指定一个翻译字符串。
作为惯例,使用短别名_来引入这个函数以节省键入时间.
classEventApi(object):
...moremethods...
@required_parameter('id',int,_('Theidoftheevent'))
defevent(self,request,dct):
returnSingleSerializableResponse(Event.objects.get(id=dct['id'])
SingleSerializableResponseworksinthesamewayasSerializableResponse,howeverthelatterworksoniterableswhiletheformerworksonasingleobject.
Returninganemptyresponse
Westillhaveaproblemtosolve.Iftheeventdoesnotexist,wearestillreturninga500error.Therearebasicallytwoapproaches#方法here:
somepeopleprefertoreturna404error,whileotherssaythatanempty200responseisbetter.Whateveryouprefer,WAPIcandoit.Ifyouwanttoreturna404error,justusethedjangoshortcutget_object_or_404:
fromwapi.responsesimportSingleSerializableResponse
fromwapi.decoratorsimportrequired_parameter
fromdjango.utils.translationimportugettext_lazyas_
fromdjango.shortcutsimportget_object_or_404
classEventApi(object):
...moremethods...
@required_parameter('id',int,_('Theidoftheevent'))
defevent(self,request,dct):
returnSingleSerializableResponse(get_object_or_404(Event,id=dct['id']))
However,ifyoupreferanemptyresponse,justusetheget_object_or_emptyWAPIshortcut:
fromwapi.responsesimportSingleSerializableResponse
fromwapi.decoratorsimportrequired_parameter
fromwapi.shortcutsimportget_object_or_empty
fromdjango.utils.translationimportugettext_lazyas_
classEventApi(object):
...moremethods...
@required_parameter('id',int,_('Theidoftheevent'))
defevent(self,request,dct):
returnSingleSerializableResponse(get_object_or_empty(Event,id=dct['id']))
Nextarticleinthisseries
TherearesomemoretopicsaboutWAPIanddjango-authspIwanttocover,butI'mnotsureaboutwhat'sthebestorder,soifyoulikedthisarticleleaveacommentandtellmewhatyouwanttoreadnext:
∙Morecomplexfunctions:
namespaces,optionalparametersandallowedrequestmethods.
∙Complexobjectserializations:
chaining,including,conditionalserializations,serializationswithparameters.
∙Authentication:
Cookie,HTTPBasic,HTTPDigestandOAuth.
∙APIdocumentation:
HowtotelltheworldaboutyourAPI.
Tags:
∙djangoweb2.0bynotes
Follow-upsforthisentry:
∙BuildingawebsiteAPIwithDjango.Part2a:
APIauthentication
Relatedentries(automaticallygenerated):
∙BuildingawebsiteAPIwithDjango.Part4:
Complexfunctions
∙Abetter(?
)serializationframework
∙Abetter(?
)serializationframework:
part2(firstalpharelease)
∙IntroducingFRF,theFiam'sRSSFramework
∙Wapireleasecomingnextweek
∙BuildingawebsiteAPIwithDjango.Part5:
Serialization
∙BuildingawebsiteAPIwithDjango.Part2a:
APIauthentication
∙BuildingawebsiteAPIwithDjango.Part3:
OAuthinDjango
BuildingawebsiteAPIwithDjango.Part2a:
APIauthentication
AsGregorMülleggersuggested,I'mnowwritingaboutAPIauthentication.Thisarticletalksonlyaboutuserauthenticationmethodswithoutexternal#外部dependencies#依赖,whilemethodswhichrequireotherapplicationshavebeenleftforthenextarticle.Iwasgoingtoincludethemallinonearticle,butsinceIwouldalsoneedtoexplainhowdjango-digestanddjango-oauthspwork,thisarticlewouldbetoolong.
HowauthenticationworksinWAPI
AuthenticationinWAPIworksbyusingamiddlewarelayer#中间件.WAPIshipswithauthenticationmiddlewareforHTTPBasic,HTTPDigestandOAuth.You'llusuallyneedtosubclass#子类oneoftheprovided#提供middlewares,sincetheauthenticationrealm#境界,域ispartoftheclass.
Whenyouplug#插入aWAPIbindingyoucanchoosetoaddanauthenticationmiddlewareclasstoit.Addingmultiple#多个authenticationclassesatthesameAPIurlisnotsupported,sincedifferentauthenticationmethodsreturndifferentWWW-Authenticate.However,youcansupportmultipleauthenticationmethodsbyusingmultiple#多个APIurls.Forexample,let'sseemyurls.pyatbyNotes:
#urls.py
fromnotes.apiimportBynotesApi,ApiAuthOAuth,ApiAuthBasic
...
(r'^api/1.0/rest/oauth/%s$'%RestBinding.PATTERN,RestBinding(auth=ApiAuthOAuth(),api=BynotesApi())),
(r'^api/1.0/rest/basic/%s$'%RestBinding.PATTERN,RestBinding(auth=ApiAuthBasic(