Package: genericclient
A generic client for RESTful APIs based onrequests.For an async version based onaiohttp, seegenericclient-aiohttp(Python 3.5+ only).Installation$ pip install genericclientQuickstartfromgenericclientimportGenericClientmyclient=GenericClient(api_url)myresource=myclient.resources.get(id=1)actives=myclient.posts.filter(active=True)UsageInstantiationmyclient = GenericClient(url, auth=None, session=None, adapter=None, trailing_slash=False, autopaginate=None)Arguments:url: The root URL of your APIauth: The auth for your API. You can pass anything thatrequestscan accept as auth.session: Pass a session instance to haverequestsuse that session. IfNone(the default), it will instantiate an instance ofrequests.sessionfor you.adapter: optional session adapter forrequests.trailing_slash: You can set this toTrueif your API’s URLs end with a/autopaginate: You can set this to a callable to fetch all pages resulting from a request. Currently, the only callable included isgenericclient.pagination.link_header, which supports [RFC5988](https://tools.ietf.org/html/rfc5988).EndpointsEndpoints are available as properties and items on the main instance:myclient.posts.all()# GET /posts/myclient["active-users"].all()# GET /active-users/.all()Retrieves all resources (essentially a simpleGETon the endpoint):myclient.posts.all()# GET /posts/.filter().filter(**kwargs)calls aGETwithkwargsas querystring values:myclient.posts.filter(blog=12,status=1)# GET /posts/?blog=12&status=1.get(**kwargs)A special case of.filter().Ifkwargscontainsid,pk,slugorusername, that value will
be used in the URL path, in that order.Otherwise, it calls aGETwithkwargsas querystring values.If the returned list is empty, will raiseResourceNotFound.If the returned list contains more than 1 resource, will raiseMultipleResourcesFoundNote that.get()will return aResource, not a list ofResourcesmyclient.posts.filter(blog=12,status=1)# GET /posts/?blog=12&status=1myclient.posts.filter(id=12)# GET /posts/12/myclient.posts.filter(slug='12-ways-clickbait')# GET /posts/12-ways-clickbait/.create(payload)Will result in aPOST, withpayload(adict) as the request’s body,
returning a newResource:post=myclient.posts.create({'blog':12,'status':1})# POST /posts/.get_or_create(defaults, **kwargs)Issues a GET to fetch the resource. If the resource is not found, issues a POST
to create the resource:# Assuming it doesn't existpost=myclient.posts.get_or_update(slug='my-post',defaults={'status':1})# GET /posts/my-post/, then POST /posts/.create_or_update(payload)Ifpayloadcontains a key called'id', will issue aPUT. If the
server returns a400error, aPATCHrequest will be re-issued.
Ifpayload`does not contains'id', it will issue aPOST:post=myclient.posts.create_or_update({'status':1})# POST /posts/post=myclient.posts.create_or_update({'id':1234,'status':1})# PUT /posts/1234/post=myclient.posts.create_or_update({'id':1234})# PUT /posts/1234/# <- server returns 400# -> PATCH /posts/1234/.delete(pk)Will issue aDELETE, and will usepkas part of the URL:myclient.posts.delete(24)# DELETE /posts/24/ResourcesAll endpoints methods (with the exception of.delete()) return either aResourceor a list ofResources.AResourceis just a wrapping class for adict, where keys can be accessed
as properties.Additionally,Resources have a special property called.payload, which
contains the original payload received from the server.Resources have the following methods:Resource.delete()will result in aDELETE, withResource.idas
par of the URL:blog=myclient.posts.create({'blog':12,'status':1})# POST /posts/blog.delete()# DELETE /blog/345/ -- the ID 345 was returned by the server in the previous responseResource.save()will result in aPUT, withResource.idas
par of the URL. If the
server returns a400error, aPATCHrequest will be re-issued:post=myclient.posts.create({'blog':12,'status':1})# POST /posts/post.status=2post.save()# PUT /posts/345/post=Resource(id=345,status=1)post.save()# PUT /posts/345/# <- server returns 400# -> PATCH /posts/345/ResourceSetsWhenever a method returns a list of Resources, they list will be wrapped in aResultSet.A ResultSet is a just alistobject, with the addition of a.responsecontaining the original response from the server.Customizing Endpoints and ResourcesResources can be customized by subclassinggenericclient.Resource.The most common reason is specifying the name of the primary key:fromgenericclientimportResourceclassPostResource(Resource):pk_name='slug'Endpoints can be customized by subclassinggenericclient.Endpoint:formgenericclientimportEndpointclassPostEndpoint(Endpoint):resource_class=PostResourceYou can then subclassgenericclient.GenericClientto tell the client which endpoint classes to use on each endpoint:fromgenericclientimportGenericClientclassClient(GenericClient):endpoint_classes={'posts':PostEndpoint,}RoutesIf your API has some non-RESTful calls within the main endpoints (sometimes referred asdetail_routeandlist_route), you can usegenericclientto call them:myclient.posts(id=123).publish(date=tomorrow)myclient.blogs().ping()Routes http calls usePOSTby default, but you can specify something else by using the_methodargument:myclient.posts(_method='get',id=123).pingbacks()myclient.blogs(_method='get').visits()Note that this calls will return an instance ofgenericclient.ParsedResponse, instead of instances ofgenericclient.Resource,LicenseLicensed under the MIT License.