Cette page a été traduite par une machine et n'a pas encore été révisée par une personne. L'anglais est la référence ; les corrections sont les bienvenues sur GitHub. GitHub

Cookwala / SDK et scénarios / 049

A malformed request gets a Problem, a well-formed one gets a status

Two different answers: a request that is not a valid ExecuteRequest is answered with application/problem+json and never reaches the device; a valid request the device will not cook gets an ExecutionStatus in state refused.

Audience: developer · Objectif: Des robots pour les gens · Niveau: beginner

Lire d'abord: /docs/CORE/ /docs/HUB/

Étapes

  1. Send a request without recipeHash. The answer is a Problem with title invalid-request naming the missing field. startExecution

  2. Send a request that claims core 0.1.0. The Problem title is unsupported-version and it carries the refusal code. startExecution

  3. A well-formed request is accepted and returns an ExecutionStatus. startExecution

Résultat

You can tell a transport or schema error from a device refusal in your client. Next: scenario 050 covers a duplicate execution id.

Ligne de commande

cookwala hub --recipes examples --speed 200
curl -si -X POST http://localhost:7878/v1/executions -H 'Content-Type: application/json' -H 'Idempotency-Key: bad-request-01' -d '{"core":"0.2.0","kind":"ExecuteRequest","id":"ex-bad"}'

Sortie enregistrée

Statut: ok

[1] startExecution: {"type": "https://cookwala.ai/errors/invalid-request", "title": "invalid-request", "detail": "missing recipeHash"}
[2] startExecution: {"type": "https://cookwala.ai/errors/unsupported-version", "title": "unsupported-version", "refusal": "unsupported_version"}
[3] startExecution: {"core": "0.2.0", "kind": "ExecutionStatus", "id": "ex-049-ok", "seq": 0, "state": "accepted", "request": "ex-049-ok", "updatedAt": "2026-10-07T00:54:31Z", "x-hub-plan": [{"node": "n1", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n2", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n3", "op": "cw.op.cut", "by": "device", "verifiedBy": "sensor", "rung": "cw.sense.vision"}, {"node": "n4", "op": "cw.op.heat", "by": "human", "verifiedBy": "human"}, {"node": "n5", "op": "cw.op.saute", "by": "human"…

Code

Exécuter: python scenarios/out/049-malformed-requests-are-problems-not-refusals/python.py

# Scenario 049: A malformed request gets a Problem, a well-formed one gets a status
# Two different answers: a request that is not a valid ExecuteRequest is answered with application/problem+json and never reaches the device; a valid request the device will not cook gets an ExecutionStatus in state refused.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem

def load(path):
    with open(path, encoding="utf-8") as f:
        return json.load(f)

def pick(obj, path):
    for part in path.replace("]", "").replace("[", ".").split("."):
        obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
    return obj

c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))


# Step 1: Send a request without recipeHash. The answer is a Problem with title invalid-request naming the missing field.
try:
    missing = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-049-missing", "recipe": "cw:cookwala.ai:example-shakshuka", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-049-missing-a"}, "ex-049-missing-key", True)
except CookwalaProblem as p:
    missing = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(missing, "title") == "invalid-request", pick(missing, "title")
print("ok", "title", "=", "invalid-request")
assert pick(missing, "detail") == "missing recipeHash", pick(missing, "detail")
print("ok", "detail", "=", "missing recipeHash")

# Step 2: Send a request that claims core 0.1.0. The Problem title is unsupported-version and it carries the refusal code.
try:
    version = c.start_execution({"core": "0.1.0", "kind": "ExecuteRequest", "id": "ex-049-version", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-049-version-a"}, "ex-049-version-key", True)
except CookwalaProblem as p:
    version = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(version, "title") == "unsupported-version", pick(version, "title")
print("ok", "title", "=", "unsupported-version")
assert pick(version, "refusal") == "unsupported_version", pick(version, "refusal")
print("ok", "refusal", "=", "unsupported_version")

# Step 3: A well-formed request is accepted and returns an ExecutionStatus.
try:
    ok = c.start_execution({"core": "0.2.0", "kind": "ExecuteRequest", "id": "ex-049-ok", "recipe": "cw:cookwala.ai:example-shakshuka", "recipeHash": "sha256:2ea6fab93cc673fc6784f9bc9fe401d2387bb7779dc537df97286b73807c8841", "servings": 4, "requestedBy": "agent:planner-1", "idempotencyKey": "ex-049-ok-a"}, "ex-049-ok-key", True)
except CookwalaProblem as p:
    ok = p.body  # a refusal is a result, not a crash
    print("refused:", p.refusal)
assert pick(ok, "kind") == "ExecutionStatus", pick(ok, "kind")
print("ok", "kind", "=", "ExecutionStatus")
assert pick(ok, "state") == "accepted", pick(ok, "state")
print("ok", "state", "=", "accepted")

print("scenario complete")

scenarios/049-malformed-requests-are-problems-not-refusals.json

Précédent: 048 Suivant: 050