Module urest.api
Abstract base class and helper classes for the server-provided REST API
Overview
During the marshalling of client requests (provided by the
RESTServer
class), the path portion of the URI is extracted
from the client. This path is expected to take the form of
/< noun >
with the 'verb' denoted by the HTTP methods. Each 'noun' is implemented by a
class which inherits from APIBase
.
Note
All nouns are checked byRESTServer
, and nouns will not be
properly routed unless APIBase
is an ancestor of the derived
class.
The 'noun' determines the resource of the request, and the 'verb' the action to
be taken on that resource. Also important is the intent of the client as
inferred from the underlying HTTP request, e.g. GET
or PUT
. Taken together
the URI and the client intent are mapped to methods of APIBase
as follows
Verb | HTTP Method | APIBase method |
---|---|---|
Get | GET |
APIBase.get_state() |
Set | PUT |
APIBase.set_state() |
Update | POST |
APIBase.update_state() |
Delete | DELETE |
APIBase.delete_state() |
Example
Getting the Noun State
See SimpleLED
class a minimal implementation of a noun
controlling on GPIO pin, using the MicroPython Pin
library. For the
SimpleLED
class, the exact pin being controlled is set
during the object instantiation, via the class constructor.
Assuming the RESTServer
has been created as
python app = RESTServer()
then a 'noun' led
can be registered via the
urest.http.server.RESTServer.register_noun
method as
python app.register_noun('led', SimpleLED(28))
This will also bind the controlled GPIO pin to Pin 28
: documentation for the
micro-controller and platform being used will be need to determine suitable
values.
Once the 'noun' has been registered, then the state of GPIO Pin 28
can be
found by the HTTP request
GET /led HTTP 1.1
All Lookup's Are Case Insensitive
All nouns are registered with urest.http.server.RESTServer
in lowercase.
Likewise all routing of API requests will also assume that the name of the noun
to be used will be in lowercase. Thus, for instance, calling
python app.register_noun('leD', SimpleLED(28))
or
python app.register_noun('LED', SimpleLED(28))
will all route to the name noun with the canonical name led
. Likewise
the request
GET /lEd HTTP 1.1
or
GET /LED HTTP 1.1
will also route to the same noun with the canonical name led
.
Setting the Noun State
Setting the state of the noun is a little more involved, as this will require the desired state of the noun to be sent to the server. A useful tool for testing purposes is the curl utility; available on most platforms.
Continuing the minimal example above, the command line
curl -X PUT -d '{"led":"0"}' -H "Content-Type: application/json" <http://10.0.30.225/LED>
will transmit something like the following HTTP request to
urest.http.server.RESTServer
PUT /LED HTTP/1.1
Host: 10.0.30.225
User-Agent: curl/7.81.0
Accept: */*
Content-Type: application/json
Content-Length: 11
{"led":"0"}
Note: JSON is Required
The only format accepted by the RESTServer
for the state
of the nouns is JSON. The
RESTServer
will also only accept a sub-set of the JSON
standard: notably assuming a single object, and a collection of key/value pairs.
The exact interpretation of the JSON is left to the implementation of the noun,
but in most cases the name of the noun is used to set the state value. For
instance in the above example the key led
is interpreted as referring to the
noun, and the value 0
as the state value. In this case setting the GPIO Pin
28<code> to the value </code>0<code> (or </code>off
). A close correspondence between the name of the
noun as referred to the API, and the name of the noun in the state list is
strongly advised: but is not strictly required.
Tested Implementations
This version is written for MicroPython 3.4, and has been tested on:
- Raspberry Pi Pico W
Licence
This module, and all included code, is made available under the terms of the MIT Licence
Copyright (c) 2022–2023 David Love
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Expand source code
"""
Abstract base class and helper classes for the server-provided REST API
Overview
--------
During the marshalling of client requests (provided by the
`urest.http.server.RESTServer` class), the path portion of the URI is extracted
from the client. This path is expected to take the form of
> `/< noun >`
with the 'verb' denoted by the HTTP methods. Each 'noun' is implemented by a
class which inherits from `urest.api.base.APIBase`.
.. Note::
All nouns are checked by`urest.http.server.RESTServer`, and nouns will not be
properly routed unless `urest.api.base.APIBase` is an ancestor of the derived
class.
The 'noun' determines the resource of the request, and the 'verb' the action to
be taken on that resource. Also important is the intent of the client as
inferred from the underlying HTTP request, e.g. `GET` or `PUT`. Taken together
the URI and the client intent are mapped to methods of `urest.api.base.APIBase`
as follows
| Verb | HTTP Method | `urest.api.base.APIBase` method |
|--------|-------------|--------------------------------------------|
| Get | `GET` | `urest.api.base.APIBase.get_state` |
| Set | `PUT` | `urest.api.base.APIBase.set_state` |
| Update | `POST` | `urest.api.base.APIBase.update_state` |
| Delete | `DELETE` | `urest.api.base.APIBase.delete_state` |
Example
--------------
### Getting the Noun State
See `urest.examples.simpleled.SimpleLED` class a minimal implementation of a noun
controlling on GPIO pin, using the MicroPython `Pin` library. For the
`urest.examples.simpleled.SimpleLED` class, the exact pin being controlled is set
during the object instantiation, via the class constructor.
Assuming the `urest.http.server.RESTServer` has been created as
```python app = RESTServer() ```
then a 'noun' `led` can be registered via the
`urest.http.server.RESTServer.register_noun` method as
```python app.register_noun('led', SimpleLED(28)) ```
This will also bind the controlled GPIO pin to `Pin 28`: documentation for the
micro-controller and platform being used will be need to determine suitable
values.
Once the 'noun' has been registered, then the state of GPIO `Pin 28` can be
found by the HTTP request
```
GET /led HTTP 1.1
```
### All Lookup's Are Case Insensitive
All nouns are registered with `urest.http.server.RESTServer` in **lowercase**.
Likewise all routing of API requests will also assume that the name of the noun
to be used will be in lowercase. Thus, for instance, calling
```python app.register_noun('leD', SimpleLED(28)) ```
or
```python app.register_noun('LED', SimpleLED(28)) ```
will **all** route to the name noun with the canonical name `led`. Likewise
the request
``` GET /lEd HTTP 1.1 ```
or
``` GET /LED HTTP 1.1 ```
will **also** route to the same noun with the canonical name `led`.
### Setting the Noun State
Setting the state of the noun is a little more involved, as this will require
the desired state of the noun to be sent to the server. A useful tool for
testing purposes is the [curl](https://curl.se) utility; available on most
platforms.
Continuing the minimal example above, the command line
```
curl -X PUT -d '{"led":"0"}' -H "Content-Type: application/json" http://10.0.30.225/LED
```
will transmit something like the following HTTP request to
`urest.http.server.RESTServer`
```
PUT /LED HTTP/1.1
Host: 10.0.30.225
User-Agent: curl/7.81.0
Accept: */*
Content-Type: application/json
Content-Length: 11
{"led":"0"}
```
.. NOTE:: JSON is Required
The only format accepted by the `urest.http.server.RESTServer` for the state
of the nouns is [JSON](https://www.json.org/json-en.html). The
`urest.http.server.RESTServer` will also only accept a sub-set of the JSON
standard: notably assuming a single object, and a collection of key/value pairs.
The exact interpretation of the JSON is left to the implementation of the noun,
but in most cases the name of the noun is used to set the state value. For
instance in the above example the key `led` is interpreted as referring to the
noun, and the value `0` as the state value. In this case setting the GPIO `Pin
28` to the value `0` (or `off`). A close correspondence between the name of the
noun as referred to the API, and the name of the noun in the state list is
**strongly** advised: but is not strictly required.
Tested Implementations
----------------------
This version is written for MicroPython 3.4, and has been tested on:
* Raspberry Pi Pico W
Licence
-------
This module, and all included code, is made available under the terms of the MIT Licence
> Copyright (c) 2022--2023 David Love
> Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
> The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
### Expose the `http` module interface
from .base import APIBase
Sub-modules
urest.api.base
-
Implements the 'Abstract' Base Class for all the nouns used by the
RESTServer
class in defining resources …