diff --git a/crates/omnigraph-server/src/api.rs b/crates/omnigraph-server/src/api.rs index 24374fa..3af59ab 100644 --- a/crates/omnigraph-server/src/api.rs +++ b/crates/omnigraph-server/src/api.rs @@ -344,6 +344,11 @@ pub enum ErrorCode { Forbidden, BadRequest, NotFound, + /// 405 Method Not Allowed — the route exists but the active server + /// mode doesn't serve this method (e.g. `GET /graphs` in single-graph + /// mode). Distinct from 404 so clients can tell "wrong context" from + /// "no such resource." + MethodNotAllowed, Conflict, /// 429 Too Many Requests — per-actor admission cap exceeded. /// Clients should respect the `Retry-After` header. diff --git a/crates/omnigraph-server/src/lib.rs b/crates/omnigraph-server/src/lib.rs index ee19c01..dfa5799 100644 --- a/crates/omnigraph-server/src/lib.rs +++ b/crates/omnigraph-server/src/lib.rs @@ -567,6 +567,20 @@ impl ApiError { } } + /// HTTP 405 Method Not Allowed. Used when the route is mounted but + /// the active server mode doesn't serve it (`GET /graphs` in + /// single-graph mode returns this instead of 404 so clients can + /// distinguish "wrong context" from "no such resource"). + pub fn method_not_allowed(message: impl Into) -> Self { + Self { + status: StatusCode::METHOD_NOT_ALLOWED, + code: ErrorCode::MethodNotAllowed, + message: message.into(), + merge_conflicts: Vec::new(), + manifest_conflict: None, + } + } + pub fn conflict(message: impl Into) -> Self { Self { status: StatusCode::CONFLICT, @@ -1155,13 +1169,9 @@ async fn server_graphs_list( // 405 in single mode — there's no registry to enumerate, and the // legacy URL surface didn't expose this endpoint. if matches!(state.mode(), ServerMode::Single { .. }) { - return Err(ApiError { - status: StatusCode::METHOD_NOT_ALLOWED, - code: ErrorCode::BadRequest, - message: "GET /graphs is only available in multi-graph mode".to_string(), - merge_conflicts: Vec::new(), - manifest_conflict: None, - }); + return Err(ApiError::method_not_allowed( + "GET /graphs is only available in multi-graph mode", + )); } // Server-level Cedar gate. `state.server_policy` is loaded from diff --git a/openapi.json b/openapi.json index f5bc244..041531c 100644 --- a/openapi.json +++ b/openapi.json @@ -1256,6 +1256,7 @@ "forbidden", "bad_request", "not_found", + "method_not_allowed", "conflict", "too_many_requests", "internal"