Resources

Resources are the core of ripozo. These define what can be accessed and the actions you can perform on those resources. They are designed to be common across all ripozo integrations. In other words, if they are designed correctly, a resource should be able to be plugged into different web frameworks and managers should be able to be plugged in and out.

Minimal Application

from ripozo import ResourceBase, apimethod
from ripozo import ResourceBase, apimethod

class MyResource(ResourceBase):

    @apimethod(methods=['GET'])
    def say_hello(cls, request):
        return cls(properties=dict(hello='world'))

That is your most basic resource. It simply has one method available to act on the resource. The ripozo.decorators.apimethod decorator indicates which methods are going to be exposed by the api. If we were to add another method, that was not decorated by the @apimethod that method would not be exposed in the api

class MyResource(ResourceBase):

    # This method is exposed by the api
    @apimethod(methods=['GET'])
    def say_hello(cls, request):
       return cls(properties=cls.get_properties())

    # This method will not be exposed
    @classmethod
    def get_properties():
       return dict(hello='world')

You’ll notice that methods decorated by apimethod are class methods. Additionally, an apimethod must always return an instance of a ResourceBase subclass. ResourceBase subclass instances, such as MyResource instances, describe what the resource being returned is. They describe both the properties of the resource and the actions available to perform on that resource.

What about the url?

So how would you access this resource? The first step would be to register it with a dispatcher (which we will get into in the next chapter). However, once you registered the url, you would be able to access the resource by using the “/my_resource” url with the GET http verb. There are two major parts to the url for a resource.

The first is the class property base_url. The ResourceBase.base_url specifies the common base url for all actions on the resource. It is constructed by taking the ResourceBase.resource_name class property and appending it the the ResourceBase.namespace class property [1]. Additionally, the ResourceBase.pks are taken and each one is added as a url_parameter [2].

By default the namespace is empty, the resource_name is the class underscore class name, and there are not pks.

>>> class MyResource(ResourceBase): pass
>>> print(MyResource.base_url)
/my_resource
class MyResource(ResourceBase):
    namespace = '/api'
    resource_name = 'resource'
    pks = ('id', 'secondary',)
>>> print(MyResource.base_url)
/api/resource/<id>/<secondary>

If you take a MyResource instance and get the url property on it, you will receive a valid url rather than just a template. It will take the properties that match the pks and plug them into the base_url template.

>>> resource = MyResource(properties=dict(id=3233, secondary='something'))
>>> print(resource.url)
/api/resource/3233/something

Cookbook

Individual endpoint url extension

In this case we want all but on of the urls to construct urls in the normal manner. But we have one endpoint that should have an extra path attribute.

For example all but one should be `/resource/<id>` but one should be `/resource/<id>/extension/<pk>`

class MyResource(ResourceBase):
    resource_name = 'resource'
    pks = ('id',)

    @apimethod()
    def first(cls, request):
        # Do something
        return cls(properties=request.url_params)

    @apimethod()
    def second(cls, request):
        # Do something else
        return cls(properties=request.url_params)

    # We need to add the wanted
    @apimethod(route='extension/<pk>')
    def extension_route(cls, request):
        # We'll also need to add the route extension explicitly
        # to the returned instance if we want to the resource's url to
        # correctly get constructed.
        pk = request.get('pk')
        return cls(properties=request.url_params, route_extension='extension/{0}'.format(pk))

If we inspect the endpoint dictionary we can see the following.

>>> print(MyResource.base_url)
/resource/<id>
>>> endpoint_dictionary = MyResource.endpoint_dictionary()
>>> print(endpoint_dictionary['first'][0]['route'])
/resource/<id>/
>>> print(endpoint_dictionary['extension_route'][0]['route'])
/resource/<id>/extension/<pk>

Also, we can see that making requests will properly return

