fix(api): document 4xx and reject invalid form-status weeks (DEV-289)

Health, form-status, and roster document 400. form-status now maps
current and returns 400 for a week that is not current or YYYY-WNN.
Redocly treats 302 as a success response, matching the portal.

Co-authored-by: Adam Moussa <amoussa1229@users.noreply.github.com>
This commit is contained in:
Cursor Agent 2026-09-21 23:55:40 +00:00
parent 198269db5b
commit fbd9444a36
No known key found for this signature in database
5 changed files with 72 additions and 8 deletions

View file

@ -1,7 +1,29 @@
# Same Redocly recommended ruleset as internal-portal (DEV-223 / DEV-289).
# Login-style redirects succeed with 302. Recommended only counts 2XX.
extends:
- recommended
rules:
operation-2xx-response: off
rule/operation-2xx-or-3xx-response:
subject:
type: Responses
message: Operation must define a 2XX or 3XX response.
severity: warn
assertions:
requireAny:
- "200"
- "201"
- "202"
- "204"
- "301"
- "302"
- "303"
- "307"
- "308"
- "2XX"
- "3XX"
apis:
meals@v1:
root: openapi.yaml

View file

@ -46,6 +46,8 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/Health"
"400":
$ref: "#/components/responses/StringError"
/api/menu/{week}:
get:
@ -82,6 +84,8 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/FormStatus"
"400":
$ref: "#/components/responses/StringError"
/api/submit-order:
post:
@ -260,6 +264,8 @@ paths:
application/json:
schema:
$ref: "#/components/schemas/FormRoster"
"400":
$ref: "#/components/responses/StringError"
/api/publish/settings:
get:

View file

@ -279,15 +279,20 @@ def lambda_handler(event, context):
return response(405, {"error": "Method not allowed"})
def handle_menu(event):
"""Return the published menu in the portal's public MenuPayload shape."""
def _week_from_path(event):
requested_week = (event.get("pathParameters") or {}).get("week", "")
if requested_week == "current":
week = current_week()
elif re.fullmatch(r"\d{4}-W\d{2}", requested_week):
week = requested_week
else:
return response(400, {"error": "week path param must be current or YYYY-WNN"})
return current_week(), None
if re.fullmatch(r"\d{4}-W\d{2}", requested_week):
return requested_week, None
return None, response(400, {"error": "week path param must be current or YYYY-WNN"})
def handle_menu(event):
"""Return the published menu in the portal's public MenuPayload shape."""
week, error = _week_from_path(event)
if error is not None:
return error
menu = get_menu(week)
if menu is None:
@ -623,7 +628,9 @@ def handle_my_orders(event):
def handle_form_status(event):
week = event.get("pathParameters", {}).get("week", current_week())
week, error = _week_from_path(event)
if error is not None:
return error
status = get_form_status(week)
result = {"week": week, "status": status}
if status == "closed":

View file

@ -12,6 +12,8 @@ def test_openapi_uses_redocly_recommended():
ci = (ROOT / ".github" / "workflows" / "ci.yml").read_text()
assert "extends:" in redocly
assert "- recommended" in redocly
assert "operation-2xx-response: off" in redocly
assert "rule/operation-2xx-or-3xx-response" in redocly
assert "root: openapi.yaml" in redocly
assert '"openapi:lint"' in package
assert '"@redocly/cli": "2.52.1"' in package

View file

@ -1446,6 +1446,33 @@ def test_form_status_open(mock_week, mock_status):
assert "reopen_at" not in body, "reopen_at should NOT be present when form is open"
@patch("submit_order_handler.get_form_status", return_value="open")
@patch("submit_order_handler.current_week", return_value="2026-W20")
def test_form_status_current_maps_to_current_week(mock_week, mock_status):
from submit_order_handler import lambda_handler
event = _make_event(
method="GET", path="/form-status/current", path_parameters={"week": "current"}
)
status, body = _parse_response(lambda_handler(event, None))
assert status == 200, f"Expected 200, got {status}: {body}"
assert body["week"] == "2026-W20"
mock_status.assert_called_once_with("2026-W20")
@patch("submit_order_handler.get_form_status")
def test_form_status_rejects_invalid_week(mock_status):
from submit_order_handler import lambda_handler
event = _make_event(
method="GET", path="/form-status/nope", path_parameters={"week": "nope"}
)
status, body = _parse_response(lambda_handler(event, None))
assert status == 400, f"Expected 400, got {status}: {body}"
assert "week path param" in body["error"]
mock_status.assert_not_called()
@patch("submit_order_handler.get_form_status", return_value="closed")
@patch("submit_order_handler.current_week", return_value="2026-W20")
def test_form_status_closed_reopen_at(mock_week, mock_status):