Welcome to restfulgrok’s documentation!

restfulgrok provides a very simple RESTful view mixin for five.grok.View. It is not meant to be a full-featured REST library, only a quick solution for simple REST APIs using five.grok.View.

Features:

  • Content negotiation:
    • Assumes same input and out mimetype (simplifies the implementation)
    • Can be specified in a GET parameter (E.g.: ?mimetype=application/yaml)
    • Can be specified use HTTP ACCEPT header.
    • Supports:
  • HTTP response helpers for common response types.

Getting started

Create a class that inherit from GrokRestViewMixin:

from restfulgrok.fancyhtmlview import GrokRestViewWithFancyHtmlMixin


class ExampleRestViewMixin(GrokRestViewWithFancyHtmlMixin):
    def handle_get(self):
        # Return something that can be encoded by JSON and YAML
        return {'hello': 'world'}

    def handle_post(self):
        try:
            # Decode request body as a dict (JSON or YAML)
            request_data = self.get_requestdata_dict()
        except ValueError, e:
            # Did not get a dict
            return self.response_400_bad_request({'error': str(e)})
        else:
            # save to database or something....
            # --- not included in example ---

            # Respond with 201 status and the request_data
            # NOTE: If you just return normally, 200 response status is used
            return self.response_201_created(request_data)

    def handle_put(self):
        try:
            # Decode request body as a dict (JSON or YAML)
            request_data = self.get_requestdata_dict()
        except ValueError, e:
            # Did not get a dict
            return self.response_400_bad_request({'error': str(e)})
        else:
            data = request_data.copy() # pretend we got this from a database
            data['last-modified'] = 'now' # Update some data
            # would save here if this was real...

            # NOTE: If you just return normally, 200 response status is used
            return {'Updated': 'yes',
                    'result': data}

And a testcase:

from unittest import TestCase
from restfulgrok.mock import MockResponse
from restfulgrok.mock import MockRequest
from restfulgrok.mock import MockContext

from example import ExampleRestViewMixin


class MockExampleRestMixin(ExampleRestViewMixin):
    def __init__(self, method='GET', body=''):
        self.response = MockResponse()
        self.request = MockRequest(method, body=body)
        self.context = MockContext()

class TestExampleRestMixin(TestCase):
    def test_get(self):
        result = MockExampleRestMixin('GET').handle()
        self.assertEquals(result, {'hello': 'world'})

    def test_post(self):
        import json
        data = {'a': 'test'}
        result = MockExampleRestMixin('POST', body=json.dumps(data)).handle()
        self.assertEquals(result, {'a': 'test'})

    def test_put(self):
        import json
        data = {'a': 'test'}
        result = MockExampleRestMixin('PUT', body=json.dumps(data)).handle()
        self.assertEquals(result,
                          {'Updated': 'yes',
                           'result': {'a': 'test',
                                      'last-modified': 'now'}})


if __name__ == '__main__':
    import unittest
    unittest.main()

And finally use the mixin to create a grok.View:

from five import grok
class ExampleRestView(ExampleRestViewMixin, grok.View):
    grok.context(IMyInterface)
    grok.name('rest')

Extending and styling the HtmlContentType view

The html provided with restfulgrok.fancyhtmlview.HtmlContentType does not have a stylesheet, however it is designed to work with Bootstrap. Just override the template, and override the head_extra block. For example:

  1. Create your own html content type (example assumes your app is my.package):

    from jinja2 import Environment, PrefixLoader, PackageLoader
    class MyHtmlContentType(HtmlContentType):
        template_name = 'fancyhtmlview.jinja.html'
        template_environment = Environment(loader = PrefixLoader({
            'restfulgrok': PackageLoader('restfulgrok'),
            'mypackage': PackageLoader('my.package')
        }))
    
  2. Create my/package/templates and my/package/staticfiles.

  3. Add static directory to configure.zcml:

    <browser:resourceDirectory
        name="my.package"
        directory="staticfiles"
        />
    
  4. Create your own template, my/package/templates/view.jinja.html, extending the one from restfulgrok:

    {% extends "restfulgrok/fancyhtmlview.jinja.html" %}
    {% block head_extra %}
        <link rel="stylesheet/less" href="++resource++my.package/bootstrap/less/bootstrap.less">
        <script src="++resource++my.package/less-1.3.0.min.js"></script>
    {% endblock %}
    

Indices and tables