Execute JSON API request and return typed envelope¶
Given a base URI, caller identity, and an authenticator, this operation constructs, executes, retries, and validates an HTTP request to a SAIF Web API, returning a typed ApiResponse<T> envelope or throwing a typed SAIFException subtype.
| Field | Value |
|---|---|
| Operation ID | OP-01 |
| Trigger | Caller invokes GetResponse<T>, PostJson<T>, PutJson<T>, PatchJson<T>, or DeleteJson<T> with a relative URI segment and (for write verbs) a request body object. |
| Inputs | methodUriSegment (string), requestBody (object, write verbs only); instance state _serviceBaseUri, _clientInfo, _authenticator, TimeoutOverride, SetOnBehalfOfUserHeaders, RetryOnStatusCodes, RetryDelayInMs, EnsureSuccessfulResponse, DateTimeZoneHandling. |
| Outputs | ApiResponse<T> (Results, Server, StatusCode, Version) — or a thrown SAIFException subtype. |
| Primary components | JsonHttpClient.GetJsonResponse (private), JsonHttpClient.GetApiResponse<T> |
| Entry point | src/SAIF.Web.API.Clients/JsonHttpClient.cs |
Steps¶
- Create the transport client:
new RestClient(_serviceBaseUri); assignAuthenticator;ClearHandlers();AddHandler("application/json", () => new JsonDeserializer())(BR-02). - Apply timeout: if
TimeoutOverride > 0, setclient.Timeout(BR-03). - Build the request:
new RestRequest(methodUriSegment, method); assignrequest.JsonSerializer = new SAIF.Web.API.Clients.JsonSerializer(DateTimeZoneHandling)(BR-07). - This step delegates request-body serialization to a locally-implemented operation.
- Configures a Newtonsoft-based serializer with
MissingMemberHandling.Ignore,NullValueHandling.Include,DefaultValueHandling.Include, and the configuredDateTimeZoneHandling(BR-21).
Origin: Step 3.1 is implemented in Serialize request body (
SAIF.Web.API.Clients.35) and executed on behalf of this operation. 4. Attach body: ifbody != null,request.AddJsonBody(body), which invokesJsonSerializer.Serialize(see Serialize request body). 5. Add identity headers:Client-Name←_clientInfo.MachineName;Application-ID←_clientInfo.ApplicationId;Client-User←_clientInfo.UserId(BR-01). 6. Add impersonation header (conditional): ifSetOnBehalfOfUserHeaders, addOnBehalfOfUser←HttpContext.Current.DomainlessUser()(BR-04). - In this .35 project, the supportingHttpContextExtensions.DomainlessUsersource file is not compiled andSystem.Webis not referenced, so this branch has no working implementation here.* 7. Execute:client.Execute(request). 8. Retry decision: ifretries > 0andRetryOnStatusCodescontains the returned status,Thread.Sleep(RetryDelayInMs)then recurse withretries - 1(BR-05). 9. Error gate: ifEnsureSuccessfulResponse, callExceptionHandler.EnsureSuccessfulResponse(response)(BR-06). - This step delegates to a locally-implemented operation. - Evaluates whether the status is outside 200–399 and, if so, maps the response to a typed exception.Origin: Step 9.1 is implemented in Translate HTTP failure to typed exception (
SAIF.Web.API.Clients.35) and executed on behalf of this operation. - On failure: an exception is thrown and propagates to the caller; steps 10–12 are skipped. 10. Wrap raw response: buildJsonResponse { Content, Headers, StatusCode, SuccessfulRequest = (int)StatusCode < 400 }. 11. Deserialize payload:GetApiResponse<T>→GetContentArray<T>(content, DateTimeZoneHandling)intoResults(BR-08, BR-09). 12. Populate envelope metadata:Server← first header namedServer-Name;StatusCode←jsonResponse.StatusCode;Version←jsonResponse.Version(BR-10).
Process flow¶
The following diagram visualizes this operation's control flow.
flowchart TD
Start([Verb method invoked]) --> S1["Create RestClient and<br>RestRequest"]
S1 --> S2["Add identity and<br>impersonation headers"]
S2 --> S3[Execute request]
S3 --> D{"Retryable status and<br>retries remain?"}
D -->|Yes| Retry["Sleep RetryDelayInMs,<br>retry"]
Retry --> S3
D -->|No| Gate{"EnsureSuccessfulResponse<br>and status outside<br>200-399?"}
Gate -->|Yes| EndErr(["Throw typed<br>SAIFException"])
Gate -->|No| Deserialize["Deserialize payload into<br>ApiResponse"]
Deserialize --> EndOk([Return ApiResponse T])
Failure and edge-case behavior¶
- An exception thrown at step 9 propagates to the caller; steps 10–12 are skipped.
- Retry at step 8 happens before the error gate, so retryable failures (502/503/401/transport-failure
0) are re-attempted up to 3 times before any exception is raised. ApiResponse<T>.Versionis never populated by this library:GetApiResponse<T>copiesjsonResponse.Version, butGetJsonResponsenever assignsJsonResponse.Versionwhen constructing the object, so the value is always null.*
Note: Statements marked with
*were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts.
Related documentation¶
Sources¶
- src/SAIF.Web.API.Clients/JsonHttpClient.cs
- src/SAIF.Web.API.Clients/JsonResponse.cs