>>> from ripozo import RequestContainer
>>> req = RequestContainer(url_params=dict(id=1, pk=2))
>>> res = MyResource.first(req)
>>> print(res.url)
/resource/1
>>> extended_req = RequestContainer(url_params=dict(id=1, pk=2))
>>> extended = MyResource.extension_route(extended_req)
>>> print(extended.url)
/resource/1/extension/2

Common base url

At some point you’ll probably want to group individual resources under a common base path. For example, you may want all of your resources to be grouped under a common `'/api'` resource path.

In most cases, you should be able to pass a base_url parameter to the constructor of a dispathcher. It will automatically prepend the `'/api'` to the routes.

import MyDispatcher

dispatcher = MyDispatcher(base_url='/api')
dispatcher.register_resources(MyResource, MyOtherResource)

In other cases this may be impractical. In that case we can take advantage of the namespace attribute.

class MyResource(ResourceBase):
    namespace = '/api'
>>> print(MyResource.base_url)
/api/my_resource

ResourceBase API

class ripozo.decorators.apimethod(route=u'', endpoint=None, methods=None, no_pks=False, **options)[source]

Decorator for declaring routes on a ripozo resource. Any method in a ResourceBase subclass that is decorated with this decorator will be exposed as an endpoint in the greater application. Although an apimethod can be decorated with another apimethod, this is not recommended.

Any method decorated with apimethod should return a ResourceBase instance (or a subclass of it).

__call__(func)[source]

The actual decorator that will be called and returns the method that is a ripozo route.

In addition to setting some properties on the function itself (i.e. __rest_route__ and routes), It also wraps the actual function calling both the preprocessors and postprocessors.

preprocessors get at least the cls, name of the function, request as arguments

postprocessors get the cls, function name, request and resource as arguments

Parameters:f (classmethod) –
Returns:The wrapped classmethod that is an action that can be performed on the resource. For example, any sort of CRUD action.
Return type:classmethod
__init__(route=u'', endpoint=None, methods=None, no_pks=False, **options)[source]

Initialize the decorator. These are the options for the endpoint that you are constructing. It determines what url’s will be handled by the decorated method.

