Skip to content

Commit

Permalink
Merge branch 'release/0.8.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
pavlov99 committed Apr 9, 2015
2 parents 27fa050 + c8cfe83 commit d9da9d2
Show file tree
Hide file tree
Showing 20 changed files with 411 additions and 257 deletions.
9 changes: 9 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
2015-04-09 Kirill Pavlov <kirill.pavlov@phystech.edu>

* Add resource clean method. It is excecuted after request
deserialization and before model create/update methods. It allows to
validate request. Useful if validation requires user access
(permission check). If validation does not require user, it is better
to use standard Django forms falidation.
* Add application exception classes.

2015-04-08 Kirill Pavlov <kirill.pavlov@phystech.edu>

* Add Partial form support for PUT request
Expand Down
3 changes: 2 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ DJANGO_ADMIN=$(shell which django-admin.py)
SETTINGS_TEST=tests.testapp.settings.test
SETTINGS_DEV=tests.testapp.settings.dev
PARAMS_DEV=--settings=$(SETTINGS_DEV) --pythonpath=$(CURDIR)
SPHINXBUILD=sphinx-build
BIN_DOCS=$(CURDIR)/docs/.env/bin
SPHINXBUILD=$(BIN_DOCS)/sphinx-build

all: $(ENV)
@echo "Virtualenv is installed"
Expand Down
4 changes: 2 additions & 2 deletions docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source

.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext

Expand Down
40 changes: 0 additions & 40 deletions docs/jsonapi.rst

This file was deleted.

7 changes: 0 additions & 7 deletions docs/modules.rst

This file was deleted.

Empty file removed docs/pages/examples.rst
Empty file.
55 changes: 0 additions & 55 deletions docs/pages/resource.rst

This file was deleted.

1 change: 0 additions & 1 deletion docs/requirements.txt

This file was deleted.

9 changes: 6 additions & 3 deletions docs/conf.py → docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import sys
import os

sys.path.insert(0, os.path.abspath('..'))
sys.path.insert(0, os.path.abspath('../..'))

from jsonapi import version, PROJECT

Expand All @@ -35,6 +35,7 @@
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinxcontrib.napoleon',
'sphinx.ext.coverage',
'sphinx.ext.mathjax',
'sphinx.ext.viewcode',
Expand All @@ -54,7 +55,7 @@

# General information about the project.
project = PROJECT
copyright = '2014, Kirill Pavlov'
copyright = '2014-2015, Kirill Pavlov'

# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
Expand Down Expand Up @@ -107,12 +108,14 @@

# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
html_theme = 'sphinx_rtd_theme'

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
import sphinx_rtd_theme
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]

# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
Expand Down
19 changes: 4 additions & 15 deletions docs/index.rst → docs/source/index.rst
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
.. jsonapi documentation master file, created by
sphinx-quickstart on Mon Jun 9 10:29:02 2014.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to json:api's documentation!
====================================

.. warning:: This documentation is in development and not updated frequently.
Check tests and raise issue or question if you have any.

.. toctree::
:maxdepth: 3

modules.rst
pages/resource.rst
resource.rst

Installation
============
Expand Down Expand Up @@ -90,11 +87,3 @@ curl -v -H "Content-Type: application/vnd.api+json" 127.0.0.1:8000/api/author
Test Application Models
=======================
.. image:: models.png


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
File renamed without changes
105 changes: 105 additions & 0 deletions docs/source/resource.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
JSONAPI Resource
================

Resources are related to Django models.
Basic customization is done in Resource.Meta class.
Exampele of resource declaration is shown below:

.. code-block:: python
from jsonapi.api import API
from jsonapi.resource import Resource
from django.conf import settings
api = API()
@api.register
class UserResource(Resource):
class Meta:
model = settings.AUTH_USER_MODEL
authenticators = [Resource.AUTHENTICATORS.SESSION]
fieldnames_exclude = 'password',
@api.register
class AuthorResource(Resource):
class Meta:
model = 'testapp.Author'
allowed_methods = 'GET', 'POST', 'PUT', 'DELETE'
@api.register
class PostWithPictureResource(Resource):
class Meta:
model = 'testapp.PostWithPicture'
fieldnames_include = 'title_uppercased',
page_size = 3
@staticmethod
def dump_document_title(obj):
return obj.title
Available Meta parameters:

