SAIF.Web.API operations and processes¶
This page is the operation catalog and cross-operation hub for this library. Each operation's detailed, step-by-step logic lives in its own page under operations/. Ten operations are implemented across the library's five public types; no database, message queue, or file-system operations exist in any path.
Operation catalog¶
| Operation | Intent | Trigger | Inputs | Outputs | Rules |
|---|---|---|---|---|---|
| Post-process an API response | Normalize every outbound Web API response with a correlation ID, Splunk lookup URL, structured error body, log entry, and trace entry. | Every HTTP request flowing through the Web API message-handler pipeline where ApiResponseHandler is registered. |
HttpRequestMessage, CancellationToken, request-scoped ILogService/IEnvironmentService (may be null), ambient HttpContextBase |
HttpResponseMessage (original with Server-Name header, or rebuilt with ErrorResponse body) |
BR-WEBAPI-001 · BR-WEBAPI-002 |
| Generate a log correlation identifier | Produce a unique, time-ordered correlation ID for the current response. | Post-process an API response, step 6. | none | string |
BR-WEBAPI-005 |
| Build the Splunk error-lookup URL | Compose (or fall back to a default) Splunk deep-link URL for the current MessageID. |
Post-process an API response, step 7. | IEnvironmentService (may be null) |
string URL |
BR-WEBAPI-006 |
| Map a Web API error to an ErrorResponse | Translate an HttpError into the library's normalized ErrorResponse DTO, including the 400-classification rule. |
Post-process an API response, step 10. | HttpStatusCode, HttpError |
SAIF.API.Responses.ErrorResponse |
BR-WEBAPI-002 · BR-WEBAPI-003 |
| Compose the trace and log message | Build the newline-joined trace/log payload, redacting password-like content when debug logging is on. | Post-process an API response, steps 13, 14, 15. | request/response context, debugMode flag |
newline-joined string |
BR-WEBAPI-007 · BR-WEBAPI-009 |
| Map a SAIF exception to an HTTP status code | Provide a static, catch-clause-based mapping from SAIF.API.Exceptions.* types to HttpStatusCode. |
Called explicitly by a consumer (no call site inside this library). | Exception |
HttpStatusCode |
BR-WEBAPI-011 |
| Enforce HTTPS on an action | Redirect non-HTTPS requests to HTTPS, with an app-setting-controlled exemption for local requests. | Web API action-filter pipeline, before action execution, on any decorated controller/action. | HttpActionContext, appSettings["RequireSSLForLocal"] |
none (side effect: HTTP redirect) | BR-WEBAPI-012 · BR-WEBAPI-013 |
| Authorize a request against SAIF roles | Decide whether the current caller holds any of the roles/resources declared on [SaifAuthorize], delegating the decision to ISecurityApiClient. |
Web API authorization-filter pipeline on any decorated controller/action. | HttpActionContext, constructed Roles string, request-scoped ISecurityApiClient/IEnvironmentService |
bool |
BR-WEBAPI-014 · BR-WEBAPI-015 · BR-WEBAPI-016 · BR-WEBAPI-017 |
| Handle an unauthorized request | Log the denial (when the user is known) and answer the caller with a structured 401. | Invoked by AuthorizeAttribute when Authorize a request against SAIF roles returns false. |
HttpActionContext |
sets actionContext.Response to 401 |
BR-WEBAPI-014 · BR-WEBAPI-018 |
| Read the first value of a request header | Return the first value of a request header, or an empty string, without ever throwing. | Compose the trace and log message, step 2, and any consumer call. | HttpRequestMessage, header key |
string |
BR-WEBAPI-019 |
Process flow diagram¶
The following diagram visualizes the primary operational flow for the response post-processing pipeline, the dominant cross-cutting path through this library.
flowchart TD
Start([Request received]) --> Base["Run downstream pipeline<br>via base.SendAsync"]
Base --> Resolve["Resolve ILogService /<br>IEnvironmentService"]
Resolve --> Ids["Assign MessageID and<br>MessageIDUrl"]
Ids --> IsError{"Non-success HttpError<br>content?"}
IsError -->|No| Trace["TraceInfo — success path"]
IsError -->|Yes| Msg["GetExceptionMessage"]
Msg --> ErrResp["GetErrorResponse"]
ErrResp --> Force400{"ErrorCode == 400?"}
Force400 -->|Yes| SetStatus["response.StatusCode =<br>400"]
Force400 -->|No| Rebuild
SetStatus --> Rebuild["Rebuild response with<br>ErrorResponse body"]
Rebuild --> LogErr["Log exception, possibly<br>twice"]
LogErr --> Trace
Trace --> Header["Add Server-Name header"]
Header --> End([Return response])
Failure and edge-case behavior¶
- A downstream exception that is not surfaced as
HttpErrorcontent passes through Post-process an API response unchanged — no normalization occurs. ILogService/IEnvironmentServiceunavailability degrades gracefully in Post-process an API response, but Authorize a request against SAIF roles and Handle an unauthorized request both fail closed (throw) on the same missing-dependency condition.- A configured
splunksearchwith a blanksplunk.error.queryyields a Splunk URL with an empty query fragment — see Build the Splunk error-lookup URL. - Debug-mode tracing on a context-less request can raise
NullReferenceException— see Compose the trace and log message. HttpContext.Currentis web-host only for the HTTPS-enforcement filter, and the redirect raisesThreadAbortExceptionby design — see Enforce HTTPS on an action.- Denial from Authorize a request against SAIF roles always returns
401 Unauthorized(not403 Forbidden) via Handle an unauthorized request, whileExceptionHandler.ToHttpErrormaps SAIF's ownUnauthorizedAccessExceptionto403— the two authorization-adjacent paths disagree on status code.
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Configuration
- Business rules
- Security and authorization
- API reference
Sources¶
src/SAIF.Web.API/ApiResponseHandler.cssrc/SAIF.Web.API/ExceptionHandler.cssrc/SAIF.Web.API/HttpRequestExtensions.cssrc/SAIF.Web.API/RequireSSLAttribute.cssrc/SAIF.Web.API/SaifAuthorizeAttribute.cssrc/SAIF.Web.API.Tests/SAIF.Web.API.Tests/ApiResponseHandlerTests.cs