class MyResource(ResourceBase):
    @apimethod(route='/myroute', methods=['POST', 'PUT']
    def my_method(cls, request):
        # ... Do something to handle the request and generate
        # the MyResource instance.
Parameters:
  • route (str|unicode) – The route for endpoint. This will be appended to the base_url for the ResourceBase subclass when constructing the actual route.
  • endpoint (str|unicode) – The name of the endpoint. Defaults to the function name.
  • methods (list[str|unicode]) – A list of the accepted http methods for this endpoint. Defaults to [‘GET’]
  • no_pks (bool) – If this flag is set to True the ResourceBase subclass’s base_url_sans_pks property will be used instead of the base_url. This is necessary for List endpoints where the pks are not part of the url.
  • options (dict) – Additionaly arguments to pass to the dispatcher that is registering the route with the application. This is dependent on the individual dispatcher and web framework that you are using.
__weakref__

list of weak references to the object (if defined)

Contains the base class for resources.

class ripozo.resources.resource_base.ResourceBase(properties=None, errors=None, meta=None, no_pks=False, status_code=200, query_args=None, include_relationships=True, route_extension=u'')[source]

ResourceBase makes up the core of ripozo. This is the class responsible for actually handling requests and appropriately constructing resources to return as a request. This class is not responsible for actually formatting the response, only for providing a standard resource that can be translated into the appropriate response by an adapter.

The @apimethod decorated methods are the endpoints that will be exposed in the api. @apimethod’s are classmethods that generally perform some action (such as updating a resource) and then generate instances of the class representing that resource. They take the class and a RequestContainer object as the arguments.

A minimal example would be

class MyResource(ResourceBase):
    @apimethod()
    def hello_world(cls, request):
        return cls(properties=dict(hello='world'))
Parameters:
  • __abstract__ (bool) – abstract classes are not registered by the ResourceMetaClass. In other words, their @apimethod decorated methods will not be exposed unless another class inherits from it. __abstract__ is not inherited.
  • _relationships (list) – The relationships that will be constructed by instances. The actual related resources will be contained in the instances related_resources list.
  • pks (list) – The pks for this resource. These, along with the namespace and resource_name are combined to generate the base url for the class.
  • manager (ManagerBase) – The BaseManager subclass that is responsible for persistence within the applictation. I.E. the AlchemyManager from ripozo-sqlalchemy
  • namespace (unicode) – The namespace of this resource. This is prepended to the resource_name and pks to create the url
  • resource_name (unicode) – The name of the resource.
  • preprocessors (list) – A list of functions that will be run before any apimethod is called.
  • postprocessors (list) – A list of functions that will be run after any apimethod from this class is called.
  • _links (dict) – Works similarly to relationships. The primary difference between this and links is that links will assume the resource is the same as this class if a relation is not specified. Additionally, links are supposed to be meta information effectively. They are not necessarily about this specific resource. For example, next and previous links for a list resource or created links when creating a new resource on a list resource.
  • append_slash (bool) – A flag that indicates whether the base urls should include a trailing slash or not.
__init__(properties=None, errors=None, meta=None, no_pks=False, status_code=200, query_args=None, include_relationships=True, route_extension=u'')[source]

Initializes a resource to pass to an adapter typically. An ResourceBase instance is supposed to fully represent the resource.

Parameters:
  • properties (dict) – The properties on
  • status_code (int) – The http status code that should be returned
  • errors (list) – A list of error that occurred. Typically not used.
  • meta (dict) – Meta information about the resource (for example the next page in a paginated list)
  • no_pks (bool) – Whether the resource should have primary keys or not. Helpful when returning a list of resources for example.
  • include_relationships (bool) – If not True, then this resource will not include relationships or links. This is primarily used to increase performance with linked resources.
  • query_args (list|tuple) – A list of the arguments that should be appended to the query string if necessary.
  • include_relationships – This flag is available to prevent infinite loops in resources that each have a relationship to the other.
  • route_extension (unicode) – A part of the url to append to the url. This is helpful in constructing the correct url for apimethods with a route defined.
__weakref__

list of weak references to the object (if defined)

classmethod endpoint_dictionary()[source]

A dictionary of the endpoints with the method as the key and the route options as the value

Returns:dictionary of endpoints
Return type:dict
get_query_arg_dict()[source]
Returns:Gets the query args that are available in the properties. This allows the user to quickly get the query args out.
Return type:dict
has_all_pks
Returns:Indicates whether an instance of this class has all of the items in the pks list as a key in the self.properties attribute.
Return type:bool
has_error
Returns:Whether or not the instance has an error
Return type:bool
item_pks

Gets a dictionary of an individual resource’s primary keys. The key of the dictionary is the name of the primary key and the value is the actual value of the primary key specified

Return type:dict
query_string
Returns:The generated query string for this resource
Return type:str|unicode
url

Lazily constructs the url for this specific resource using the specific pks as specified in the pks tuple.

Returns:The url for this resource
Return type:unicode
ripozo.resources.resource_base.create_url(base_url, **kwargs)[source]

Generates a fully qualified url. It iterates over the keyword arguments and for each key it replaces any instances of “<key>” with “value” The keys of the dictionary must be strings.

Parameters:
  • base_url (unicode) – The url template that will be used to generate an acutal url
  • kwargs (dict) – The dictionary of template variables and their associated values
Returns:

A complete url.

Return type:

unicode

[1]In ripozo, whenever urls are constructed, they are joined with a ‘/’. However, it will not allow multiple slashes in a row. For example, if you had a namespace of ‘/api/’ and resource_name of ‘/myresource’, it would still use ‘/api/myresource’ as the url. You can view more details at ripozo.utilities.join_url_parts()
[2]Url parameters in the base_url are indicating a a part of the whole path. Additionally, they are wrapped in angle brackets. For example, if you had the _resource_name = 'my_resource' and the _pks = ['id', 'secondary'] The base url would be '/my_resource/<id>/<secondary>