Plone JSON API -- Routes
Project description
plone.jsonapi.routes
- Author:
Ramon Bartl
- Version:
0.3
Introduction
This is an add-on package for plone.jsonapi.core which provides some basic URLs for Plone standard contents (and more).
Motivation
The routes package is built on top of the plone.jsonapi.core package to allow Plone developers to build modern (JavaScript) web UIs which communicate through a RESTful API with their Plone site.
Compatibility
The plone.jsonapi.routes is compatible with Plone 4.
Installation
The official release is on pypi, so you have to simply include plone.jsonapi.routes to your buildout config.
Example:
[buildout] ... [instance] ... eggs = ... plone.jsonapi.core plone.jsonapi.routes
The routes for the standard Plone content types get registered on startup.
The following URL should be available after startup:
API URL
After installation, the Plone API routes are available below the plone.jsonapi.core root URL (@@API) with the base /plone/api/1.0, for example http://localhost:8080/Plone/@@API/plone/api/1.0/api.json.
There is also an overview of the registered routes which can be accessed here:
API Routes
- BASE_URL:
/plone/api/1.0
This is an overview of the provided API Routes. The basic content routes provide all an interface for CRUD operations.
CRUD URL Scheme:
OPERATION |
URL |
METHOD |
---|---|---|
VIEW |
<BASE_URL>/<RESOURCE>/<uid:optional> |
GET |
CREATE |
<BASE_URL>/<RESOURCE>/create/<uid:optional> |
POST |
UPDATE |
<BASE_URL>/<RESOURCE>/update/<uid:optional> |
POST |
DELETE |
<BASE_URL>/<RESOURCE>/delete/<uid:optional> |
POST |
Request Parameters
All GET resources acceppt request parameters.
Parameter |
Type |
Description |
---|---|---|
limit |
number |
limit the search results |
sort_on |
index |
sort the results by the given catalog index |
sort_order |
asc/desc |
sort ascending/descending |
q |
query |
search the SearchableText index for the given query string |
creator |
username |
search for items which were created by the given user |
Examples
Search for documents and return 10 results
http://localhost:8080/Plone/@@API/plone/api/1.0/documents?limit=10
Search all content created by admin
http://localhost:8080/Plone/@@API/plone/api/1.0/documents?creator=admin
Search for documents which contain the text Open-Source
http://localhost:8080/Plone/@@API/plone/api/1.0/documents?q=Open-Source
Search for all documents created by admin which contain the text Open-Source
http://localhost:8080/Plone/@@API/plone/api/1.0/documents?q=Open-Source&creator=admin
Response Format
The response format is for all resources the same.
Example:
{ url: "http://localhost:8080/Plone/@@API/plone/api/1.0/documents", count: 0, _runtime: 0.0021538734436035156, items: [ ] }
- url
The resource root url
- count
Count of found results
- _runtime
The processing time in milliseconds after the request was received until the respone was prepared.
- items
An array of result items
Content URLs
- BASE_URL:
/plone/api/1.0
- SCHEME:
BASE_URL/RESOURCE
All content informations are dynamically gathered by the contents schema definition through the IInfo adapter. It is possible to define a more specific adapter for your content type to control the data returned by the API.
Resource |
Description |
---|---|
folders |
Resource for all Folder contents |
documents |
Resource for all Page contents |
events |
Resource for all Event contents |
files |
Resource for all File contents |
images |
Resource for all Image contents |
links |
Resource for all Link contents |
newsitems |
Resource for all News Item contents |
topics |
Resource for all Collection (old style) contents |
collections |
Resource for all Collection contents |
Special URLs
- BASE_URL:
/plone/api/1.0
- SCHEME:
BASE_URL/RESOURCE
Beside the content URLs described above, there are some other resources available in this extension.
Resource |
Description |
---|---|
users |
Resourece for all Plone Users |
users/current |
Get the current logged in user |
Write your own API
This package is designed to provide an easy way for you to write your own JSON API for your custom Dexterity content types.
The plone.jsonapi.example package shows how to do so.
Example
Lets say you want to provide a simple CRUD JSON API for your custom Dexterity content type. You want to access the API directly from the plone.jsonapi.core root URL (http://localhost:8080/Plone/@@API/).
First of all, you need to import the CRUD functions of plone.jsonapi.routes:
from plone.jsonapi.routes.api import get_items from plone.jsonapi.routes.api import create_items from plone.jsonapi.routes.api import update_items from plone.jsonapi.routes.api import delete_items
To register your custom routes, you need to import the router module of plone.jsonapi.core. The add_route decorator of this module will register your function with the api framework:
from plone.jsonapi.core import router
The next step is to provide the a function which get called by the plone.jsonapi.core framework:
@router.add_route("/example", "example", methods=["GET"]) def get(context, request): return {}
Lets go through this step by step…
The @router.add_route(…) registers the decorated function with the framework. So the function will be invoked when someone sends a request to @@API/example.
The framework registers the decorated function with the key example. We also provide the HTTP Method GET which tells the framework that we only want to get invoked on a HTTP GET request.
When the function gets invoked, the framework provides a context and a request. The context is usually the Plone site root, because this is where the base view (@@API) is registered. The request contains all needed parameters and headers from the original request.
At the moment we return an empty dictionary. Lets provide something more useful here:
@router.add_route("/example", "example", methods=["GET"]) def get(context, request=None): items = get_items("my.custom.type", request, uid=None, endpoint="example") return { "count": len(items), "items": items, }
The get_items function of the plone.jsonapi.routes.api module does all the heavy lifting here. It searches the catalog for my.custom.type contents, parses the request for any additional parameters or returns all informations of the “waked up” object if the uid is given.
The return value is a list of dictionaries, where each dictionary represents the information of one result, be it a catalog result or the full information set of an object.
Now we need a way to handle the uid with this function. Therefore we can simple add another add_route decorator around this function:
@router.add_route("/example", "example", methods=["GET"]) @router.add_route("/example/<string:uid>", "example", methods=["GET"]) def get(context, request=None, uid=None): return get_batched("my.custom.type", request, uid=uid, endpoint="example")
This function handles now URLs like @@API/example/4b7a1f… as well and invokes the function directly with the provided UID as the parameter. The get_items tries to find the object with the given UID to provide all informations of the waked up object.
The CREATE, UPDATE and DELETE functionality is basically identical with the basic VIEW function above, so here in short:
# CREATE @router.add_route("/example/create", "example_create", methods=["POST"]) @router.add_route("/example/create/<string:uid>", "example_create", methods=["POST"]) def create(context, request, uid=None): items = create_items("plone.example.todo", request, uid=uid, endpoint="example") return { "count": len(items), "items": items, } # UPDATE @router.add_route("/example/update", "example_update", methods=["POST"]) @router.add_route("/example/update/<string:uid>", "example_update", methods=["POST"]) def update(context, request, uid=None): items = update_items("plone.example.todo", request, uid=uid, endpoint="example") return { "count": len(items), "items": items, } # DELETE @router.add_route("/example/delete", "example_delete", methods=["POST"]) @router.add_route("/example/delete/<string:uid>", "example_delete", methods=["POST"]) def delete(context, request, uid=None): items = delete_items("plone.example.todo", request, uid=uid, endpoint="example") return { "count": len(items), "items": items, }
See it in action
A small tec demo is available on youtube:
License
MIT - do what you want
Changelog
0.3 - 2014-10-14
FIXED ISSUES
https://github.com/collective/plone.jsonapi.routes/issues/16: Files can not be created/updated with base64 encoded data
https://github.com/collective/plone.jsonapi.routes/issues/10: Fails on NamedBlobFile dexterity fields
https://github.com/collective/plone.jsonapi.routes/pull/11: Typo in brain adapter
https://github.com/collective/plone.jsonapi.routes/issues/14: Missing UIDs for complete objects
ENHANCEMENTS
https://github.com/collective/plone.jsonapi.routes/issues/12: Add batching
https://github.com/collective/plone.jsonapi.routes/issues/13: Add a flag to return the full fledged object results immediately
https://github.com/collective/plone.jsonapi.routes/issues/19: Need to do a GET on a file using file path without using uid
https://github.com/collective/plone.jsonapi.routes/issues/18: destination handling
https://github.com/collective/plone.jsonapi.routes/issues/3: Add buildout configs inside package
DOCUMENTATION
https://github.com/collective/plone.jsonapi.routes/issues/2: Sphinx documentation started
0.2 - 2014-03-05
FIXED ISSUES
https://github.com/ramonski/plone.jsonapi.routes/issues/5: Dexterity support
https://github.com/ramonski/plone.jsonapi.routes/issues/4: Update on UID Urls not working
https://github.com/ramonski/plone.jsonapi.routes/issues/1: Started with some basic browsertests
API CHANGES
API root url provided.
Image and file fields are now rendered as a nested structure, e.g:
{ data: b64, size: 42, content_type: "image/png" }
Workflow info is provided where possible, e.g:
{ status: "Private", review_state: "private", transitions: [ { url: ".../content_status_modify?workflow_action=submit", display: "Puts your item in a review queue, so it can be published on the site.", value: "submit" }, ], workflow: "simple_publication_workflow" }
0.1 - 2014-01-23
first public release
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.