summaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'README.md')
-rw-r--r--README.md127
1 files changed, 127 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d08b0bd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,127 @@
+# Hot functions API
+
+A small HTTP service that registers typed Python functions and calls them with
+JSON. It derives input and output schemas from type annotations; there is no
+separate schema registration step or UI.
+
+## Run locally
+
+Python 3.10 or newer is needed for `int | str` annotations in the examples.
+The `curl` examples use Bash's `$'...'` quoting for multiline source.
+
+```sh
+python -m venv .venv
+. .venv/bin/activate
+pip install -r requirements.txt
+python server.py
+```
+
+The service listens on port 8000. Functions live in memory and disappear when
+the server stops.
+
+## Register and call a function
+
+Send a complete, synchronous function definition. The function name must match
+the URL, and every parameter and the return value must have a type annotation.
+
+```sh
+curl -X PATCH http://localhost:8000/double \
+ --data-binary $'def double(x: int) -> int:\n return x * 2'
+```
+
+With one parameter, POST either a bare JSON value or a named argument:
+
+```sh
+curl -X POST http://localhost:8000/double \
+ -H 'Content-Type: application/json' -d '4'
+# 8
+
+curl -X POST http://localhost:8000/double \
+ -H 'Content-Type: application/json' -d '{"x":4}'
+# 8
+```
+
+The response is the function's JSON result, without a `result` wrapper. Input
+and output are validated against the annotations in Pydantic's strict mode.
+
+### Multiple arguments and union types
+
+```sh
+curl -X PATCH http://localhost:8000/label \
+ --data-binary $'def label(x: int | str, prefix: str = "item") -> str:\n return f"{prefix}:{x}"'
+
+curl -X POST http://localhost:8000/label \
+ -H 'Content-Type: application/json' -d '{"x":4,"prefix":"order"}'
+# "order:4"
+
+curl -X POST http://localhost:8000/label \
+ -H 'Content-Type: application/json' -d '{"x":"abc"}'
+# "item:abc"
+```
+
+For multiple parameters, POST a JSON object with parameter names as keys.
+Defaults may be omitted. Unrecognized keys are rejected.
+
+A single parameter may accept any JSON value its annotation permits: an object,
+array, string, number, boolean, or `null`. For example, a function annotated
+`x: dict[str, int]` can receive `{"count":2}` directly or as
+`{"x":{"count":2}}`. If an object also looks like valid named arguments, the
+named-argument form takes precedence. Structured types can use Pydantic models
+defined in the uploaded source.
+
+## Discover functions and schemas
+
+```sh
+curl http://localhost:8000/double
+curl http://localhost:8000/
+```
+
+`GET /double` returns an object containing `name`, `source`, and `schema`.
+`GET /` returns `{"functions": [...]}` with the same objects for all registered
+functions. For `double`, the input schema describes both accepted POST forms:
+
+```json
+{
+ "name": "double",
+ "source": "def double(x: int) -> int:\n return x * 2",
+ "schema": {
+ "input": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "anyOf": [
+ {
+ "type": "object",
+ "properties": {"x": {"title": "X", "type": "integer"}},
+ "required": ["x"],
+ "additionalProperties": false
+ },
+ {"type": "integer"}
+ ]
+ },
+ "output": {
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
+ "type": "integer"
+ }
+ }
+}
+```
+
+The input and output schemas are JSON Schema Draft 2020-12 documents. Replacing
+a function with `PATCH` also regenerates its schemas.
+
+## API responses
+
+| Request | Result |
+| --- | --- |
+| `PATCH /name` | `200` on registration; `400` for an invalid definition |
+| `POST /name` | `200` with the JSON result; `400` for invalid input; `404` if undefined; `500` if execution or output validation fails |
+| `GET /name` | `200` with the function description; `404` if undefined |
+| `GET /` | `200` with all defined functions |
+
+Run the tests with `python -m unittest -v test_server`.
+
+## Trust boundary
+
+Uploaded definitions execute as Python in the server process, including at
+registration time. The server has no authentication, isolation, request-size
+limit, or execution timeout and binds to `0.0.0.0`. Only run it where every
+caller is fully trusted; it is not safe to expose to untrusted clients.