pyramid_restful
The pyramid_restful
project is an easy to use ReST service builder.
This project is a middleware plugin for the Pyramid framework, a flexible Python HTTP server.
Installation
pip install pyramid_restful
Documentation
Getting Started
ReSTful interfaces work by defining endpoints based on HTTP method
verbage for different resources. The pyramid_restful middle ware allows you to easily
create these endpoints out of your modules using the endpoint
decorator.
Let's assume that we have created a new website using the pcreate command from Pyramid. We would start with a site that looks like this:
MyProject/
myproject/
static/
templates/
__init__.py
tests.py
views.py
CHANGES.txt
MANIFEST.in
README.txt
development.ini
production.ini
setup.py
We will use this as the basis for the rest of the documentation to make it easy to follow along.
Configuring API
Edit the development.ini
and production.ini
files to include these lines
underneath the [app:main]
section:
# restful configuration
restful.api.root = /api/v1
restful.api.version = 0.0.1
The first parameter will be the URL that pyramid will serve the API through. The second is the version that will be returned when the user hits that API endpoint.
Including API
With those configuration values in place, you will also need to include the project
into your application. You can do this either by including it with the pyramid.includes
,
or within your global Configurator
defined in the myproject/__init__.py
file.
I tend to do this in the __init__.py
file because this is an inclusion that will exist
for all environments, but either way works.
** Inclusion via Config **
Edit the development.ini
and modify the pyramid.includes
property to read:
pyramid.includes =
pyramid_debugtoolbar
pyramid_restful
** Inclusion via Applicaiton **
Edit the myproject/__init__.py
file to read add a config.include('pyramid_restful')
line:
...
def main(global_config, **settings):
""" This function returns a Pyramid WSGI application.
"""
config = Configurator(settings=settings)
config.include('pyramid_chameleon')
config.include('pyramid_restful')
...
Testing the API
With these two pieces in place, you will now have the basics for your API server. To test, you can
run your project and go to the /api/v1
page:
$ pserve development.ini
Starting server in PID 12345.
serving on http://0.0.0.0:6543
If you go to http://0.0.0.0:6543 at this point, you will now see automatically generated documentation for your API. Included with the server, we also will generate documentation based on the code that is exposed as endpoints here. If you hit this URL with an HTTP request, the documentation is returned. If you request a JSON response, you will see the version that was defined in the configuration files:
$ curl -i -H "Accept: application/json" http://localhost:643/api/v1
HTTP/1.1 200 OK
Content-Length: 26
Content-Type: application/json; charset=UTF-8
Date: Mon, 28 Mar 2016 23:15:06 GMT
Server: waitress
{
"version": "0.0.1"
}
Basic Endpoints
The API uses the Pyramid traversal scheme for navigating resources. That means the endpoints that you expose will all be automatically added URLs underneath the API root.
From here, let's start making defining the ReSTful API itself. First, create a
directory called rest
within your myproject
directory and add an __init__.py
file:
MyProject/
myproject/
static/
templates/
__init__.py
rest.py
tests.py
views.py
CHANGES.txt
MANIFEST.in
README.txt
development.ini
production.ini
setup.py
** Multiple Endpoints **
Within the rest.py
file, you will start defining your endpoints. To do this, you
use the endpoint
decorator from the pyramid_restful
project.
As an example, you could do:
from pyramid_restful import endpoint
_USER = None
@endpoint.post()
def login(request):
username = request.params.get('username')
_ = request.params.get('password')
global _USER
_USER = {'username': username}
return _USER
@endpoint.get()
def whoami(request):
return _USER
@endpoint.post()
def logout(request):
global _USER
_USER = None
def includeme(config):
api = config.registry.rest_api
# register various endpoints
api.register(login)
api.register(logout)
api.register(whoami)
(Obviously you would never store a user this way, this is just an example of running the server)
These endpoints are now registered underneath the api root (/api/v1
) and can
be accessed via:
GET /api/v1/whoami
POST /api/v1/login
POST /api/v1/logout
The endpoint
decorator allows you to define all the common HTTP verbs of a ReSTful interface:
@endpoint.get()
@endpoint.post()
@endpoint.put()
@endpoint.patch()
@endpoint.delete()
** Single Endpoint, multiple verbs **
Each of these decorators corresponds to a particular HTTP request method that can be performed. ReSTful interfaces use these methods to define resource states. You could also define this API like:
from pyramid_restful import endpoint
_USER = None
@endpoint.get()
def login(request):
return _USER
@login.endpoint.post()
def set_login(request):
username = request.params.get('username')
_ = request.params.get('password')
global _USER
_USER = {'username': username}
return _USER
@login.endpoint.delete()
def unset_login(request):
global _USER
_USER = None
def includeme(config):
api = config.registry.rest_api
# register various endpoints
api.register(login)
For this example, there is only 1 endpoint URL created, /api/v1/login
, with 3 different
verbs associated with it. Usage of the API routes are defined as:
GET /api/v1/login
POST /api/v1/login
DELETE /api/v1/login
This is actually the preferred and more ReSTful way to define your API.
Subpaths
You can define subpaths for your ReST API by using classes or modules to encompass your routes. As your API becomes larger and more complex, you will want to start grouping endpoints together to make it easier to maintain.
** Scoping by class **
The first example is to use a single class for your endpoints. If we modify our rest.py
file now to read:
from pyramid_restful import endpoint
_USER = None
class auth(object):
def __init__(self, request):
self.request = request
@endpoint.get()
def login(self):
return _USER
@login.endpoint.post()
def set_login(self):
username = self.request.params.get('username')
_ = self.request.params.get('password')
global _USER
_USER = {'username': username}
return _USER
@login.endpoint.delete()
def unset_login(self):
global _USER
_USER = None
def includeme(config):
api = config.registry.rest_api
# register various endpoints
api.register(auth)
We will now have registered a scope called auth
which contains the endpoints. Note, for classes you must
accept a request parameter in the class constructor and reference it within your endpoints.
The API now looks like:
GET /api/v1/auth/login
POST /api/v1/auth/login
DELETE /api/v1/auth/login
** Scoping by module **
Alternatively, it is often useful to break your rest API up into modules. If we change our file structure to be:
MyProject/
myproject/
rest/
__init__.py
auth.py
static/
templates/
__init__.py
tests.py
views.py
CHANGES.txt
MANIFEST.in
README.txt
development.ini
production.ini
setup.py
We've now removed the rest.py
module and created a rest
package with two files: __init__.py
and auth.py
.
Inside the __init__.py
let's add the code:
from . import auth
def includeme(config):
api = config.registry.rest_api
# register various endpoints
api.register(auth)
And inside the auth.py
file let's add:
from pyramid_restful import endpoint
_USER = None
@endpoint.get()
def login(request):
return _USER
@login.endpoint.post()
def set_login(request):
username = request.params.get('username')
_ = request.params.get('password')
global _USER
_USER = {'username': username}
return _USER
@login.endpoint.delete()
def unset_login(request):
global _USER
_USER = None
In this case, our endpoints will stay the same:
GET /api/v1/auth/login
POST /api/v1/auth/login
DELETE /api/v1/auth/login
But instead of being routed through the class named auth
, it is routed through the module named auth
.
There is only ever one level of scoping within the pyramid_restful
API.