Skip to content

Commit

Permalink
GET API to update a single prop
Browse files Browse the repository at this point in the history
  • Loading branch information
ramdacxp committed Jul 14, 2024
1 parent bcec701 commit f747216
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 11 deletions.
97 changes: 87 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,23 @@

**dcache** is a PHP REST API implementing a JSON data cache.

* The data cache consists of _data sets_ containing multiple _properties_ (as key-value-pairs).
* A _data set_ is identified by an unique _data token_.
* The data cache consists of _data sets_ containing multiple _properties_ as key-value-pairs.
* A _data set_ is identified by an unique _token_.
* _Data Provider_ can create, update, and remove _data sets_.
* _Consumer_ can query a _data set_ based on a provided _data token_.
* _Consumer_ can query a _data set_ identified by the provided _token_.

A running demo is available at: <https://dcache.schademarmelade.de/>.

![dcache Table View](doc/tableview.png)

Usage examples:

* Selected [Home Assistant](https:c//www.home-assistant.io/) entities can be pushed to _dcache_ and visualized on a [TRMNL](https://usetrmnl.com/) e-ink display via a [custom TRMNL-Plugin](https://help.usetrmnl.com/en/articles/9510536-custom-plugins).
* The result status of a DevOps build pipeline can be sent _dcache_ and visualized on a WLED led strip.
* The battery status of multiple IoT devices is available in a single _dcache_ data set.
* Selected [Home Assistant](https:c//www.home-assistant.io/) entities can be pushed to **dcache** and visualized on a [TRMNL](https://usetrmnl.com/) e-ink display via a [custom TRMNL-Plugin](https://help.usetrmnl.com/en/articles/9510536-custom-plugins).
* The result status of a DevOps build pipeline can be sent to **dcache** and visualized on a WLED led strip.
* The battery status of multiple IoT devices is available in a single **dcache** data set.
* ...

A typical flow between Home Assistant, dcache, and TRMNL could look like this:
A typical data flow between Home Assistant, **dcache**, and TRMNL could look like this:

* HA provides `temperature=25`
* HA provides `humidity=65`
Expand Down Expand Up @@ -47,12 +47,12 @@ No system wide settings are modified during the installation.
The database content can be reset to the initial test data with `reset-testdata.cmd`.
Already existing data in dcache tables will be removed!

All tools can be removed safely by deleting the `bin` and `node_modules` sub-folders.
All tools and test data can be removed completely by deleting the `bin` and `node_modules` sub-folders.

## Run dcache locally

* Execute `npm start` or choose `Terminal > Run Build Task...` in VSCode.
* Open the local dev webserver <http://localhost:8080/> in your browser.
* Open the local dev webserver address <http://localhost:8080/> in your browser.
* Stop the servers by pressing `Ctrl-C` in the Terminal window.

## Settings
Expand All @@ -77,10 +77,87 @@ $settings["prefix"] = "dc-";
The REST API is exposed at `/api.php`.

For a list of supported requests and related responses, please refer to the [`requests.http`](./requests.http) sample file.

All requests can be executed against the provided PHP development webserver in order to test and debug the API.
This requires VSCode with the [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) extension installed.

| Method | URL | Description | Success Response |
|--------|---------------------------------------|-------------------------------------------|--------------------------------|
| GET | `/api.php?token=T` | Query complete dataset `T` | Dataset `T` as object `{...}` |
| GET | `/api.php?token=T&property=P` | Query property `P` from dataset `T` | Value of `P` as string `"val"` |
| GET² | `/api.php?token=T&property=P&value=V` | Update property `P` to `V` in dataset `T` | Updated dataset `T` as object |
| POST | `/api.php?token=T` | Update provided properties in dataset `T` | Updated dataset `T` as object |
| DELETE | `/api.php?token=T` | Remove complete dataset `T` | Boolean `true` |
| DELETE | `/api.php?token=T&property=P` | Remove property `P` from dataset `T` | Boolean `true` |

² - This non standard REST operation behaves like a `POST` of the single property `P`, but can be executed from a browser.

### Restrictions

| Type | Length | Characters |
|-------------------|----------|-------------------------------|
| Dataset token `T` | min. `8` | `a-z`, `A-Z`, `0-9`, `-`, `.` |
| Property name `P` | min. `1` | `a-z`, `0-9`, `-`, `.` |

### Request Body (POST)

A `POST` request can be used to update one or more properties of an existing dataset, which is identified by the given token `T`. If the token `T` was not found, a new dataset related to this token is created. The `POST` payload needs to contain the a JSON object in `Content-Type: application/json`.

Example:

If the given dataset, which is related to token `testdata`:

```json
{
"firstname": "Max",
"lastname": "Mustermann"
}
```

is updated via `POST /api.php?token=testdata` containing the `Content-Type: application/json` payload:

```json
{
"firstname": "Hans",
"town": "New York"
}
```

it will return the updated dataset as JSON object as:

```json
{
"firstname": "Hans",
"lastname": "Mustermann",
"town": "New York"
}
```

### Error Response Messages

In case of errors, a HTTP response code different from `200` (OK) is returned together with an JSON object describing the error.

```json
{
"kind": "error",
"code": 400,
"message": "Token contains invalid characters. Only letters, numbers, dots and dashes are allowed."
}
```

Possible errors:

| Code | Message |
|----------------------|----------------------------------------------------------------------------------------|
| `400` Bad Request | Content is not valid JSON. |
| `400` Bad Request | Invalid content type. Expected application/json. |
| `400` Bad Request | No token given. |
| `400` Bad Request | Not implemented. |
| `400` Bad Request | Token contains invalid characters. Only letters, numbers, dots and dashes are allowed. |
| `400` Bad Request | Token is too short. Must be at least 8 characters long. |
| `404` Not found | Dataset not found. |
| `404` Not found | Property not found in dataset. |
| `500` Internal Error | Not configured. |

## License

See [LICENSE](LICENSE).
4 changes: 4 additions & 0 deletions requests.http
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ GET {{server}}/api.php?token=testdata&property=doesnotexist HTTP/1.1
### -> 200 (ok) string response
GET {{server}}/api.php?token=testdata&property=firstname HTTP/1.1

### GET with correct token, property, and value
### -> 200 (ok) updated JSON object response
GET {{server}}/api.php?token=testdata&property=firstname&value=Egon HTTP/1.1

### ============================================================================
### SET/UPDATE DATA
### ============================================================================
Expand Down
22 changes: 21 additions & 1 deletion www/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@

switch ($_SERVER['REQUEST_METHOD']) {
case "GET":
handleGet($db, $_REQUEST['token'], $_REQUEST['property']);
if (isset($_REQUEST['value'])) {
handleGetUpdate($db, $_REQUEST['token'], $_REQUEST['property'], $_REQUEST['value']);
} else {
handleGet($db, $_REQUEST['token'], $_REQUEST['property']);
}
break;

case "POST":
Expand Down Expand Up @@ -79,6 +83,22 @@ function handleGet($db, $token, $property)
}
}

function handleGetUpdate($db, $token, $property, $value)
{
if (!validateToken($token)) return false;

if (!isset($property) || is_null($property) || empty($property)) {
Rest::respondError(Rest::CODE_400_BAD_REQUEST, "No property given.");
return false;
}

$db->deleteProperty($token, $property);
$db->insertProperty($token, $property, $value);

$data = $db->getData($token);
Rest::respond(Rest::CODE_200_OK, $data);
}

function handlePost($db, $token, $contentType)
{
if (!validateToken($token)) return;
Expand Down

0 comments on commit f747216

Please sign in to comment.