+--------------------+---------------------------+-----------------------+-----------------------------------+
| Name | Type | Default | Usage |
+--------------------+---------------------------+-----------------------+-----------------------------------+
| model | str | None. Need to specify | '<appname>.<modelname>' |
+--------------------+---------------------------+-----------------------+-----------------------------------+
| allowed_methods | tuple | ('GET') | tuple of capitalized HTTP methods |
+--------------------+---------------------------+-----------------------+-----------------------------------+
| authenticators | list | [] | [Resource.AUTHENTICATORS.SESSION] |
+--------------------+---------------------------+-----------------------+-----------------------------------+
| fieldnames_include | list | [] | list of field names |
+--------------------+---------------------------+-----------------------+-----------------------------------+
| fieldnames_exclude | list | [] | list of field names |
+--------------------+---------------------------+-----------------------+-----------------------------------+
| page_size | int | None | integer if need pagination |
+--------------------+---------------------------+-----------------------+-----------------------------------+
| form | django.forms.Form Default | ModelForm | form to use |
+--------------------+---------------------------+-----------------------+-----------------------------------+

GET/POST/PUT/DELETE method kwargs
---------------------------------

+---------+--------------------------------+
| name | note |
+---------+--------------------------------+
| request | Django request |
+---------+--------------------------------+
| ids | ids in request url, optional |
+---------+--------------------------------+

Exceptions
----------

.. note:: These exceptions are application specific. Than means that they are
raised inside resource get/post/put/delete methods handlers but not in api.
They are handled in request handler and serialized into correct response
document with "errors" attribute on the top level.

Error standard http://jsonapi.org/format/#errors says that every member of error
object could be optional, but suggest to use some. JSONAPI defines common
exceptions and allows user to raise own ones. It uses code, status, title and
detail members for every exception. Sometimed members links, paths and data (not
suggested by document) could be added.

.. warning:: Exceptions are still in development. Codes of existing exceptions
would not be changed, but titles could.

+-------+--------+-----------------------------+--------------------------------+
| Code | Status | Title | Class |
+-------+--------+-----------------------------+--------------------------------+
| 32000 | 400 | General JSONAPI Error | JSONAPIError |
+-------+--------+-----------------------------+--------------------------------+
| 32001 | 403 | Resource Forbidden Error | JSONAPIForbiddenError |
+-------+--------+-----------------------------+--------------------------------+
| 32100 | 400 | Resource Validation Error | JSONAPIResourceValidationError |
+-------+--------+-----------------------------+--------------------------------+
| 32101 | 400 | Model Form Validation Error | JSONAPIFormValidationError |
+-------+--------+-----------------------------+--------------------------------+
| 32102 | 400 | Model Form Save Error | JSONAPIFormSaveError |
+-------+--------+-----------------------------+--------------------------------+
| 32103 | 400 | Database Integrity Error | JSONAPIIntegrityError |
+-------+--------+-----------------------------+--------------------------------+
2 changes: 1 addition & 1 deletion jsonapi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
""" JSON:API realization."""
__version = (0, 8, 3)
__version = (0, 8, 4)

__version__ = version = '.'.join(map(str, __version))
__project__ = PROJECT = __name__
41 changes: 21 additions & 20 deletions jsonapi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,21 +232,17 @@ def handler_view_put(self, resource, **kwargs):
if 'ids' not in kwargs:
return HttpResponse("Request SHOULD have resource ids", status=400)

try:
data = resource.put(**kwargs)
if "errors" in data:
response = HttpResponse(
json.dumps(data, cls=DatetimeDecimalEncoder),
content_type=self.CONTENT_TYPE, status=400)
return response

data = resource.put(**kwargs)
if "errors" in data:
response = HttpResponse(
json.dumps(data, cls=DatetimeDecimalEncoder),
content_type=self.CONTENT_TYPE, status=200)
content_type=self.CONTENT_TYPE, status=400)
return response
except JSONAPIError as e:
return HttpResponse(
e.message, content_type=self.CONTENT_TYPE, status=e.status_code)

response = HttpResponse(
json.dumps(data, cls=DatetimeDecimalEncoder),
content_type=self.CONTENT_TYPE, status=200)
return response

def handler_view_delete(self, resource, **kwargs):
if 'ids' not in kwargs:
Expand Down Expand Up @@ -282,11 +278,16 @@ def handler_view(self, request, resource_name, ids=None):
if ids is not None:
kwargs['ids'] = ids.split(",")

if request.method == "GET":
return self.handler_view_get(resource, **kwargs)
elif request.method == "POST":
return self.handler_view_post(resource, **kwargs)
elif request.method == "PUT":
return self.handler_view_put(resource, **kwargs)
elif request.method == "DELETE":
return self.handler_view_delete(resource, **kwargs)
try:
if request.method == "GET":
return self.handler_view_get(resource, **kwargs)
elif request.method == "POST":
return self.handler_view_post(resource, **kwargs)
elif request.method == "PUT":
return self.handler_view_put(resource, **kwargs)
elif request.method == "DELETE":
return self.handler_view_delete(resource, **kwargs)
except JSONAPIError as e:
return HttpResponse(
json.dumps({"errors": [e.data]}, cls=DatetimeDecimalEncoder),
content_type=self.CONTENT_TYPE, status=e.status)

0 comments on commit d9da9d2

Please sign in to comment.