Lightweight RESTful API Server Builder

## Project description

RASBlite allows you to quickly define a data model that you can interact with via a RESTful API in a consistent way. Although there are numerous scenarios when you’d want to do this, it is particularly useful during the development of REST clients (such as in unit tests and continuous integration environments).

Imagine you’re working on a client that accesses some remote resource using a RESTful API. For example, let’s say your client will interact with a server holding a list of items which includes the name and the amount of the item. If the server does not yet exist, how will you test your client? If the server does exist, how can you automatically test your client consistently without having constant direct access to the server? For this example, we could easily define a hierarchical model with RASBlite like so:

[Base]
url = /api/

[Model]
structure =
GET,POST         items/
GET,PUT,DELETE   items/:item_number/
GET,PUT          items/:item_number/name
GET,PUT          items/:item_number/amount

With RASBlite, your REST client could now perform a HTTP POST to http://127.0.0.1:8080/api/items/ with {'name': 'Spoon', 'amount': '3'} and then verify it worked by subsequently doing a HTTP GET to http://127.0.0.1:8080/api/items/0/ and checking the response matched your earlier POST.

## Quickstart

Install RASBlite using pip3 - $pip3 install rasblite, this will provide the script rasblite-run. If you encounter an error during installation, you may have to run with elevated privileges using sudo -$ sudo pip3 install rasblite.

Next, create a file containing your model called model.txt. To begin with you can just fill the contents with the one below which contains a list of users, their names and any addresses they may have on record:

[Base]
url = /rest/api/1.0/

[Model]
structure =
GET,POST         users/
GET,PUT,DELETE   users/:userID/
GET,PUT          users/:userID/name
GET,PUT          users/:userID/age

Now, if we wanted to start off with no initial data on the server you can simply run:

$rasblite-run --model model.txt --starting_data DEFAULT Otherwise if you want start with some example data for this particular model you can create a file called data.json with the contents: {'users': [{'addresses': [{'address_lines': '123 Fake Street', 'post_code': 'AB12 3CD'}], 'age': '21', 'name': 'Bob'}, {'addresses': [{'address_lines': '456 My Street', 'post_code': 'EF45 6GH'}, {'address_lines': '789 Other Street', 'post_code': 'IJ12 3KL'}], 'age': '60', 'name': 'Frank'}]} and run it with: $ rasblite-run --model model.txt --starting_data data.json

or

$rasblite-run -m model.txt -d data.json Feeling lazy? The above starting data is pre-built into the script so you can get the same effect without creating the initial data file by running: $ rasblite-run -m model.txt -d EXAMPLE

Your HTTP server should now be running and you can easily test it works by accessing it with your favourite web bowser:

http://127.0.0.1:8080/rest/api/1.0/users/

If all went well you should see your starting data returned. You can drill down to specific points by following the hierarchy:

You can now perform all your usual REST functions with HTTP methods such as GET, POST, PUT and DELETE. The model you used specifies which of these HTTP methods are allowed and are determined by you (more on this below in the Model Structure section).

NOTE:

Make sure to set the correct HTTP headers in your client for POST and PUT requests. Currently, the only content-type supported is application/json and you need to include the correct content-length too. For example, an example raw POST request might look like:

POST /rest/api/1.0/users HTTP/1.1
HOST: 127.0.0.1:8080
content-length: 103
content-type: application/json

{"name": "Jim", "addresses": [{"post_code": "UR98 7ST", "address_lines": "30 Flat Road"}], "age": "18"}

## Usage

### Initialising without hierarchical data store

It’s possible to tell RASBlite not to create a hierarchical data store to match your model structure. To do this, pass EMPTY for the --starting_data argument:

\$ rasblite-run --model model.txt --starting_data EMPTY

## Model Syntax

### Base URL

Most REST APIs contain a base url (the part in the url before the hierarchical structure). i.e.

http://<host>:<port><base_url><your_model>

You can set the base url for your API by setting the url attribute within the [Base] section. The path prefix will then be used for your API.

For example:

[Base]
url = /rest/api/1.0/
...

The above would mean the client must request with /rest/api/1.0/ before their model i.e. http://127.0.0.1:8080/rest/api/1.0/some/path

### Model Structure

To define the structure of your model, you must include the possible request suffix paths with the structure attribute under a [Model] section like so:

...

[Model]
structure =
GET,POST         users/
GET,PUT,DELETE   users/:userID/
GET,PUT          users/:userID/name
GET,PUT          users/:userID/age

Each line contains the approved HTTP methods for that entry and the hierarchical suffix path. The parts need to be separated by whitespace but this can be spaces or tabs.

#### Approved HTTP methods

Each line in the structure must start with the HTTP methods that are allowed. They have to be comma separated and must be GET, POST, PUT and/or DELETE. For example, if you only wanted to allow clients to perform a GET, POST or DELETE to http://<host>:<port>/base/users/ your model structure could look like this:

[Base]
url = /base/

[Model]
structure =
GET,POST,DELETE users/

#### Request path suffix

Each line in the structure must end with the path suffix. You can build a hierarchical tree by including additional paths that contain common parents. Parts of the path that start with a colon : such as item_number in /some/:item_number/path denote a list and can be accessed by an index. For example, you could have a list of cars by defining a structure like this:

[Base]
url = /base/

[Model]
structure =
GET,POST         cars/
GET,PUT,DELETE   cars/:car_number/
GET,PUT          cars/:car_number/name
GET,PUT          cars/:car_number/make
GET,PUT          cars/:car_number/reg

The lists are zero-indexed which means to access the make of the 5th car stored by your server, you would perform a GET on:

http://127.0.0.1:8080/base/cars/4/make

Notice how :car_number in the path has been replaced by an index.

## Project details

Uploaded source