Add CMFRT best practices and anti-patterns documentation for various coding standards

This commit is contained in:
BeytullahCengiz88 2026-07-05 20:10:55 +02:00
parent cfcf16a00e
commit 906ddcfd72
21 changed files with 427 additions and 5 deletions

View file

@ -0,0 +1,15 @@
page 55035 "CMFRT AQ FS JJL API"
{
PageType = API;
SourceTable = "Job Journal Line"; // real table exposed directly to the API
trigger OnInsertRecord(BelowxRec: Boolean): Boolean
begin
// Manual insert/exit boilerplate duplicates the framework insert
// and couples the HTTP request to the real-table insert: no retry,
// no error queue, one validation error fails the whole request.
Rec.Insert(true);
Rec.CMFRTAQFSLogIncomingRequest();
exit(false);
end;
}

View file

@ -0,0 +1,33 @@
page 55035 "CMFRT AQ FS JJL API"
{
PageType = API;
SourceTable = "CMFRT AQ FS JJL Buffer"; // buffer table, not Job Journal Line
trigger OnInsertRecord(BelowxRec: Boolean): Boolean
begin
// Side effects only; framework performs the default insert.
Rec.CMFRTAQFSLogIncomingRequest();
end;
}
codeunit 55038 "CMFRT AQ FS JJL Proc"
{
procedure CMFRTAQProcessPendingEntries()
var
JJLBuffer: Record "CMFRT AQ FS JJL Buffer";
JJLCreator: Codeunit "CMFRT AQ FS JJL Creator";
begin
JJLBuffer.SetRange("CMFRT AQ Status", "CMFRT AQ Buffer Status"::"CMFRT AQ Pending");
if JJLBuffer.FindSet(true) then
repeat
// Proc owns the error boundary: one bad row does not abort the batch.
if Codeunit.Run(Codeunit::"CMFRT AQ FS JJL Creator", JJLBuffer) then
JJLBuffer."CMFRT AQ Status" := "CMFRT AQ Buffer Status"::"CMFRT AQ Processed"
else begin
JJLBuffer."CMFRT AQ Status" := "CMFRT AQ Buffer Status"::"CMFRT AQ Error";
JJLBuffer."CMFRT AQ Error Message" := CopyStr(GetLastErrorText(), 1, MaxStrLen(JJLBuffer."CMFRT AQ Error Message"));
end;
JJLBuffer.Modify(true);
until JJLBuffer.Next() = 0;
end;
}

View file

@ -0,0 +1,26 @@
---
bc-version: [all]
domain: architecture
keywords: [api, buffer, staging, oninsertrecord, api-page, inbound, creator, proc, codeunit-run]
technologies: [al]
countries: [w1]
application-area: [all]
---
# CMFRT inbound API pages write to buffer tables
## Description
Inbound CMFRT API pages never source from real application tables. Each API page sources from a dedicated buffer (staging) table owned by the extension. The buffer row records the raw inbound payload plus a status field (Pending/Processing/Processed/Error) and an operation enum where applicable. A Proc codeunit picks up pending buffer rows and owns the `Codeunit.Run` error boundary; a Creator codeunit transfers buffer values into the real table via `Validate` calls. The API page's `OnInsertRecord` trigger contains no manual insert plumbing — the framework performs the default insert; the trigger only performs side effects such as request logging.
## Best Practice
For each inbound API: one buffer table (with status and error-message fields), one API page sourced from the buffer, one Proc codeunit that iterates pending rows and calls the Creator inside a `Codeunit.Run` boundary so one failing row does not abort the batch, and one Creator codeunit that fills and inserts the real record. `OnInsertRecord` bodies contain only logging or metadata capture and no `exit` statement, so the framework insert proceeds.
See sample: `cmfrt-buffer-table-api-pattern.good.al`.
## Anti Pattern
An API page sourced directly from a real table (Sales Header, Job, Ship-to Address), or an `OnInsertRecord` trigger that calls `Rec.Insert(true)` followed by `exit(false)` to suppress the framework insert. Direct-to-real-table APIs make inbound failures atomic with the HTTP request (no retry, no error queue), and the manual insert/exit boilerplate duplicates framework behaviour while hiding the insert from other trigger logic.
See sample: `cmfrt-buffer-table-api-pattern.bad.al`.