Skip to content

oikoumene/plone.jsonapi.routes

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

plone.jsonapi.routes

Author

Ramon Bartl

Version

0.2

Table of Contents

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.

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.

Note

Please see the documentation of plone.jsonapi.core for the API root URL.

There is also an overview of the registered routes which can be accessed here:

http://localhost:8080/Plone/@@API/plone/api/1.0/api.json

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

Important

the optional UID of the create, update and delete URLs is to specify the target container where to create the content. If this is omitted, the API expects a parameter parent_uid in the request body JSON. If this is also not found, an API Error will be returned.

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

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.

Note

without the uid given, only catalog brains are returned

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):
    items = get_items("my.custom.type", request, uid=uid, endpoint="example")
    return {
        "count": len(items),
        "items": items,
    }

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.

Note

API URLs which contain the UID are automatically generated with the provided endpoint

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:

http://www.youtube.com/watch?v=MiwgkWLMUqk

License

MIT - do what you want

About

Plone JSONAPI Route Providers

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Python 100.0%