REST API#

The package adds one endpoint, @redismemoize, on the Plone site root. It requires the Manage portal permission, which only the Manager role has in a stock Plone 6.2 site. Site Administrators get 401 Unauthorized.

Every instance answers for itself. The breaker, the routes and the counters belong to the process that handled the request.

The examples below are recorded by the test suite.

Get the status#

GET /@redismemoize returns the configuration, the state of the breaker, the server, and every cached function the process has seen.

http

GET /plone/@redismemoize HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0

curl

curl -i -X GET http://nohost/plone/@redismemoize -H "Accept: application/json" --user admin:secret

httpie

http http://nohost/plone/@redismemoize Accept:application/json -a admin:secret

python-requests

requests.get('http://nohost/plone/@redismemoize', headers={'Accept': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "active": true,
    "breaker": {
        "open": false,
        "seconds_until_retry": 0.0
    },
    "functions": {
        "plone.app.theming.plugins.utils.getPluginSettings": {
            "counters": {
                "errors": 0,
                "ram_hits": 2,
                "ram_misses": 0,
                "redis_hits": 0,
                "redis_misses": 2,
                "refused": 0,
                "too_large": 0,
                "undecodable": 0
            },
            "reason": null,
            "route": "redis"
        },
        "plone.app.theming.plugins.utils.getPlugins": {
            "counters": {
                "errors": 0,
                "ram_hits": 2,
                "ram_misses": 0,
                "redis_hits": 0,
                "redis_misses": 2,
                "refused": 0,
                "too_large": 0,
                "undecodable": 0
            },
            "reason": null,
            "route": "redis"
        },
        "tests.integration.compute": {
            "counters": {
                "errors": 0,
                "ram_hits": 0,
                "ram_misses": 1,
                "redis_hits": 1,
                "redis_misses": 1,
                "refused": 0,
                "too_large": 0,
                "undecodable": 0
            },
            "reason": null,
            "route": "redis"
        }
    },
    "server": {
        "error": null,
        "latency_ms": 0.25,
        "product": "redis",
        "version": null
    },
    "settings": {
        "exclude": [],
        "include": [],
        "max_size": 1048576,
        "prefix": "test.memoize",
        "retry_after": 30.0,
        "timeout": 0.25,
        "ttl": 86400,
        "url": "redis://fakeredis:6379/0"
    }
}

The response has these keys:

active

true when REDIS_MEMOIZE_URL is set.

settings

The configuration in effect, with any password in the URL replaced by ***.

breaker

open, and seconds_until_retry; null when the package is inert.

server

latency_ms of a PING, product (redis or valkey), version, and error; null when the package is inert. The endpoint contacts the server even while the breaker is open.

functions

For each function, its route, the reason for a RAM route, and its counters.

The routes are:

redis

Values go to Redis.

ram-excluded

An include or exclude pattern keeps the function in RAM.

ram-not-shareable

A value was not shareable; the function stays in RAM until the process restarts.

The counters are redis_hits, redis_misses, ram_hits, ram_misses, refused, too_large, undecodable, and errors.

Without REDIS_MEMOIZE_URL, the response says so:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "active": false,
    "breaker": null,
    "functions": {},
    "server": null,
    "settings": {
        "exclude": [],
        "include": [],
        "max_size": 1048576,
        "prefix": "plone.memoize",
        "retry_after": 30.0,
        "timeout": 0.25,
        "ttl": 86400,
        "url": null
    }
}

Invalidate one function#

POST /@redismemoize/invalidate with a body naming a function drops that function's values from Redis, and from the RAM cache of the instance that answers.

http

POST /plone/@redismemoize/invalidate HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: application/json

{
    "function": "tests.integration.compute"
}

curl

curl -i -X POST http://nohost/plone/@redismemoize/invalidate -H "Accept: application/json" -H "Content-Type: application/json" --data-raw '{"function": "tests.integration.compute"}' --user admin:secret

httpie

echo '{
  "function": "tests.integration.compute"
}' | http POST http://nohost/plone/@redismemoize/invalidate Accept:application/json Content-Type:application/json -a admin:secret

python-requests

requests.post('http://nohost/plone/@redismemoize/invalidate', headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, json={'function': 'tests.integration.compute'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "function": "tests.integration.compute",
    "removed": 1
}

removed is the number of Redis keys removed.

Invalidate everything#

POST /@redismemoize/invalidate with an empty object as the body drops every key under the prefix, and the whole RAM cache of the instance that answers.

http

POST /plone/@redismemoize/invalidate HTTP/1.1
Accept: application/json
Authorization: Basic YWRtaW46c2VjcmV0
Content-Type: application/json

{}

curl

curl -i -X POST http://nohost/plone/@redismemoize/invalidate -H "Accept: application/json" -H "Content-Type: application/json" --user admin:secret

httpie

http POST http://nohost/plone/@redismemoize/invalidate Accept:application/json Content-Type:application/json -a admin:secret

python-requests

requests.post('http://nohost/plone/@redismemoize/invalidate', headers={'Accept': 'application/json', 'Content-Type': 'application/json'}, auth=('admin', 'secret'))
HTTP/1.1 200 OK
Content-Type: application/json

{
    "function": null,
    "removed": 3
}

Errors#

400 Bad Request

The body is not a JSON object, or function is not a non-empty string.

401 Unauthorized

The user lacks Manage portal.

404 Not Found

A POST to any path other than @redismemoize/invalidate.