API Logging without rollback due to hard errors
In a current API connection in a customer project I have just dealt with the topic of API request logging again. I had already built a small prototype that allows logging via webservice.
But it is much easier than that. Namely by using background sessions. This can persist the information despite hard errors in the foreground session. This is extremely useful for API implementations where you would like to have the explicit rollback in case of api errors but keep the request or response in a log for further debugging.
In our example we have an temporary api parameter table, in which we have various settings for calling the api interface like the url, rest method, parameters and payloads. And additionally an api log table with the fields we want to save:
codeunit 79007 "MyApi Log Management"
{
TableNo = "MyApi Api Parameters";
trigger OnRun()
begin
LogWebserviceCall(Rec);
end;
procedure LogWebserviceCall(MyApiSetup: Record "MyApi API Setup"; var MyApiParameters: Record "MyApi API Parameters" temporary)
var
SessionID: Integer;
begin
if not MyApiSetup."Log API Calls" then
exit;
//The codeunit is calling itself in a background session
StartSession(SessionID, Codeunit::"MyApi Log Management", CompanyName, MyApiParameters);
end;
procedure LogWebserviceCall(var MyApiParameters: Record "MyApi API Parameters" temporary)
var
MyApiLog: Record "MyApi Api Log";
begin
MyApiLog.Init();
MyApiLog."No." := 0;
//Request
MyApiLog."Query DateTime" := CurrentDateTime;
MyApiLog."Request Parameters" := MyApiParameters.Method;
MyApiLog."Request Method" := CopyStr(Format(MyApiParameters.RestMethod), 1, MaxStrLen(MyApiLog."Request Method"));
MyApiLog."Request URL" := MyApiParameters.URL;
//Response
MyApiLog."Response Code" := MyApiParameters."Response Code";
MyApiLog."Error Message" := CopyStr(MyApiParameters."Error Message", 1, MaxStrLen(MyApiLog."Error Message"));
//Blob fields
MyApiLog."Request Content" := MyApiParameters."Request Content";
MyApiLog."Response Content" := MyApiParameters."Response Content";
MyApiLog.User := CopyStr(UserId, 1, MaxStrLen(MyApiLog.User));
if not MyApiLog.Insert() then;
end;
}
Now, if an error happens in the web service call, we can still pass all the parameters into the background session and thus persist them. So, basically the logging codeunit is calling itself in a background session.
//Send webservice query
WebClient.Send(RequestMessage, ResponseMessage);
//Persist for Logging
MyApiParameters."Response Code" := ResponseMessage.HttpStatusCode();
//Fetch result
if not ResponseMessage.IsSuccessStatusCode() then begin
ErrorMessage := StrSubstNo('API Error: %1', ResponseMessage.ReasonPhrase());
//Write to temp. parameter table
MyApiParameters."Error Message" := CopyStr(ErrorMessage, 1, MaxStrLen(MyApiParameters."Error Message"));
//Log to API Log Entries
MyApiApiLog.LogWebserviceCall(MyApiSetup, MyApiParameters);
Error(ErrorMessage);
end else begin
//...
end;