Strengthen review contracts and HTTP guidance

- add outbound HttpClient transport and HTTP status review rules with paired fixtures`n- resolve layered action-skill overrides deterministically across enabled layers`n- validate findings reports and enforce measurable changed-fixture coverage
This commit is contained in:
demiliani 2026-09-23 15:31:21 +02:00
parent 07e324ddbc
commit 45ca57a23e
21 changed files with 830 additions and 34 deletions

View file

@ -0,0 +1,21 @@
codeunit 50100 "HTTP Status Handling Bad"
{
procedure GetCustomer(CustomerId: Guid): JsonObject
var
Client: HttpClient;
Response: HttpResponseMessage;
CustomerJson: JsonObject;
ResponseText: Text;
begin
if not Client.Get(
StrSubstNo('https://api.example.com/customers/%1', CustomerId),
Response)
then
Error('The customer service could not be reached.');
// A completed request can still contain a 4xx or 5xx error document.
Response.Content().ReadAs(ResponseText);
CustomerJson.ReadFrom(ResponseText);
exit(CustomerJson);
end;
}

View file

@ -0,0 +1,23 @@
codeunit 50100 "HTTP Status Handling Good"
{
procedure GetCustomer(CustomerId: Guid): JsonObject
var
Client: HttpClient;
Response: HttpResponseMessage;
CustomerJson: JsonObject;
ResponseText: Text;
begin
if not Client.Get(
StrSubstNo('https://api.example.com/customers/%1', CustomerId),
Response)
then
Error('The customer service could not be reached.');
if not Response.IsSuccessStatusCode() then
Error('The customer service returned HTTP status %1.', Response.HttpStatusCode());
Response.Content().ReadAs(ResponseText);
CustomerJson.ReadFrom(ResponseText);
exit(CustomerJson);
end;
}

View file

@ -0,0 +1,31 @@
---
bc-version: [all]
domain: web-services
keywords: [httpclient, httpresponsemessage, issuccessstatuscode, httpstatuscode, response-body, json]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Check HTTP status before consuming the response body
## Description
A successful AL `HttpClient` call only confirms that the platform completed the HTTP exchange. The server can still return `4xx` or `5xx`, often with an error document whose shape differs from the expected success payload. Parsing that body as business data can produce misleading parse errors, incomplete records, or decisions based on an error response.
## Best Practice
After handling any platform or transport failure, check `HttpResponseMessage.IsSuccessStatusCode()` or the expected `HttpStatusCode()` before interpreting the response body as a success payload. Handle non-success status explicitly and include safe diagnostic context when appropriate. A bounded error body may be read for diagnostics, but it must not enter the success parsing path.
See sample: [`check-http-status-before-consuming-response-body.good.al`](check-http-status-before-consuming-response-body.good.al).
## Anti Pattern
Checking only the Boolean result of `Get`, `Post`, `Put`, `Delete`, or `Send` and then parsing `Response.Content()` as the expected payload. The Boolean can be `true` for any HTTP status, including authentication failures, throttling, validation errors, and server failures.
See sample: [`check-http-status-before-consuming-response-body.bad.al`](check-http-status-before-consuming-response-body.bad.al).
## References
- [HttpResponseMessage.IsSuccessStatusCode method](https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/methods-auto/httpresponsemessage/httpresponsemessage-issuccessstatuscode-method)
- [HttpClient data type](https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/methods-auto/httpclient/httpclient-data-type)

View file

@ -0,0 +1,18 @@
codeunit 50100 "Http Platform Failure Bad"
{
procedure GetCustomer(CustomerId: Guid): Text
var
Client: HttpClient;
Response: HttpResponseMessage;
ResponseText: Text;
RequestSucceeded: Boolean;
begin
RequestSucceeded := Client.Get(
StrSubstNo('https://api.example.com/customers/%1', CustomerId),
Response);
// Response content is unavailable when the platform call failed.
Response.Content().ReadAs(ResponseText);
exit(ResponseText);
end;
}

View file

@ -0,0 +1,18 @@
codeunit 50100 "Http Platform Failure Good"
{
procedure GetCustomer(CustomerId: Guid): Text
var
Client: HttpClient;
Response: HttpResponseMessage;
ResponseText: Text;
begin
if not Client.Get(
StrSubstNo('https://api.example.com/customers/%1', CustomerId),
Response)
then
Error('The customer service could not be reached.');
Response.Content().ReadAs(ResponseText);
exit(ResponseText);
end;
}

View file

@ -0,0 +1,31 @@
---
bc-version: [all]
domain: web-services
keywords: [httpclient, transport-failure, boolean-return, httpresponsemessage, content, runtime-error]
technologies: [al]
countries: [w1]
application-area: [all]
---
# Handle HttpClient platform failure before accessing the response
## Description
AL `HttpClient` methods can fail before a usable HTTP response exists because of an invalid request, DNS or network failure, certificate validation, timeout, a disabled extension setting, or the response-size limit. When code captures the optional Boolean return value, `false` reports this platform or transport failure. The accompanying `HttpResponseMessage` is not safe to consume; accessing its content after the failed call can raise another error and obscure the original failure.
## Best Practice
When capturing the Boolean return value from `Get`, `Post`, `Put`, `Delete`, or `Send`, stop the current response-processing path immediately when it is `false`. Report or propagate the transport failure without reading status, headers, or content. Omitting the optional Boolean is also valid when fail-fast behavior is intended: the runtime then raises an error if the operation cannot execute.
See sample: [`handle-httpclient-platform-failure-before-response-access.good.al`](handle-httpclient-platform-failure-before-response-access.good.al).
## Anti Pattern
Capturing a failed call in a Boolean and then reading `Response.Content()`, parsing the body, or otherwise treating `Response` as usable. Do not report omission of the Boolean by itself; that form deliberately delegates failure propagation to the runtime.
See sample: [`handle-httpclient-platform-failure-before-response-access.bad.al`](handle-httpclient-platform-failure-before-response-access.bad.al).
## References
- [HttpClient.Send method](https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/methods-auto/httpclient/httpclient-send-method)
- [Call external services with HttpClient](https://learn.microsoft.com/dynamics365/business-central/dev-itpro/developer/devenv-httpclient)