Skip to content

Pokie Views

Pokie extends on the class-based views on Flask, and offers additional features such as automatic request body unmarshall, custom-named view methods (a-la Controllers), response helpers and authentication.

Using Pokie views is not mandatory; however, they are quite handy to implement REST-based APIs, and they provide extra degrees of automation and JSON interaction.

Using PokieView

PokieView is the base view class of Pokie. This class implements the following functionalities:

  • optional automatic body deserialization and validation with a RequestRecord class;
  • pre-dispatch hook system;
  • json-first exception handler;
  • json helpers;

Body deserialization & validation

The request body can be automatically deserialized and validated for specific http methods (POST, PUT, PATCH) by specifying a RequestRecord class in the request_class class attribute. If the submitted data fails validation, a RequestRecord error response is returned. If validation is successful, the handler method is called and the RequestRecord object instance can be accessed via self.request property.

Simple example with a custom RequestRecord class and a POST handler:

from rick.form import RequestRecord, field
from pokie.http import PokieView

# JSON Request validation 
class FilmRequest(RequestRecord):
    fields = {
        'id': field(validators='id|numeric'),
        'title': field(validators='required'),
        'description': field(validators=''),
        'releaseYear': field(validators='numeric'),
        'rating': field(validators=''),
        'lastUpdate': field(validators='required|iso8601'),
        'sinopse': field(validators='maxlen:2048'),
    }


class FilmView(PokieView):
    # use FilmRequest for automatic body deserialization and validation
    request_class = FilmRequest

    def post(self):

        print("submitted data:")
        #retrieve dict with all submitted values
        print(self.request.get_data())

        # return a standard JSON success response with code 200:
        # {"success":true,"message":""}
        return self.success() 

Custom Response objects

PokieView responses are traditionally either JsonResponse or CamelCaseJsonResponse objects; however, it is quite simple to override the default response class to use your own custom implementation - just extend pokie.http.ResponseRendererInterface, and refer it in your view, using the response_class attribute:

from pokie.http import PokieView, ResponseRendererInterface


class HamburgerResponse(ResponseRendererInterface):

    def assemble(self, _app, **kwargs):
        # our custom Response only returns "hamburger"
        return "hamburger"


class CustomResponseView(PokieView):
    # custom response class to be used, intead of the default one
    response_class = HamburgerResponse

    def get(self):
        # just generate a response
        return self.success()

CamelCase response

PokieView can, automatically, convert keys from the snake_case notation to camelCase before assembling the JSON response. This functionality is provided by the pokie.http.CamelCaseJsonResponse class, and is controlled by the PokieView.camel_case attribute:

from pokie.http import PokieView
from pokie_test.dto import CustomerRecord


class CamelCaseResponseView(PokieView):
    # enable automatic camelCasing of responses    
    camel_case = True

    def get(self):
        record = CustomerRecord(
            company_name="company_name",
            contact_name="contact_name",
            contact_title="contact_title",
            address="address"

        )
        return self.success(record)

Generated response:

{
   "success":true,
   "data":{
      "address":"address",
      "companyName":"company_name",
      "contactName":"contact_name",
      "contactTitle":"contact_title"
   }
}

Custom pre-dispatch hooks

Pre-dispatch hooks work as middlweware methods - they can be used to perform additional validations. If a given hook returns a ResponseReturnValue, the dispatch exits with the specified response. If a hook is run successfully, it should return None.

Example:

from rick.form import RequestRecord, field
from pokie.http import PokieView

# JSON Request validation 
class FilmRequest(RequestRecord):
    fields = {
        'id': field(validators='id|numeric'),
        'title': field(validators='required'),
        'description': field(validators=''),
        'releaseYear': field(validators='numeric'),
        'rating': field(validators=''),
        'lastUpdate': field(validators='required|iso8601'),
        'sinopse': field(validators='maxlen:2048'),
    }


class FilmView(PokieView):
    # use FilmRequest for automatic body deserialization and validation
    request_class = FilmRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # add hook method to the hook list
        self.dispatch_hooks.append('_my_hook')

    def _my_hook(self, method: str, *args: Any, **kwargs: Any) -> Optional[ResponseReturnValue]:
        """
        Custom hook to be executed on dispatch
        """
        if method == 'get':
            return self.error('We are blocking GET requests via dispatch hooks')
        return None

    def post(self):

        print("submitted data:")
        #retrieve dict with all submitted values
        print(self.request.get_data())

        # return a standard JSON success response with code 200:
        # {"success":true,"message":""}
        return self.success()