diff --git a/src/System Application/App/Rest Client/app.json b/src/System Application/App/Rest Client/app.json
index 4be03c0715..fe0060b51c 100644
--- a/src/System Application/App/Rest Client/app.json
+++ b/src/System Application/App/Rest Client/app.json
@@ -34,11 +34,10 @@
"idRanges": [
{
"from": 2350,
- "to": 2361
+ "to": 2362
}
],
"target": "OnPrem",
- "runtime": "12.0",
"resourceExposurePolicy": {
"allowDebugging": true,
"allowDownloadingSource": true,
diff --git a/src/System Application/App/Rest Client/src/Authentication/HttpAuthOAuthClientCredentials.Codeunit.al b/src/System Application/App/Rest Client/src/Authentication/HttpAuthOAuthClientCredentials.Codeunit.al
index 3cccb6fb90..cd73e7752e 100644
--- a/src/System Application/App/Rest Client/src/Authentication/HttpAuthOAuthClientCredentials.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/Authentication/HttpAuthOAuthClientCredentials.Codeunit.al
@@ -7,6 +7,7 @@ namespace System.RestClient;
codeunit 2361 "HttpAuthOAuthClientCredentials" implements "Http Authentication"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
diff --git a/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationAnonymous.Codeunit.al b/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationAnonymous.Codeunit.al
index abf1c542c3..3ca85bf67e 100644
--- a/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationAnonymous.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationAnonymous.Codeunit.al
@@ -7,6 +7,7 @@ namespace System.RestClient;
/// Implementation of the "Http Authentication" interface for a anonymous request.
codeunit 2358 "Http Authentication Anonymous" implements "Http Authentication"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
diff --git a/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationBasic.Codeunit.al b/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationBasic.Codeunit.al
index 552d139504..f5499c06a3 100644
--- a/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationBasic.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/Authentication/HttpAuthenticationBasic.Codeunit.al
@@ -9,6 +9,7 @@ using System;
codeunit 2359 "Http Authentication Basic" implements "Http Authentication"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
diff --git a/src/System Application/App/Rest Client/src/ExceptionHandling/RestClientException.Enum.al b/src/System Application/App/Rest Client/src/ExceptionHandling/RestClientException.Enum.al
new file mode 100644
index 0000000000..78fc1c25b7
--- /dev/null
+++ b/src/System Application/App/Rest Client/src/ExceptionHandling/RestClientException.Enum.al
@@ -0,0 +1,54 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace System.RestClient;
+
+///
+/// This enum contains the exceptions of the Rest Client.
+///
+enum 2351 "Rest Client Exception"
+{
+ ///
+ /// Specifies that the exception is an unknown exception.
+ ///
+ value(100; UnknownException)
+ {
+ Caption = 'Unknown Exception';
+ }
+ ///
+ /// Specifies that the connection failed.
+ ///
+ value(101; ConnectionFailed)
+ {
+ Caption = 'Connection Failed';
+ }
+ ///
+ /// Specifies that the request is blocked by the environment.
+ ///
+ value(102; BlockedByEnvironment)
+ {
+ Caption = 'Blocked By Environment';
+ }
+ ///
+ /// Specifies that the request failed.
+ ///
+ value(103; RequestFailed)
+ {
+ Caption = 'Request Failed';
+ }
+ ///
+ /// Specifies that the content is not valid JSON.
+ ///
+ value(201; InvalidJson)
+ {
+ Caption = 'Invalid Json';
+ }
+ ///
+ /// Specifies that the content is not valid XML.
+ ///
+ value(202; InvalidXml)
+ {
+ Caption = 'Invalid Xml';
+ }
+}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/ExceptionHandling/RestClientExceptionBuilder.Codeunit.al b/src/System Application/App/Rest Client/src/ExceptionHandling/RestClientExceptionBuilder.Codeunit.al
new file mode 100644
index 0000000000..177845c2b2
--- /dev/null
+++ b/src/System Application/App/Rest Client/src/ExceptionHandling/RestClientExceptionBuilder.Codeunit.al
@@ -0,0 +1,51 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+namespace System.RestClient;
+
+codeunit 2362 "Rest Client Exception Builder"
+{
+ Access = Public;
+ InherentEntitlements = X;
+ InherentPermissions = X;
+
+ ///
+ /// Creates an exception with the specified error code and message. The exception is collectible if the errors are currently being collected.
+ ///
+ /// The error code for the exception.
+ /// The message for the exception.
+ /// The exception with the specified error code and message.
+ procedure CreateException(RestClientException: Enum "Rest Client Exception"; ErrorMessage: Text) Exception: ErrorInfo
+ begin
+ Exception := CreateException(RestClientException, ErrorMessage, IsCollectingErrors());
+ end;
+
+ ///
+ /// Creates an exception with the specified error code, message, and collectible flag.
+ ///
+ /// The error code for the exception.
+ /// The message for the exception.
+ /// Whether the exception is collectible.
+ /// The exception with the specified error code, message, and collectible flag.
+ procedure CreateException(RestClientException: Enum "Rest Client Exception"; ErrorMessage: Text; Collectible: Boolean) Exception: ErrorInfo
+ begin
+ Exception.Message := ErrorMessage;
+ Exception.CustomDimensions.Add('ExceptionCode', Format(RestClientException.AsInteger()));
+ Exception.CustomDimensions.Add('ExceptionName', RestClientException.Names.Get(RestClientException.Ordinals.IndexOf(RestClientException.AsInteger())));
+ Exception.Collectible := Collectible;
+ end;
+
+ ///
+ /// Gets the exception code from the error info.
+ ///
+ /// The error info of the exception.
+ /// The exception code.
+ procedure GetRestClientException(ErrInfo: ErrorInfo) RestClientException: Enum "Rest Client Exception"
+ var
+ ExceptionCode: Integer;
+ begin
+ Evaluate(ExceptionCode, ErrInfo.CustomDimensions.Get('ExceptionCode'));
+ RestClientException := Enum::"Rest Client Exception".FromInteger(ExceptionCode);
+ end;
+}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Codeunit.al b/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Codeunit.al
index c7ab685cf7..41f24996e3 100644
--- a/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Codeunit.al
@@ -6,14 +6,15 @@ namespace System.RestClient;
codeunit 2360 "Http Client Handler" implements "Http Client Handler"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
- procedure Send(HttpClient: HttpClient; HttpRequestMessage: Codeunit "Http Request Message"; var HttpResponseMessage: Codeunit "Http Response Message") Success: Boolean;
+ procedure Send(CurrHttpClientInstance: HttpClient; HttpRequestMessage: Codeunit "Http Request Message"; var HttpResponseMessage: Codeunit "Http Response Message") Success: Boolean;
var
ResponseMessage: HttpResponseMessage;
begin
- Success := HttpClient.Send(HttpRequestMessage.GetHttpRequestMessage(), ResponseMessage);
- HttpResponseMessage.SetResponseMessage(ResponseMessage);
+ Success := CurrHttpClientInstance.Send(HttpRequestMessage.GetHttpRequestMessage(), ResponseMessage);
+ HttpResponseMessage := HttpResponseMessage.Create(ResponseMessage);
end;
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Interface.al b/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Interface.al
index 849a4605ea..b4d492dfd2 100644
--- a/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Interface.al
+++ b/src/System Application/App/Rest Client/src/HttpClientHandler/HttpClientHandler.Interface.al
@@ -6,5 +6,5 @@ namespace System.RestClient;
interface "Http Client Handler"
{
- procedure Send(HttpClient: HttpClient; HttpRequestMessage: Codeunit "Http Request Message"; var HttpResponseMessage: Codeunit "Http Response Message") Success: Boolean;
+ procedure Send(CurrHttpClientInstance: HttpClient; HttpRequestMessage: Codeunit "Http Request Message"; var HttpResponseMessage: Codeunit "Http Response Message") Success: Boolean;
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/HttpContent.Codeunit.al b/src/System Application/App/Rest Client/src/HttpContent.Codeunit.al
index 8295f767a9..8c1caf0592 100644
--- a/src/System Application/App/Rest Client/src/HttpContent.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/HttpContent.Codeunit.al
@@ -9,6 +9,7 @@ using System.Utilities;
/// Holder object for the Http Content data.
codeunit 2354 "Http Content"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
@@ -20,18 +21,20 @@ codeunit 2354 "Http Content"
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'text/plain'.
- procedure Create(Content: Text) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: Text): Codeunit "Http Content"
begin
- HttpContent := Create(Content, '');
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified SecretText content.
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'text/plain'.
- procedure Create(Content: SecretText) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: SecretText): Codeunit "Http Content"
begin
- HttpContent := Create(Content, '');
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified Text content and content type.
@@ -39,10 +42,10 @@ codeunit 2354 "Http Content"
/// The content type of the content to send to the server.
/// The Http Content object.
/// If the ContentType parameter is not specified, it will be set to 'text/plain'.
- procedure Create(Content: Text; ContentType: Text) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: Text; ContentType: Text): Codeunit "Http Content"
begin
- SetContent(Content, ContentType);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content, ContentType);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified SecretText content and content type.
@@ -50,59 +53,60 @@ codeunit 2354 "Http Content"
/// The content type of the content to send to the server.
/// The Http Content object.
/// If the ContentType parameter is not specified, it will be set to 'text/plain'.
- procedure Create(Content: SecretText; ContentType: Text) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: SecretText; ContentType: Text): Codeunit "Http Content"
begin
- SetContent(Content, ContentType);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content, ContentType);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified JsonObject content.
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'application/json'.
- procedure Create(Content: JsonObject) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: JsonObject): Codeunit "Http Content"
begin
- SetContent(Content);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified JsonArray content.
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'application/json'.
- procedure Create(Content: JsonArray) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: JsonArray): Codeunit "Http Content"
begin
- SetContent(Content);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified JsonToken content.
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'application/json'.
- procedure Create(Content: JsonToken) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: JsonToken): Codeunit "Http Content"
begin
- SetContent(Content);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified XmlDocument content.
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'text/xml'.
- procedure Create(Content: XmlDocument) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: XmlDocument): Codeunit "Http Content"
begin
- SetContent(Content);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified "Temp Blob" Codeunit content.
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'application/octet-stream'.
- procedure Create(Content: Codeunit "Temp Blob") HttpContent: Codeunit "Http Content"
+ procedure Create(Content: Codeunit "Temp Blob"): Codeunit "Http Content"
begin
- HttpContent := Create(Content, '');
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified "Temp Blob" Codeunit content and content type.
@@ -110,19 +114,20 @@ codeunit 2354 "Http Content"
/// The content type of the content to send to the server.
/// The Http Content object.
/// If the ContentType parameter is not specified, it will be set to 'application/octet-stream'.
- procedure Create(Content: Codeunit "Temp Blob"; ContentType: Text) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: Codeunit "Temp Blob"; ContentType: Text): Codeunit "Http Content"
begin
- SetContent(Content, ContentType);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content, ContentType);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified InStream content.
/// The content to send to the server.
/// The Http Content object.
/// The Content-Type header will be set to 'application/octet-stream'.
- procedure Create(Content: InStream) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: InStream): Codeunit "Http Content"
begin
- HttpContent := Create(Content, '');
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
/// Initializes a new instance of the Http Content class with the specified InStream content and content type.
@@ -130,20 +135,20 @@ codeunit 2354 "Http Content"
/// The content type of the content to send to the server.
/// The Http Content object.
/// If the ContentType parameter is not specified, it will be set to 'application/octet-stream'.
- procedure Create(Content: InStream; ContentType: Text) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: InStream; ContentType: Text): Codeunit "Http Content"
begin
- SetContent(Content, ContentType);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content, ContentType);
+ exit(this);
end;
/// Initializes a new instance of the Http Content object with the specified HttpContent object.
/// The HttpContent object.
/// The HttpContent object.
/// The HttpContent must be properly prepared including the Content-Type header.
- procedure Create(Content: HttpContent) HttpContent: Codeunit "Http Content"
+ procedure Create(Content: HttpContent): Codeunit "Http Content"
begin
- SetContent(Content);
- HttpContent.SetHttpContentImpl(HttpContentImpl);
+ HttpContentImpl := HttpContentImpl.Create(Content);
+ exit(this);
end;
#endregion
@@ -232,57 +237,23 @@ codeunit 2354 "Http Content"
begin
JsonToken := HttpContentImpl.AsJson();
end;
- #endregion
-
- #region Internal Methods
- internal procedure SetContent(Content: Text; ContentType: Text)
- begin
- HttpContentImpl.SetContent(Content, ContentType);
- end;
-
- internal procedure SetContent(Content: SecretText; ContentType: Text)
- begin
- HttpContentImpl.SetContent(Content, ContentType);
- end;
- internal procedure SetContent(Content: InStream; ContentType: Text)
- begin
- HttpContentImpl.SetContent(Content, ContentType);
- end;
-
- internal procedure SetContent(TempBlob: Codeunit "Temp Blob"; ContentType: Text)
- begin
- HttpContentImpl.SetContent(TempBlob, ContentType);
- end;
-
- internal procedure SetContent(Content: XmlDocument)
- begin
- HttpContentImpl.SetContent(Content);
- end;
-
- internal procedure SetContent(Content: JsonObject)
- begin
- SetContent(Content.AsToken());
- end;
-
- internal procedure SetContent(Content: JsonArray)
- begin
- SetContent(Content.AsToken());
- end;
-
- internal procedure SetContent(Content: JsonToken)
- begin
- HttpContentImpl.SetContent(Content);
- end;
-
- internal procedure SetContent(var Value: HttpContent)
+ /// Gets the content of the HTTP response message as a JsonObject.
+ /// The content of the HTTP response message as a JsonObject.
+ /// Returns an empty JsonObject in case there is no content.
+ /// Fails in case the content is not a valid JSON document.
+ procedure AsJsonObject() JsonObject: JsonObject
begin
- HttpContentImpl.SetContent(Value);
+ JsonObject := HttpContentImpl.AsJsonObject();
end;
- internal procedure SetHttpContentImpl(Value: Codeunit "Http Content Impl.")
+ /// Gets the content of the HTTP response message as a JsonArray.
+ /// The content of the HTTP response message as a JsonArray.
+ /// Returns an empty JsonArray in case there is no content.
+ /// Fails in case the content is not a valid JSON document.
+ procedure AsJsonArray() JsonArray: JsonArray
begin
- HttpContentImpl := Value;
+ JsonArray := HttpContentImpl.AsJsonArray();
end;
#endregion
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/HttpContentImpl.Codeunit.al b/src/System Application/App/Rest Client/src/HttpContentImpl.Codeunit.al
index b384aa28ed..8b1488e5c5 100644
--- a/src/System Application/App/Rest Client/src/HttpContentImpl.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/HttpContentImpl.Codeunit.al
@@ -8,19 +8,103 @@ using System.Utilities;
codeunit 2355 "Http Content Impl."
{
+ Access = Internal;
InherentEntitlements = X;
InherentPermissions = X;
- Access = Internal;
-
var
- HttpContent: HttpContent;
+ CurrHttpContentInstance: HttpContent;
ContentTypeEmptyErr: Label 'The value of the Content-Type header must be specified.';
MimeTypeTextPlainTxt: Label 'text/plain', Locked = true;
MimeTypeTextXmlTxt: Label 'text/xml', Locked = true;
MimeTypeApplicationOctetStreamTxt: Label 'application/octet-stream', Locked = true;
MimeTypeApplicationJsonTxt: Label 'application/json', Locked = true;
+ #region Constructors
+ procedure Create(Content: Text) HttpContentImpl: Codeunit "Http Content Impl."
+ begin
+ HttpContentImpl := Create(Content, '');
+ end;
+
+ procedure Create(Content: SecretText) HttpContentImpl: Codeunit "Http Content Impl."
+ begin
+ HttpContentImpl := Create(Content, '');
+ end;
+
+ procedure Create(Content: Text; ContentType: Text): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content, ContentType);
+ exit(this);
+ end;
+
+ procedure Create(Content: SecretText; ContentType: Text): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content, ContentType);
+ exit(this);
+ end;
+
+ procedure Create(Content: JsonObject): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content.AsToken());
+ exit(this);
+ end;
+
+ procedure Create(Content: JsonArray): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content.AsToken());
+ exit(this);
+ end;
+
+ procedure Create(Content: JsonToken): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content);
+ exit(this);
+ end;
+
+ procedure Create(Content: XmlDocument): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content);
+ exit(this);
+ end;
+
+ procedure Create(Content: Codeunit "Temp Blob") HttpContentImpl: Codeunit "Http Content Impl."
+ begin
+ HttpContentImpl := Create(Content, '');
+ end;
+
+ procedure Create(Content: Codeunit "Temp Blob"; ContentType: Text): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content, ContentType);
+ exit(this);
+ end;
+
+ procedure Create(Content: InStream) HttpContent: Codeunit "Http Content Impl."
+ begin
+ HttpContent := Create(Content, '');
+ end;
+
+ procedure Create(Content: InStream; ContentType: Text): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content, ContentType);
+ exit(this);
+ end;
+
+ procedure Create(Content: HttpContent): Codeunit "Http Content Impl."
+ begin
+ ClearAll();
+ SetContent(Content);
+ exit(this);
+ end;
+ #endregion
+
procedure SetContentTypeHeader(ContentType: Text)
begin
if ContentType = '' then
@@ -30,58 +114,58 @@ codeunit 2355 "Http Content Impl."
procedure AddContentEncoding(ContentEncoding: Text)
var
- Headers: HttpHeaders;
+ ContentHeaders: HttpHeaders;
begin
- if not HttpContent.GetHeaders(Headers) then begin
- HttpContent.Clear();
- HttpContent.GetHeaders(Headers);
+ if not CurrHttpContentInstance.GetHeaders(ContentHeaders) then begin
+ CurrHttpContentInstance.Clear();
+ CurrHttpContentInstance.GetHeaders(ContentHeaders);
end;
- Headers.Add('Content-Encoding', ContentEncoding);
+ ContentHeaders.Add('Content-Encoding', ContentEncoding);
end;
procedure SetHeader(Name: Text; Value: Text)
var
- Headers: HttpHeaders;
+ ContentHeaders: HttpHeaders;
begin
- if not HttpContent.GetHeaders(Headers) then begin
- HttpContent.Clear();
- HttpContent.GetHeaders(Headers);
+ if not CurrHttpContentInstance.GetHeaders(ContentHeaders) then begin
+ CurrHttpContentInstance.Clear();
+ CurrHttpContentInstance.GetHeaders(ContentHeaders);
end;
- if Headers.Contains(Name) then
- Headers.Remove(Name);
+ if ContentHeaders.Contains(Name) or ContentHeaders.ContainsSecret(Name) then
+ ContentHeaders.Remove(Name);
- Headers.Add(Name, Value);
+ ContentHeaders.Add(Name, Value);
end;
procedure SetHeader(Name: Text; Value: SecretText)
var
- Headers: HttpHeaders;
+ ContentHeaders: HttpHeaders;
begin
- if not HttpContent.GetHeaders(Headers) then begin
- HttpContent.Clear();
- HttpContent.GetHeaders(Headers);
+ if not CurrHttpContentInstance.GetHeaders(ContentHeaders) then begin
+ CurrHttpContentInstance.Clear();
+ CurrHttpContentInstance.GetHeaders(ContentHeaders);
end;
- if Headers.Contains(Name) then
- Headers.Remove(Name);
+ if ContentHeaders.Contains(Name) or ContentHeaders.ContainsSecret(Name) then
+ ContentHeaders.Remove(Name);
- Headers.Add(Name, Value);
+ ContentHeaders.Add(Name, Value);
end;
procedure GetHttpContent() ReturnValue: HttpContent
begin
- ReturnValue := HttpContent;
+ ReturnValue := CurrHttpContentInstance;
end;
procedure AsText() ReturnValue: Text
begin
- HttpContent.ReadAs(ReturnValue);
+ CurrHttpContentInstance.ReadAs(ReturnValue);
end;
procedure AsSecretText() ReturnValue: SecretText
begin
- HttpContent.ReadAs(ReturnValue);
+ CurrHttpContentInstance.ReadAs(ReturnValue);
end;
procedure AsBlob() ReturnValue: Codeunit "Temp Blob"
@@ -89,14 +173,14 @@ codeunit 2355 "Http Content Impl."
InStr: InStream;
OutStr: OutStream;
begin
- HttpContent.ReadAs(InStr);
+ CurrHttpContentInstance.ReadAs(InStr);
ReturnValue.CreateOutStream(OutStr);
CopyStream(OutStr, InStr);
end;
procedure AsInStream(var InStr: InStream)
begin
- HttpContent.ReadAs(InStr);
+ CurrHttpContentInstance.ReadAs(InStr);
end;
procedure AsXmlDocument() ReturnValue: XmlDocument
@@ -104,7 +188,8 @@ codeunit 2355 "Http Content Impl."
XmlReadOptions: XmlReadOptions;
begin
XmlReadOptions.PreserveWhitespace(false);
- XmlDocument.ReadFrom(AsText(), XmlReadOptions, ReturnValue);
+ if not XmlDocument.ReadFrom(AsText(), XmlReadOptions, ReturnValue) then
+ ThrowInvalidXmlException();
end;
procedure AsJson() ReturnValue: JsonToken
@@ -112,14 +197,38 @@ codeunit 2355 "Http Content Impl."
Json: Text;
begin
Json := AsText();
- if Json <> '' then
- ReturnValue.ReadFrom(AsText());
+ if Json = '' then
+ exit;
+ if not ReturnValue.ReadFrom(Json) then
+ ThrowInvalidJsonException();
+ end;
+
+ procedure AsJsonObject() ReturnValue: JsonObject
+ var
+ Json: Text;
+ begin
+ Json := AsText();
+ if Json = '' then
+ exit;
+ if not ReturnValue.ReadFrom(Json) then
+ ThrowInvalidJsonException();
+ end;
+
+ procedure AsJsonArray() ReturnValue: JsonArray
+ var
+ Json: Text;
+ begin
+ Json := AsText();
+ if Json = '' then
+ exit;
+ if not ReturnValue.ReadFrom(Json) then
+ ThrowInvalidJsonException();
end;
procedure SetContent(Content: Text; ContentType: Text)
begin
- HttpContent.Clear();
- HttpContent.WriteFrom(Content);
+ CurrHttpContentInstance.Clear();
+ CurrHttpContentInstance.WriteFrom(Content);
if ContentType = '' then
ContentType := MimeTypeTextPlainTxt;
SetContentTypeHeader(ContentType);
@@ -127,8 +236,8 @@ codeunit 2355 "Http Content Impl."
procedure SetContent(Content: SecretText; ContentType: Text)
begin
- HttpContent.Clear();
- HttpContent.WriteFrom(Content);
+ CurrHttpContentInstance.Clear();
+ CurrHttpContentInstance.WriteFrom(Content);
if ContentType = '' then
ContentType := MimeTypeTextPlainTxt;
SetContentTypeHeader(ContentType);
@@ -136,8 +245,8 @@ codeunit 2355 "Http Content Impl."
procedure SetContent(Content: InStream; ContentType: Text)
begin
- HttpContent.Clear();
- HttpContent.WriteFrom(Content);
+ CurrHttpContentInstance.Clear();
+ CurrHttpContentInstance.WriteFrom(Content);
if ContentType = '' then
ContentType := MimeTypeApplicationOctetStreamTxt;
SetContentTypeHeader(ContentType);
@@ -173,6 +282,22 @@ codeunit 2355 "Http Content Impl."
procedure SetContent(var Value: HttpContent)
begin
- HttpContent := Value;
+ CurrHttpContentInstance := Value;
+ end;
+
+ local procedure ThrowInvalidJsonException()
+ var
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ InvalidJsonMessageTxt: Label 'The content is not a valid JSON.';
+ begin
+ Error(RestClientExceptionBuilder.CreateException(Enum::"Rest Client Exception"::InvalidJson, InvalidJsonMessageTxt));
+ end;
+
+ local procedure ThrowInvalidXmlException()
+ var
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ InvalidXmlMessageTxt: Label 'The content is not a valid XML.';
+ begin
+ Error(RestClientExceptionBuilder.CreateException(Enum::"Rest Client Exception"::InvalidXml, InvalidXmlMessageTxt));
end;
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/HttpRequestMessage.Codeunit.al b/src/System Application/App/Rest Client/src/HttpRequestMessage.Codeunit.al
index fe0fe9319b..9bbbf56dcc 100644
--- a/src/System Application/App/Rest Client/src/HttpRequestMessage.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/HttpRequestMessage.Codeunit.al
@@ -7,12 +7,23 @@ namespace System.RestClient;
/// Holder object for the HTTP request data.
codeunit 2352 "Http Request Message"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
var
HttpRequestMessageImpl: Codeunit "Http Request Message Impl.";
+ /// Creates a new instance of the HttpRequestMessage object.
+ /// The HTTP method to use. Valid options are GET, POST, PATCH, PUT, DELETE, HEAD, OPTIONS
+ /// The Uri to use for the HTTP request.
+ /// The Http Content object to use for the HTTP request.
+ /// The create Http Request Message
+ procedure Create(Method: Enum "Http Method"; RequestUri: Text; Content: Codeunit "Http Content") HttpRequestMessage: Codeunit "Http Request Message"
+ begin
+ HttpRequestMessageImpl := HttpRequestMessageImpl.Create(Method, RequestUri, Content);
+ HttpRequestMessage := this;
+ end;
/// Sets the HTTP method or the HttpRequestMessage object.
/// The HTTP method to use. Valid options are GET, POST, PATCH, PUT, DELETE, HEAD, OPTIONS
@@ -68,6 +79,79 @@ codeunit 2352 "Http Request Message"
HttpRequestMessageImpl.SetHeader(HeaderName, HeaderValue);
end;
+ /// Gets the values of the header with the given name from the HttpRequestMessage object.
+ /// The name of the header to get.
+ /// A list of values of the header with the given name.
+ /// If the header is not found, an empty list is returned.
+ procedure GetHeaderValues(HeaderName: Text) Values: List of [Text]
+ begin
+ Values := HttpRequestMessageImpl.GetHeaderValues(HeaderName);
+ end;
+
+ /// Gets the secret values of the header with the given name from the HttpRequestMessage object.
+ /// The name of the header to get.
+ /// A list of values of the header with the given name.
+ /// If the header is not found, an empty list is returned.
+ procedure GetSecretHeaderValues(HeaderName: Text) Values: List of [SecretText]
+ begin
+ Values := HttpRequestMessageImpl.GetSecretHeaderValues(HeaderName);
+ end;
+
+ /// Sets the cookie given a name and value
+ /// The name of the cookie to set.
+ /// The value of the cookie to set.
+ procedure SetCookie(Name: Text; Value: Text) Success: Boolean
+ begin
+ Success := HttpRequestMessageImpl.SetCookie(Name, Value);
+ end;
+
+ /// Sets the cookie given a cookie object
+ /// The cookie object to set.
+ procedure SetCookie(Cookie: Cookie) Success: Boolean
+ begin
+ Success := HttpRequestMessageImpl.SetCookie(Cookie);
+ end;
+
+ /// Gets the names of the cookies that are set in the HttpRequestMessage object.
+ /// The names of the cookies that are set in the HttpRequestMessage object.
+ procedure GetCookieNames() CookieNames: List of [Text]
+ begin
+ CookieNames := HttpRequestMessageImpl.GetCookieNames();
+ end;
+
+ /// Gets the cookies that are set in the HttpRequestMessage object.
+ /// The cookies that are set in the HttpRequestMessage object.
+ procedure GetCookies() Cookies: List of [Cookie]
+ begin
+ Cookies := HttpRequestMessageImpl.GetCookies();
+ end;
+
+ /// Gets the cookie with the given name from the HttpRequestMessage object.
+ /// The name of the cookie to get.
+ /// The cookie object.
+ /// If the cookie is not found, an empty cookie object is returned.
+ procedure GetCookie(Name: Text) ReturnValue: Cookie
+ begin
+ ReturnValue := HttpRequestMessageImpl.GetCookie(Name);
+ end;
+
+ /// Gets the cookie with the given name from the HttpRequestMessage object.
+ /// The name of the cookie to get.
+ /// The cookie object to get.
+ /// True if the cookie was found, false otherwise.
+ procedure GetCookie(Name: Text; var Cookie: Cookie) Success: Boolean
+ begin
+ Success := HttpRequestMessageImpl.GetCookie(Name, Cookie);
+ end;
+
+ /// Removes the cookie with the given name from the HttpRequestMessage object.
+ /// The name of the cookie to remove.
+ /// True if the cookie was removed, false otherwise.
+ procedure RemoveCookie(Name: Text) Success: Boolean
+ begin
+ Success := HttpRequestMessageImpl.RemoveCookie(Name);
+ end;
+
/// Sets the HttpRequestMessage that is represented by the HttpRequestMessage object.
/// The HttpRequestMessage to set.
procedure SetHttpRequestMessage(var RequestMessage: HttpRequestMessage)
diff --git a/src/System Application/App/Rest Client/src/HttpRequestMessageImpl.Codeunit.al b/src/System Application/App/Rest Client/src/HttpRequestMessageImpl.Codeunit.al
index e95a1f0907..6ac1c89795 100644
--- a/src/System Application/App/Rest Client/src/HttpRequestMessageImpl.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/HttpRequestMessageImpl.Codeunit.al
@@ -11,11 +11,20 @@ codeunit 2353 "Http Request Message Impl."
InherentPermissions = X;
var
- HttpRequestMessage: HttpRequestMessage;
+ CurrHttpRequestMessageInstance: HttpRequestMessage;
+
+ procedure Create(Method: Enum "Http Method"; RequestUri: Text; Content: Codeunit "Http Content"): Codeunit "Http Request Message Impl."
+ begin
+ ClearAll();
+ SetHttpMethod(Method);
+ SetRequestUri(RequestUri);
+ SetContent(Content);
+ exit(this);
+ end;
procedure SetHttpMethod(Method: Text)
begin
- HttpRequestMessage.Method := Method;
+ CurrHttpRequestMessageInstance.Method := Method;
end;
procedure SetHttpMethod(Method: Enum "Http Method")
@@ -25,51 +34,128 @@ codeunit 2353 "Http Request Message Impl."
procedure GetHttpMethod() ReturnValue: Text
begin
- ReturnValue := HttpRequestMessage.Method;
+ ReturnValue := CurrHttpRequestMessageInstance.Method;
end;
procedure SetRequestUri(Uri: Text)
begin
- HttpRequestMessage.SetRequestUri(Uri);
+ CurrHttpRequestMessageInstance.SetRequestUri(Uri);
end;
procedure GetRequestUri() Uri: Text
begin
- Uri := HttpRequestMessage.GetRequestUri();
+ Uri := CurrHttpRequestMessageInstance.GetRequestUri();
end;
procedure SetHeader(HeaderName: Text; HeaderValue: Text)
var
- HttpHeaders: HttpHeaders;
+ RequestHttpHeaders: HttpHeaders;
begin
- HttpRequestMessage.GetHeaders(HttpHeaders);
- if HttpHeaders.Contains(HeaderName) then
- HttpHeaders.Remove(HeaderName);
- HttpHeaders.Add(HeaderName, HeaderValue);
+ CurrHttpRequestMessageInstance.GetHeaders(RequestHttpHeaders);
+ if RequestHttpHeaders.Contains(HeaderName) or RequestHttpHeaders.ContainsSecret(HeaderName) then
+ RequestHttpHeaders.Remove(HeaderName);
+ RequestHttpHeaders.Add(HeaderName, HeaderValue);
end;
procedure SetHeader(HeaderName: Text; HeaderValue: SecretText)
var
- HttpHeaders: HttpHeaders;
+ RequestHttpHeaders: HttpHeaders;
+ begin
+ CurrHttpRequestMessageInstance.GetHeaders(RequestHttpHeaders);
+ if RequestHttpHeaders.Contains(HeaderName) or RequestHttpHeaders.ContainsSecret(HeaderName) then
+ RequestHttpHeaders.Remove(HeaderName);
+ RequestHttpHeaders.Add(HeaderName, HeaderValue);
+ end;
+
+ procedure GetHeaders() ReturnValue: HttpHeaders
+ begin
+ CurrHttpRequestMessageInstance.GetHeaders(ReturnValue);
+ end;
+
+ procedure GetHeaderValue(HeaderName: Text) Value: Text
+ var
+ RequestHttpHeaders: HttpHeaders;
+ Values: List of [Text];
+ begin
+ CurrHttpRequestMessageInstance.GetHeaders(RequestHttpHeaders);
+ if RequestHttpHeaders.Contains(HeaderName) then begin
+ RequestHttpHeaders.GetValues(HeaderName, Values);
+ if Values.Count > 0 then
+ Value := Values.Get(1);
+ end;
+ end;
+
+ procedure GetHeaderValues(HeaderName: Text) Values: List of [Text]
+ var
+ RequestHttpHeaders: HttpHeaders;
+ begin
+ CurrHttpRequestMessageInstance.GetHeaders(RequestHttpHeaders);
+ if RequestHttpHeaders.Contains(HeaderName) then
+ RequestHttpHeaders.GetValues(HeaderName, Values);
+ end;
+
+ procedure GetSecretHeaderValues(HeaderName: Text) Values: List of [SecretText]
+ var
+ RequestHttpHeaders: HttpHeaders;
+ begin
+ CurrHttpRequestMessageInstance.GetHeaders(RequestHttpHeaders);
+ if RequestHttpHeaders.ContainsSecret(HeaderName) then
+ RequestHttpHeaders.GetSecretValues(HeaderName, Values);
+ end;
+
+ procedure SetCookie(Name: Text; Value: Text) Success: Boolean
+ begin
+ Success := CurrHttpRequestMessageInstance.SetCookie(Name, Value);
+ end;
+
+ procedure SetCookie(TheCookie: Cookie) Success: Boolean
+ begin
+ Success := CurrHttpRequestMessageInstance.SetCookie(TheCookie);
+ end;
+
+ procedure GetCookieNames() CookieNames: List of [Text]
+ begin
+ CookieNames := CurrHttpRequestMessageInstance.GetCookieNames();
+ end;
+
+ procedure GetCookies() Cookies: List of [Cookie]
+ var
+ CookieName: Text;
+ TheCookie: Cookie;
+ begin
+ foreach CookieName in CurrHttpRequestMessageInstance.GetCookieNames() do begin
+ CurrHttpRequestMessageInstance.GetCookie(CookieName, TheCookie);
+ Cookies.Add(TheCookie);
+ end;
+ end;
+
+ procedure GetCookie(Name: Text) ReturnValue: Cookie
+ begin
+ if CurrHttpRequestMessageInstance.GetCookie(Name, ReturnValue) then;
+ end;
+
+ procedure GetCookie(Name: Text; var TheCookie: Cookie) Success: Boolean
+ begin
+ Success := CurrHttpRequestMessageInstance.GetCookie(Name, TheCookie);
+ end;
+
+ procedure RemoveCookie(Name: Text) Success: Boolean
begin
- HttpRequestMessage.GetHeaders(HttpHeaders);
- if HttpHeaders.Contains(HeaderName) then
- HttpHeaders.Remove(HeaderName);
- HttpHeaders.Add(HeaderName, HeaderValue);
+ Success := CurrHttpRequestMessageInstance.RemoveCookie(Name);
end;
procedure SetHttpRequestMessage(var RequestMessage: HttpRequestMessage)
begin
- HttpRequestMessage := RequestMessage;
+ CurrHttpRequestMessageInstance := RequestMessage;
end;
procedure SetContent(HttpContent: Codeunit "Http Content")
begin
- HttpRequestMessage.Content := HttpContent.GetHttpContent();
+ CurrHttpRequestMessageInstance.Content := HttpContent.GetHttpContent();
end;
procedure GetRequestMessage() ReturnValue: HttpRequestMessage
begin
- ReturnValue := HttpRequestMessage;
+ ReturnValue := CurrHttpRequestMessageInstance;
end;
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/HttpResponseMessage.Codeunit.al b/src/System Application/App/Rest Client/src/HttpResponseMessage.Codeunit.al
index d53e3ca94e..cdb1833173 100644
--- a/src/System Application/App/Rest Client/src/HttpResponseMessage.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/HttpResponseMessage.Codeunit.al
@@ -7,12 +7,24 @@ namespace System.RestClient;
/// Holder object for the HTTP response data.
codeunit 2356 "Http Response Message"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
var
HttpResponseMessageImpl: Codeunit "Http Response Message Impl.";
+ #region Constructors
+ /// Initializes a new instance of the HttpResponseMessage class.
+ /// The HTTP response message.
+ /// The HttpResponseMessage object.
+ procedure Create(HttpResponseMessage: HttpResponseMessage): Codeunit "Http Response Message"
+ begin
+ HttpResponseMessageImpl := HttpResponseMessageImpl.Create(HttpResponseMessage);
+ exit(this);
+ end;
+ #endregion
+
#region IsBlockedByEnvironment
/// Sets whether the request is blocked by the environment.
/// True if the request is blocked by the environment; otherwise, false.
@@ -127,6 +139,47 @@ codeunit 2356 "Http Response Message"
end;
#endregion
+ #region Cookies
+ /// Sets the cookies in the HTTP response message.
+ /// The cookies to set.
+ procedure SetCookies(Cookies: Dictionary of [Text, Cookie])
+ begin
+ HttpResponseMessageImpl.SetCookies(Cookies);
+ end;
+
+ /// Gets the cookies in the HTTP response message.
+ /// The cookies in the HTTP response message.
+ procedure GetCookies() ReturnValue: Dictionary of [Text, Cookie]
+ begin
+ ReturnValue := HttpResponseMessageImpl.GetCookies();
+ end;
+
+ /// Gets the names of the cookies that are set in the HTTP response message.
+ /// The names of the cookies that are set in the HTTP response message.
+ procedure GetCookieNames() ReturnValue: List of [Text]
+ begin
+ ReturnValue := HttpResponseMessageImpl.GetCookieNames();
+ end;
+
+ /// Gets the cookie with the given name from the HTTP response message.
+ /// The name of the cookie to get.
+ /// The cookie object.
+ /// If the cookie is not found, an empty cookie object is returned.
+ procedure GetCookie(Name: Text) ReturnValue: Cookie
+ begin
+ ReturnValue := HttpResponseMessageImpl.GetCookie(Name);
+ end;
+
+ /// Gets the cookie with the given name from the HTTP response message.
+ /// The name of the cookie to get.
+ /// The cookie object to get.
+ /// True if the cookie was found, false otherwise.
+ procedure GetCookie(Name: Text; var Cookie: Cookie) Success: Boolean
+ begin
+ Success := HttpResponseMessageImpl.GetCookie(Name, Cookie);
+ end;
+ #endregion
+
#region ErrorMessage
/// Sets an error message when the request failed.
/// The error message.
@@ -141,5 +194,19 @@ codeunit 2356 "Http Response Message"
begin
ReturnValue := HttpResponseMessageImpl.GetErrorMessage();
end;
+
+ /// Sets the exception information when the request failed.
+ /// The exception information.
+ procedure SetException(Exception: ErrorInfo)
+ begin
+ HttpResponseMessageImpl.SetException(Exception);
+ end;
+
+ /// Gets the exception information when the request failed.
+ /// The exception information.
+ procedure GetException() Exception: ErrorInfo
+ begin
+ Exception := HttpResponseMessageImpl.GetException();
+ end;
#endregion
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/HttpResponseMessageImpl.Codeunit.al b/src/System Application/App/Rest Client/src/HttpResponseMessageImpl.Codeunit.al
index 7355f0244d..c6117a53e1 100644
--- a/src/System Application/App/Rest Client/src/HttpResponseMessageImpl.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/HttpResponseMessageImpl.Codeunit.al
@@ -10,6 +10,14 @@ codeunit 2357 "Http Response Message Impl."
InherentEntitlements = X;
InherentPermissions = X;
+ #region Constructors
+ procedure Create(ResponseMessage: HttpResponseMessage): Codeunit "Http Response Message Impl."
+ begin
+ SetResponseMessage(ResponseMessage);
+ exit(this);
+ end;
+ #endregion
+
#region IsBlockedByEnvironment
var
IsBlockedByEnvironment: Boolean;
@@ -47,7 +55,7 @@ codeunit 2357 "Http Response Message Impl."
procedure GetIsSuccessStatusCode() Result: Boolean
begin
- Result := HttpResponseMessage.IsSuccessStatusCode;
+ Result := IsSuccessStatusCode;
end;
procedure SetIsSuccessStatusCode(Value: Boolean)
@@ -67,7 +75,7 @@ codeunit 2357 "Http Response Message Impl."
procedure GetReasonPhrase() ReturnValue: Text
begin
- ReturnValue := HttpResponseMessage.ReasonPhrase;
+ ReturnValue := ReasonPhrase;
end;
#endregion
@@ -88,55 +96,114 @@ codeunit 2357 "Http Response Message Impl."
#region HttpResponseMessage
var
- HttpResponseMessage: HttpResponseMessage;
+ CurrHttpResponseMessageInstance: HttpResponseMessage;
procedure SetResponseMessage(var ResponseMessage: HttpResponseMessage)
+ var
+ Cookie: Cookie;
+ Cookies: Dictionary of [Text, Cookie];
+ CookieName: Text;
begin
- HttpResponseMessage := ResponseMessage;
+ ClearAll();
+ CurrHttpResponseMessageInstance := ResponseMessage;
SetIsBlockedByEnvironment(ResponseMessage.IsBlockedByEnvironment);
SetHttpStatusCode(ResponseMessage.HttpStatusCode);
SetReasonPhrase(ResponseMessage.ReasonPhrase);
SetIsSuccessStatusCode(ResponseMessage.IsSuccessStatusCode);
SetHeaders(ResponseMessage.Headers);
SetContent(HttpContent.Create(ResponseMessage.Content));
+ foreach CookieName in ResponseMessage.GetCookieNames() do begin
+ ResponseMessage.GetCookie(CookieName, Cookie);
+ Cookies.Add(CookieName, Cookie);
+ end;
+ SetCookies(Cookies);
end;
procedure GetResponseMessage() ReturnValue: HttpResponseMessage
begin
- ReturnValue := HttpResponseMessage;
+ ReturnValue := CurrHttpResponseMessageInstance;
end;
#endregion
#region HttpHeaders
var
- HttpHeaders: HttpHeaders;
+ ResponseHttpHeaders: HttpHeaders;
procedure SetHeaders(Headers: HttpHeaders)
begin
- HttpHeaders := Headers;
+ ResponseHttpHeaders := Headers;
end;
procedure GetHeaders() ReturnValue: HttpHeaders
begin
- ReturnValue := HttpHeaders;
+ ReturnValue := ResponseHttpHeaders;
+ end;
+ #endregion
+
+ #region Cookies
+ var
+ GlobalCookies: Dictionary of [Text, Cookie];
+
+ procedure SetCookies(Cookies: Dictionary of [Text, Cookie])
+ begin
+ GlobalCookies := Cookies;
+ end;
+
+ procedure GetCookies() Cookies: Dictionary of [Text, Cookie]
+ begin
+ Cookies := GlobalCookies;
+ end;
+
+ procedure GetCookieNames() CookieNames: List of [Text]
+ begin
+ CookieNames := GlobalCookies.Keys;
+ end;
+
+ procedure GetCookie(Name: Text) TheCookie: Cookie
+ begin
+ if GlobalCookies.Get(Name, TheCookie) then;
+ end;
+
+ procedure GetCookie(Name: Text; var TheCookie: Cookie) Success: Boolean
+ begin
+ Success := GlobalCookies.Get(Name, TheCookie);
end;
#endregion
#region ErrorMessage
var
ErrorMessage: Text;
+ GlobalException: ErrorInfo;
procedure SetErrorMessage(Value: Text)
begin
ErrorMessage := Value;
end;
- procedure GetErrorMessage() ReturnValue: Text
+ procedure GetErrorMessage(): Text
begin
+ if GlobalException.Message <> '' then
+ exit(GlobalException.Message);
+
if ErrorMessage <> '' then
- ReturnValue := ErrorMessage
+ exit(ErrorMessage);
+
+ exit(GetLastErrorText());
+ end;
+
+ procedure SetException(Exception: ErrorInfo)
+ begin
+ GlobalException := Exception;
+ end;
+
+ procedure GetException() Exception: ErrorInfo
+ var
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ begin
+ if GlobalException.Message = '' then
+ Exception := RestClientExceptionBuilder.CreateException(Enum::"Rest Client Exception"::UnknownException, GetErrorMessage())
else
- ReturnValue := GetLastErrorText();
+ Exception := GlobalException;
end;
#endregion
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/RestClient.Codeunit.al b/src/System Application/App/Rest Client/src/RestClient.Codeunit.al
index fcc243cd50..5d7f69cb08 100644
--- a/src/System Application/App/Rest Client/src/RestClient.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/RestClient.Codeunit.al
@@ -7,12 +7,54 @@ namespace System.RestClient;
/// Provides functionality to easily work with the HttpClient object.
codeunit 2350 "Rest Client"
{
+ Access = Public;
InherentEntitlements = X;
InherentPermissions = X;
var
RestClientImpl: Codeunit "Rest Client Impl.";
+ #region Constructors
+ /// Initializes a new instance of the Rest Client class.
+ /// The Rest Client object.
+ /// The default Http Client Handler and anonymous Http authentication will be used.
+ procedure Create(): Codeunit "Rest Client"
+ begin
+ RestClientImpl := RestClientImpl.Create();
+ exit(this);
+ end;
+
+ /// Initializes a new instance of the Rest Client class.
+ /// The Http Client Handler to use.
+ /// The Rest Client object.
+ /// The anynomous Http Authentication will be used.
+ procedure Create(HttpClientHandler: Interface "Http Client Handler"): Codeunit "Rest Client"
+ begin
+ RestClientImpl := RestClientImpl.Create(HttpClientHandler);
+ exit(this);
+ end;
+
+ /// Initializes a new instance of the Rest Client class.
+ /// The authentication to use.
+ /// The Rest Client object.
+ /// The default Http Client Handler will be used.
+ procedure Create(HttpAuthentication: Interface "Http Authentication"): Codeunit "Rest Client"
+ begin
+ RestClientImpl := RestClientImpl.Create(HttpAuthentication);
+ exit(this);
+ end;
+
+ /// Initializes a new instance of the Rest Client class.
+ /// The Http Client Handler to use.
+ /// The authentication to use.
+ /// The Rest Client object.
+ procedure Create(HttpClientHandler: Interface "Http Client Handler"; HttpAuthentication: Interface "Http Authentication"): Codeunit "Rest Client"
+ begin
+ RestClientImpl := RestClientImpl.Create(HttpClientHandler, HttpAuthentication);
+ exit(this);
+ end;
+ #endregion
+
#region Initialization
/// Initializes the Rest Client with the default Http Client Handler and anonymous Http authentication.
procedure Initialize()
@@ -135,11 +177,21 @@ codeunit 2350 "Rest Client"
begin
RestClientImpl.SetAuthorizationHeader(Value);
end;
+
+ /// Sets the use of response cookies in subsequent requests.
+ /// Use this function to enable or disable automatically attach cookies received in the response to all subsequent requests.
+ /// The Rest Client will be initialized if it was not initialized before.
+ /// If true, the client automatically attaches cookies received in the response to all subsequent requests. False to disable
+ procedure SetUseResponseCookies(Value: Boolean)
+ begin
+ RestClientImpl.SetUseResponseCookies(Value);
+ end;
#endregion
#region BasicMethods
/// Sends a GET request to the specified Uri and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
+ /// If a response was received, then the response message object contains information about the status.
/// The Uri the request is sent to.
/// The response message object
procedure Get(RequestUri: Text) HttpResponseMessage: Codeunit "Http Response Message"
@@ -148,7 +200,7 @@ codeunit 2350 "Rest Client"
end;
/// Sends a POST request to the specified Uri and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
/// If a response was received, then the response message object contains information about the status.
/// The Uri the request is sent to.
/// The content to send.
@@ -159,7 +211,7 @@ codeunit 2350 "Rest Client"
end;
/// Sends a PATCH request to the specified Uri and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
/// If a response was received, then the response message object contains information about the status.
/// The Uri the request is sent to.
/// The content to send.
@@ -170,7 +222,7 @@ codeunit 2350 "Rest Client"
end;
/// Sends a PUT request to the specified Uri and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
/// If a response was received, then the response message object contains information about the status.
/// The Uri the request is sent to.
/// The content to send.
@@ -181,23 +233,22 @@ codeunit 2350 "Rest Client"
end;
/// Sends a DELETE request to the specified Uri and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
/// If a response was received, then the response message object contains information about the status.
/// The Uri the request is sent to.
/// The response message object
- procedure Delete(RequestUri: Text) HttpResponseMessage: Codeunit "Http Response Message";
+ procedure Delete(RequestUri: Text) HttpResponseMessage: Codeunit "Http Response Message"
begin
HttpResponseMessage := Send(Enum::"Http Method"::DELETE, RequestUri);
end;
-
#endregion
#region BasicMethodsAsJson
/// Sends a GET request to the specified Uri and returns the response content as JsonToken.
- /// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
- /// In case the response contains content, then the function fails if the content is invalid JSON.
+ /// In case the response contains content, then the function fails with a collectible error if the content is invalid JSON.
/// The Uri the request is sent to.
/// The response content as JsonToken
procedure GetAsJson(RequestUri: Text) JsonToken: JsonToken
@@ -207,7 +258,7 @@ codeunit 2350 "Rest Client"
/// Sends a POST request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -220,7 +271,7 @@ codeunit 2350 "Rest Client"
/// Sends a POST request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -233,7 +284,7 @@ codeunit 2350 "Rest Client"
/// Sends a POST request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -246,7 +297,7 @@ codeunit 2350 "Rest Client"
/// Sends a PATCH request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -259,7 +310,7 @@ codeunit 2350 "Rest Client"
/// Sends a PATCH request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -272,7 +323,7 @@ codeunit 2350 "Rest Client"
/// Sends a PATCH request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -285,7 +336,7 @@ codeunit 2350 "Rest Client"
/// Sends a PUT request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -298,7 +349,7 @@ codeunit 2350 "Rest Client"
/// Sends a PUT request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -311,7 +362,7 @@ codeunit 2350 "Rest Client"
/// Sends a PUT request to the specified Uri and returns the response content as JsonToken.
/// The function fails with an error message if the request could not be sent or a response was not received.
- /// The function also fails in case the response does not contain a success status code.
+ /// The function also fails with a collectible error in case the response does not contain a success status code.
/// In case the response contains no content, an empty JsonToken is returned.
/// In case the response contains content, then the function fails if the content is invalid JSON.
/// The Uri the request is sent to.
@@ -325,7 +376,7 @@ codeunit 2350 "Rest Client"
#region GenericSendMethods
/// Sends a request with the specific Http method and an empty content to the specified Uri and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
/// If a response was received, then the response message object contains information about the status.
/// The HTTP method to use.
/// The Uri the request is sent to.
@@ -336,7 +387,7 @@ codeunit 2350 "Rest Client"
end;
/// Sends a request with the specific Http method and the given content to the specified Uri and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
/// If a response was received, then the response message object contains information about the status.
/// The HTTP method to use.
/// The Uri the request is sent to.
@@ -348,12 +399,13 @@ codeunit 2350 "Rest Client"
end;
/// Sends the given request message and returns the response message.
- /// The function fails with an error message if the request could not be sent or a response was not received.
+ /// The function fails with a collectible error if the request could not be sent or a response was not received.
/// The request message to send.
/// The response message object
procedure Send(var HttpRequestMessage: Codeunit "Http Request Message") HttpResponseMessage: Codeunit "Http Response Message"
begin
HttpResponseMessage := RestClientImpl.Send(HttpRequestMessage);
end;
+
#endregion
}
\ No newline at end of file
diff --git a/src/System Application/App/Rest Client/src/RestClientImpl.Codeunit.al b/src/System Application/App/Rest Client/src/RestClientImpl.Codeunit.al
index c2c30f9498..6ba4f969ae 100644
--- a/src/System Application/App/Rest Client/src/RestClientImpl.Codeunit.al
+++ b/src/System Application/App/Rest Client/src/RestClientImpl.Codeunit.al
@@ -13,14 +13,39 @@ codeunit 2351 "Rest Client Impl."
var
DefaultHttpClientHandler: Codeunit "Http Client Handler";
HttpAuthenticationAnonymous: Codeunit "Http Authentication Anonymous";
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
HttpAuthentication: Interface "Http Authentication";
HttpClientHandler: Interface "Http Client Handler";
- HttpClient: HttpClient;
+ CurrHttpClientInstance: HttpClient;
IsInitialized: Boolean;
- EnvironmentBlocksErr: Label 'Environment blocks an outgoing HTTP request to ''%1''.', Comment = '%1 = url, e.g. https://microsoft.com';
- ConnectionErr: Label 'Connection to the remote service ''%1'' could not be established.', Comment = '%1 = url, e.g. https://microsoft.com';
- RequestFailedErr: Label 'The request failed: %1 %2', Comment = '%1 = HTTP status code, %2 = Reason phrase';
+ EnvironmentBlocksErr: Label 'The outgoing HTTP request to "%1" was blocked by the environment.', Comment = '%1 = url, e.g. https://microsoft.com';
+ ConnectionErr: Label 'Connection to the remote service "%1" could not be established.', Comment = '%1 = url, e.g. https://microsoft.com';
+ RequestFailedErr: Label 'The request to "%1" failed with status code %2 %3.', Comment = '%1 = url, %2 = HTTP status code, %3 = Reason phrase';
UserAgentLbl: Label 'Dynamics 365 Business Central - |%1| %2/%3', Locked = true, Comment = '%1 = App Publisher; %2 = App Name; %3 = App Version';
+ TimeoutOutOfRangeErr: Label 'The timeout value must be greater than 0.';
+
+ #region Constructors
+ procedure Create() RestClientImpl: Codeunit "Rest Client Impl."
+ begin
+ RestClientImpl := RestClientImpl.Create(DefaultHttpClientHandler, HttpAuthenticationAnonymous);
+ end;
+
+ procedure Create(HttpClientHandlerInstance: Interface "Http Client Handler") RestClientImpl: Codeunit "Rest Client Impl."
+ begin
+ RestClientImpl := RestClientImpl.Create(HttpClientHandlerInstance, HttpAuthenticationAnonymous);
+ end;
+
+ procedure Create(HttpAuthenticationInstance: Interface "Http Authentication") RestClientImpl: Codeunit "Rest Client Impl."
+ begin
+ RestClientImpl := RestClientImpl.Create(DefaultHttpClientHandler, HttpAuthenticationInstance);
+ end;
+
+ procedure Create(HttpClientHandlerInstance: Interface "Http Client Handler"; HttpAuthenticationInstance: Interface "Http Authentication"): Codeunit "Rest Client Impl."
+ begin
+ Initialize(HttpClientHandlerInstance, HttpAuthenticationInstance);
+ exit(this);
+ end;
+ #endregion
#region Initialization
procedure Initialize()
@@ -28,23 +53,21 @@ codeunit 2351 "Rest Client Impl."
Initialize(DefaultHttpClientHandler, HttpAuthenticationAnonymous);
end;
-#pragma warning disable AA0244
- procedure Initialize(HttpClientHandler: Interface "Http Client Handler")
+ procedure Initialize(HttpClientHandlerInstance: Interface "Http Client Handler")
begin
- Initialize(HttpClientHandler, HttpAuthenticationAnonymous);
+ Initialize(HttpClientHandlerInstance, HttpAuthenticationAnonymous);
end;
- procedure Initialize(HttpAuthentication: Interface "Http Authentication")
+ procedure Initialize(HttpAuthenticationInstance: Interface "Http Authentication")
begin
- Initialize(DefaultHttpClientHandler, HttpAuthentication);
+ Initialize(DefaultHttpClientHandler, HttpAuthenticationInstance);
end;
-#pragma warning restore AA0244
procedure Initialize(HttpClientHandlerInstance: Interface "Http Client Handler"; HttpAuthenticationInstance: Interface "Http Authentication")
begin
ClearAll();
- HttpClient.Clear();
+ CurrHttpClientInstance.Clear();
HttpClientHandler := HttpClientHandlerInstance;
HttpAuthentication := HttpAuthenticationInstance;
IsInitialized := true;
@@ -54,53 +77,55 @@ codeunit 2351 "Rest Client Impl."
procedure SetDefaultRequestHeader(Name: Text; Value: Text)
begin
CheckInitialized();
- if HttpClient.DefaultRequestHeaders.Contains(Name) then
- HttpClient.DefaultRequestHeaders.Remove(Name);
- HttpClient.DefaultRequestHeaders.Add(Name, Value);
+ if CurrHttpClientInstance.DefaultRequestHeaders.Contains(Name) then
+ CurrHttpClientInstance.DefaultRequestHeaders.Remove(Name);
+ CurrHttpClientInstance.DefaultRequestHeaders.Add(Name, Value);
end;
procedure SetDefaultRequestHeader(Name: Text; Value: SecretText)
begin
CheckInitialized();
- if HttpClient.DefaultRequestHeaders.Contains(Name) then
- HttpClient.DefaultRequestHeaders.Remove(Name);
- HttpClient.DefaultRequestHeaders.Add(Name, Value);
+ if CurrHttpClientInstance.DefaultRequestHeaders.Contains(Name) then
+ CurrHttpClientInstance.DefaultRequestHeaders.Remove(Name);
+ CurrHttpClientInstance.DefaultRequestHeaders.Add(Name, Value);
end;
procedure SetBaseAddress(Url: Text)
begin
CheckInitialized();
- HttpClient.SetBaseAddress(Url);
+ CurrHttpClientInstance.SetBaseAddress(Url);
end;
procedure GetBaseAddress() Url: Text
begin
CheckInitialized();
- Url := HttpClient.GetBaseAddress;
+ Url := CurrHttpClientInstance.GetBaseAddress;
end;
procedure SetTimeOut(TimeOut: Duration)
begin
CheckInitialized();
- HttpClient.Timeout := TimeOut;
+ if TimeOut <= 0 then
+ Error(TimeoutOutOfRangeErr);
+ CurrHttpClientInstance.Timeout := TimeOut;
end;
procedure GetTimeOut() TimeOut: Duration
begin
CheckInitialized();
- TimeOut := HttpClient.Timeout;
+ TimeOut := CurrHttpClientInstance.Timeout;
end;
procedure AddCertificate(Certificate: Text)
begin
CheckInitialized();
- HttpClient.AddCertificate(Certificate);
+ CurrHttpClientInstance.AddCertificate(Certificate);
end;
procedure AddCertificate(Certificate: Text; Password: SecretText)
begin
CheckInitialized();
- HttpClient.AddCertificate(Certificate, Password);
+ CurrHttpClientInstance.AddCertificate(Certificate, Password);
end;
procedure SetAuthorizationHeader(Value: SecretText)
@@ -112,8 +137,13 @@ codeunit 2351 "Rest Client Impl."
begin
SetDefaultRequestHeader('User-Agent', Value);
end;
- #endregion
+ procedure SetUseResponseCookies(Value: Boolean)
+ begin
+ CheckInitialized();
+ CurrHttpClientInstance.UseResponseCookies(Value);
+ end;
+ #endregion
#region BasicMethodsAsJson
procedure GetAsJson(RequestUri: Text) JsonToken: JsonToken
@@ -121,8 +151,16 @@ codeunit 2351 "Rest Client Impl."
HttpResponseMessage: Codeunit "Http Response Message";
begin
HttpResponseMessage := Send(Enum::"Http Method"::GET, RequestUri);
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
+
if not HttpResponseMessage.GetIsSuccessStatusCode() then
- Error(HttpResponseMessage.GetErrorMessage());
+ Error(HttpResponseMessage.GetException());
+
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
JsonToken := HttpResponseMessage.GetContent().AsJson();
end;
@@ -133,9 +171,16 @@ codeunit 2351 "Rest Client Impl."
HttpContent: Codeunit "Http Content";
begin
HttpResponseMessage := Send(Enum::"Http Method"::POST, RequestUri, HttpContent.Create(Content));
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
if not HttpResponseMessage.GetIsSuccessStatusCode() then
- Error(HttpResponseMessage.GetErrorMessage());
+ Error(HttpResponseMessage.GetException());
+
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
Response := HttpResponseMessage.GetContent().AsJson();
end;
@@ -146,9 +191,16 @@ codeunit 2351 "Rest Client Impl."
HttpContent: Codeunit "Http Content";
begin
HttpResponseMessage := Send(Enum::"Http Method"::PATCH, RequestUri, HttpContent.Create(Content));
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
if not HttpResponseMessage.GetIsSuccessStatusCode() then
- Error(HttpResponseMessage.GetErrorMessage());
+ Error(HttpResponseMessage.GetException());
+
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
Response := HttpResponseMessage.GetContent().AsJson();
end;
@@ -159,9 +211,16 @@ codeunit 2351 "Rest Client Impl."
HttpContent: Codeunit "Http Content";
begin
HttpResponseMessage := Send(Enum::"Http Method"::PUT, RequestUri, HttpContent.Create(Content));
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
if not HttpResponseMessage.GetIsSuccessStatusCode() then
- Error(HttpResponseMessage.GetErrorMessage());
+ Error(HttpResponseMessage.GetException());
+
+ if IsCollectingErrors() then
+ if HasCollectedErrors() then
+ exit;
Response := HttpResponseMessage.GetContent().AsJson();
end;
@@ -179,15 +238,7 @@ codeunit 2351 "Rest Client Impl."
var
HttpRequestMessage: Codeunit "Http Request Message";
begin
- CheckInitialized();
-
- HttpRequestMessage.SetHttpMethod(Method);
- if RequestUri.StartsWith('http://') or RequestUri.StartsWith('https://') then
- HttpRequestMessage.SetRequestUri(RequestUri)
- else
- HttpRequestMessage.SetRequestUri(GetBaseAddress() + RequestUri);
- HttpRequestMessage.SetContent(Content);
-
+ HttpRequestMessage := CreateHttpRequestMessage(Method, RequestUri, Content);
HttpResponseMessage := Send(HttpRequestMessage);
end;
@@ -196,8 +247,9 @@ codeunit 2351 "Rest Client Impl."
CheckInitialized();
if not SendRequest(HttpRequestMessage, HttpResponseMessage) then
- Error(HttpResponseMessage.GetErrorMessage());
+ Error(HttpResponseMessage.GetException());
end;
+
#endregion
#region Local Methods
@@ -218,27 +270,36 @@ codeunit 2351 "Rest Client Impl."
SetUserAgentHeader(UserAgentString);
end;
+ local procedure CreateHttpRequestMessage(Method: Enum "Http Method"; RequestUri: Text; Content: Codeunit "Http Content") HttpRequestMessage: Codeunit "Http Request Message"
+ begin
+ if not (RequestUri.StartsWith('http://') or RequestUri.StartsWith('https://')) then
+ RequestUri := GetBaseAddress() + RequestUri;
+ HttpRequestMessage := HttpRequestMessage.Create(Method, RequestUri, Content);
+ end;
+
local procedure SendRequest(var HttpRequestMessage: Codeunit "Http Request Message"; var HttpResponseMessage: Codeunit "Http Response Message"): Boolean
- var
- ErrorMessage: Text;
begin
Clear(HttpResponseMessage);
if HttpAuthentication.IsAuthenticationRequired() then
Authorize(HttpRequestMessage);
- if not HttpClientHandler.Send(HttpClient, HttpRequestMessage, HttpResponseMessage) then begin
+ if not HttpClientHandler.Send(CurrHttpClientInstance, HttpRequestMessage, HttpResponseMessage) then begin
if HttpResponseMessage.GetIsBlockedByEnvironment() then
- ErrorMessage := StrSubstNo(EnvironmentBlocksErr, HttpRequestMessage.GetRequestUri())
+ HttpResponseMessage.SetException(
+ RestClientExceptionBuilder.CreateException(Enum::"Rest Client Exception"::BlockedByEnvironment,
+ StrSubstNo(EnvironmentBlocksErr, HttpRequestMessage.GetRequestUri())))
else
- ErrorMessage := StrSubstNo(ConnectionErr, HttpRequestMessage.GetRequestUri());
+ HttpResponseMessage.SetException(
+ RestClientExceptionBuilder.CreateException(Enum::"Rest Client Exception"::ConnectionFailed,
+ StrSubstNo(ConnectionErr, HttpRequestMessage.GetRequestUri())));
exit(false);
end;
- if not HttpResponseMessage.GetIsSuccessStatusCode() then begin
- ErrorMessage := StrSubstNo(RequestFailedErr, HttpResponseMessage.GetHttpStatusCode(), HttpResponseMessage.GetReasonPhrase());
- HttpResponseMessage.SetErrorMessage(ErrorMessage);
- end;
+ if not HttpResponseMessage.GetIsSuccessStatusCode() then
+ HttpResponseMessage.SetException(
+ RestClientExceptionBuilder.CreateException(Enum::"Rest Client Exception"::RequestFailed,
+ StrSubstNo(RequestFailedErr, HttpRequestMessage.GetRequestUri(), HttpResponseMessage.GetHttpStatusCode(), HttpResponseMessage.GetReasonPhrase())));
exit(true);
end;
diff --git a/src/System Application/Test/DisabledTests/RestClientTests.DisabledTest.json b/src/System Application/Test/DisabledTests/RestClientTests.DisabledTest.json
new file mode 100644
index 0000000000..6c38dccb1f
--- /dev/null
+++ b/src/System Application/Test/DisabledTests/RestClientTests.DisabledTest.json
@@ -0,0 +1,32 @@
+[
+ {
+ "bug": "524800",
+ "codeunitId": 134971,
+ "codeunitName": "Rest Client Tests",
+ "method": "TestResponseWithCookies"
+ },
+ {
+ "bug": "524800",
+ "codeunitId": 134971,
+ "codeunitName": "Rest Client Tests",
+ "method": "TestRequestWithCookies"
+ },
+ {
+ "bug": "524800",
+ "codeunitId": 134971,
+ "codeunitName": "Rest Client Tests",
+ "method": "TestWithoutUseResponseCookies"
+ },
+ {
+ "bug": "524800",
+ "codeunitId": 134971,
+ "codeunitName": "Rest Client Tests",
+ "method": "TestWithUseResponseCookies"
+ },
+ {
+ "bug": "524800",
+ "codeunitId": 134971,
+ "codeunitName": "Rest Client Tests",
+ "method": "TestUseResponseCookiesWithAdditionalCookies"
+ }
+]
\ No newline at end of file
diff --git a/src/System Application/Test/Rest Client/app.json b/src/System Application/Test/Rest Client/app.json
index 2d14cf6c3f..d6ad2f8ba4 100644
--- a/src/System Application/Test/Rest Client/app.json
+++ b/src/System Application/Test/Rest Client/app.json
@@ -35,7 +35,7 @@
"idRanges": [
{
"from": 134970,
- "to": 134974
+ "to": 134977
}
],
"resourceExposurePolicy": {
diff --git a/src/System Application/Test/Rest Client/src/HttpAuthenticationTests.Codeunit.al b/src/System Application/Test/Rest Client/src/HttpAuthenticationTests.Codeunit.al
index 48834ba82e..4568b0ef9a 100644
--- a/src/System Application/Test/Rest Client/src/HttpAuthenticationTests.Codeunit.al
+++ b/src/System Application/Test/Rest Client/src/HttpAuthenticationTests.Codeunit.al
@@ -28,7 +28,7 @@ codeunit 134973 "Http Authentication Tests"
// [WHEN] The authentication object is asked to return the authorization header
// [THEN] The authentication object should return an empty list
- Assert.AreEqual(HttpAuthenticationAnonymous.GetAuthorizationHeaders().Count, 0, 'Anonymous authentication should not return an authorization header');
+ Assert.AreEqual(0, HttpAuthenticationAnonymous.GetAuthorizationHeaders().Count, 'Anonymous authentication should not return an authorization header');
end;
[NonDebuggable]
@@ -49,10 +49,10 @@ codeunit 134973 "Http Authentication Tests"
// [WHEN] The authentication object is asked to return the authorization header
// [THEN] THe authentication object should return a dictionary with one element that is a base64 encoded string
AuthHeader := HttpAuthenticationBasic.GetAuthorizationHeaders();
- Assert.AreEqual(AuthHeader.Count, 1, 'Basic authentication should return one authorization header');
- Assert.AreEqual(AuthHeader.ContainsKey('Authorization'), true, 'Basic authentication should return an authorization header');
+ Assert.AreEqual(1, AuthHeader.Count, 'Basic authentication should return one authorization header');
+ Assert.AreEqual(true, AuthHeader.ContainsKey('Authorization'), 'Basic authentication should return an authorization header');
BasicAuthHeaderValue := AuthHeader.Get('Authorization');
- Assert.AreEqual(BasicAuthHeaderValue.Unwrap(), 'Basic VVNFUjAxOlBhc3N3b3JkMTIzIQ==', 'Basic authentication should return a base64 encoded string');
+ Assert.AreEqual('Basic VVNFUjAxOlBhc3N3b3JkMTIzIQ==', BasicAuthHeaderValue.Unwrap(), 'Basic authentication should return a base64 encoded string');
end;
}
\ No newline at end of file
diff --git a/src/System Application/Test/Rest Client/src/HttpExceptionTests.Codeunit.al b/src/System Application/Test/Rest Client/src/HttpExceptionTests.Codeunit.al
new file mode 100644
index 0000000000..5a9d00379b
--- /dev/null
+++ b/src/System Application/Test/Rest Client/src/HttpExceptionTests.Codeunit.al
@@ -0,0 +1,290 @@
+// ------------------------------------------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+// ------------------------------------------------------------------------------------------------
+
+namespace System.Test.RestClient;
+
+using System.RestClient;
+using System.TestLibraries.Utilities;
+
+codeunit 134977 "Http Exception Tests"
+{
+ Subtype = Test;
+
+ var
+ Assert: Codeunit "Library Assert";
+ HttpClientHandler: Codeunit "Test Http Client Handler";
+
+ [Test]
+ procedure TestConnectionFailed()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ begin
+ // [SCENARIO] Error is raised when the connection fails
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.SetMockConnectionFailed();
+ RestClient := RestClient.Create(HttpClientHandler);
+
+ // [WHEN] Sending a request
+ asserterror HttpResponseMessage := RestClient.Get('http://www.example.com');
+
+ // [THEN] RestClient returns an error
+ Assert.ExpectedError('Connection to the remote service "http://www.example.com/" could not be established.');
+ end;
+
+ [Test]
+ [ErrorBehavior(ErrorBehavior::Collect)]
+ procedure TestConnectionFailedWithErrorCollection()
+ var
+ RestClient: Codeunit "Rest Client";
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ Exceptions: List of [ErrorInfo];
+ Exception: ErrorInfo;
+ RestClientException: Enum "Rest Client Exception";
+ begin
+ // [SCENARIO] Error is raised when the connection fails
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.SetMockConnectionFailed();
+ RestClient := RestClient.Create(HttpClientHandler);
+
+ // [WHEN] Sending a request
+ HttpResponseMessage := RestClient.Get('http://www.example.com');
+
+ // [THEN] RestClient returns one collectible error of type ConnectionFailed
+ Assert.IsTrue(HasCollectedErrors(), 'No collectible error was returned');
+ Exceptions := GetCollectedErrors(true);
+ Assert.AreEqual(1, Exceptions.Count, 'There should be 1 exception');
+
+ Exception := Exceptions.Get(1);
+ RestClientException := RestClientExceptionBuilder.GetRestClientException(Exception);
+ Assert.AreEqual(Enum::"Rest Client Exception"::ConnectionFailed, RestClientException, 'The exception should be of type ConnectionFailed');
+ Assert.AreEqual('ConnectionFailed', Exception.CustomDimensions.Get('ExceptionName'), 'The exception name should be "ConnectionFailed"');
+ Assert.AreEqual('Connection to the remote service "http://www.example.com/" could not be established.', Exception.Message, 'The error message is incorrect');
+ end;
+
+ [Test]
+ procedure TestBlockedByEnvironment()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ begin
+ // [SCENARIO] Error is raised when the request is blocked by the environment
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.SetMockIsBlockedByEnvironment();
+ RestClient := RestClient.Create(HttpClientHandler);
+
+ // [WHEN] Sending a request
+ asserterror HttpResponseMessage := RestClient.Get('http://www.example.com');
+
+ // [THEN] RestClient returns an error
+ Assert.ExpectedError('The outgoing HTTP request to "http://www.example.com/" was blocked by the environment.');
+ end;
+
+ [Test]
+ [ErrorBehavior(ErrorBehavior::Collect)]
+ procedure TestBlockedByEnvironmentWithErrorCollection()
+ var
+ RestClient: Codeunit "Rest Client";
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ Exceptions: List of [ErrorInfo];
+ Exception: ErrorInfo;
+ RestClientException: Enum "Rest Client Exception";
+ begin
+ // [SCENARIO] Error is raised when the request is blocked by the environment
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.SetMockIsBlockedByEnvironment();
+ RestClient := RestClient.Create(HttpClientHandler);
+
+ // [WHEN] Sending a request
+ HttpResponseMessage := RestClient.Get('http://www.example.com');
+
+ // [THEN] RestClient returns one collectible error of type BlockedByEnvironment
+ Assert.IsTrue(HasCollectedErrors(), 'No collectible error was returned');
+ Exceptions := GetCollectedErrors(true);
+ Assert.AreEqual(1, Exceptions.Count, 'There should be 1 exception');
+
+ Exception := Exceptions.Get(1);
+ RestClientException := RestClientExceptionBuilder.GetRestClientException(Exception);
+ Assert.AreEqual(Enum::"Rest Client Exception"::BlockedByEnvironment, RestClientException, 'The exception should be of type BlockedByEnvironment');
+ Assert.AreEqual('BlockedByEnvironment', Exception.CustomDimensions.Get('ExceptionName'), 'The exception name should be "BlockedByEnvironment"');
+ Assert.AreEqual('The outgoing HTTP request to "http://www.example.com/" was blocked by the environment.', Exception.Message, 'The error message is incorrect');
+ end;
+
+ [Test]
+ procedure TestRequestFailedOnGenericMethod()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ begin
+ // [SCENARIO] Error is raised when the request fails
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.SetMockRequestFailed();
+ RestClient := RestClient.Create(HttpClientHandler);
+
+ // [WHEN] Sending a request
+ HttpResponseMessage := RestClient.Get('http://www.example.com');
+
+ // [THEN] HttpResponseMessage contains an error
+ Assert.IsFalse(HttpResponseMessage.GetIsSuccessStatusCode(), 'The request should not be successful');
+ asserterror Error(HttpResponseMessage.GetException());
+ Assert.ExpectedError('The request to "http://www.example.com/" failed with status code 400 Bad Request.');
+ end;
+
+ [Test]
+ procedure TestRequestFailedOnTypedMethod()
+ var
+ RestClient: Codeunit "Rest Client";
+ JsonToken: JsonToken;
+ begin
+ // [SCENARIO] Error is raised when the request fails
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.SetMockRequestFailed();
+ RestClient := RestClient.Create(HttpClientHandler);
+
+ // [WHEN] Sending a request
+ asserterror JsonToken := RestClient.GetAsJson('http://www.example.com');
+
+ // [THEN] HttpResponseMessage contains an error
+ Assert.ExpectedError('The request to "http://www.example.com/" failed with status code 400 Bad Request.');
+ end;
+
+ [Test]
+ [ErrorBehavior(ErrorBehavior::Collect)]
+ procedure TestRequestFailedWithErrorCollection()
+ var
+ RestClient: Codeunit "Rest Client";
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ JsonToken: JsonToken;
+ Exceptions: List of [ErrorInfo];
+ Exception: ErrorInfo;
+ RestClientException: Enum "Rest Client Exception";
+ begin
+ // [SCENARIO] Error is raised when the request fails
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.SetMockRequestFailed();
+ RestClient := RestClient.Create(HttpClientHandler);
+
+ // [WHEN] Sending a request
+ JsonToken := RestClient.GetAsJson('http://www.example.com');
+
+ // [THEN] RestClient returns one collectible error of type RequestFailed
+ Assert.IsTrue(HasCollectedErrors(), 'No collectible error was returned');
+ Exceptions := GetCollectedErrors(true);
+ Assert.AreEqual(1, Exceptions.Count, 'There should be 1 exception');
+
+ Exception := Exceptions.Get(1);
+ RestClientException := RestClientExceptionBuilder.GetRestClientException(Exception);
+ Assert.AreEqual(Enum::"Rest Client Exception"::RequestFailed, RestClientException, 'The exception should be of type RequestFailed');
+ Assert.AreEqual('RequestFailed', Exception.CustomDimensions.Get('ExceptionName'), 'The exception name should be "RequestFailed"');
+ Assert.AreEqual('The request to "http://www.example.com/" failed with status code 400 Bad Request.', Exception.Message, 'The error message is incorrect');
+ end;
+
+ [Test]
+ procedure TestInvalidJson()
+ var
+ HttpContent: Codeunit "Http Content";
+ JsonToken: JsonToken;
+ begin
+ // [SCENARIO] Error is raised when trying to read as JSON from a HttpContent object with invalid JSON
+
+ // [GIVEN] HttpContent object with invalid JSON
+ HttpContent := HttpContent.Create('{"key": "value"');
+
+ // [WHEN] Trying to read as JSON
+ asserterror JsonToken := HttpContent.AsJson();
+
+ // [THEN] HttpContent returns an error
+ Assert.ExpectedError('The content is not a valid JSON.');
+ end;
+
+ [Test]
+ [ErrorBehavior(ErrorBehavior::Collect)]
+ procedure TestInvalidJsonWithErrorCollection()
+ var
+ HttpContent: Codeunit "Http Content";
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ JsonToken: JsonToken;
+ Exceptions: List of [ErrorInfo];
+ Exception: ErrorInfo;
+ RestClientException: Enum "Rest Client Exception";
+ begin
+ // [SCENARIO] Error is raised when trying to read as JSON from a HttpContent object with invalid JSON
+
+ // [GIVEN] HttpContent object with invalid JSON
+ HttpContent := HttpContent.Create('{"key": "value"');
+
+ // [WHEN] Trying to read as JSON
+ JsonToken := HttpContent.AsJson();
+
+ // [THEN] HttpContent returns one collectible error of type InvalidJson
+ Assert.IsTrue(HasCollectedErrors(), 'No collectible error was returned');
+ Exceptions := GetCollectedErrors(true);
+ Assert.AreEqual(1, Exceptions.Count, 'There should be 1 exception');
+
+ Exception := Exceptions.Get(1);
+ RestClientException := RestClientExceptionBuilder.GetRestClientException(Exception);
+ Assert.AreEqual(Enum::"Rest Client Exception"::InvalidJson, RestClientException, 'The exception should be of type InvalidJson');
+ Assert.AreEqual('InvalidJson', Exception.CustomDimensions.Get('ExceptionName'), 'The exception name should be "InvalidJson"');
+ Assert.AreEqual('The content is not a valid JSON.', Exception.Message, 'The message should be "The content is not a valid JSON."');
+ end;
+
+ [Test]
+ procedure TestInvalidXml()
+ var
+ HttpContent: Codeunit "Http Content";
+ XmlDocument: XmlDocument;
+ begin
+ // [SCENARIO] Error is raised when trying to read as XML from a HttpContent object with invalid XML
+
+ // [GIVEN] HttpContent object with invalid XML
+ HttpContent := HttpContent.Create('');
+
+ // [WHEN] Trying to read as XML
+ asserterror XmlDocument := HttpContent.AsXmlDocument();
+
+ // [THEN] HttpContent returns an error
+ Assert.ExpectedError('The content is not a valid XML.');
+ end;
+
+ [Test]
+ [ErrorBehavior(ErrorBehavior::Collect)]
+ procedure TestInvalidXmlWithErrorCollection()
+ var
+ HttpContent: Codeunit "Http Content";
+ RestClientExceptionBuilder: Codeunit "Rest Client Exception Builder";
+ XmlDocument: XmlDocument;
+ Exceptions: List of [ErrorInfo];
+ Exception: ErrorInfo;
+ RestClientException: Enum "Rest Client Exception";
+ begin
+ // [SCENARIO] Error is raised when trying to read as XML from a HttpContent object with invalid XML
+
+ // [GIVEN] HttpContent object with invalid XML
+ HttpContent := HttpContent.Create('');
+
+ // [WHEN] Trying to read as XML
+ XmlDocument := HttpContent.AsXmlDocument();
+
+ // [THEN] HttpContent returns one collectible error of type InvalidXml
+ Assert.IsTrue(HasCollectedErrors(), 'No collectible error was returned');
+ Exceptions := GetCollectedErrors(true);
+ Assert.AreEqual(1, Exceptions.Count, 'There should be 1 exception');
+
+ Exception := Exceptions.Get(1);
+ RestClientException := RestClientExceptionBuilder.GetRestClientException(Exception);
+ Assert.AreEqual(Enum::"Rest Client Exception"::InvalidXml, RestClientException, 'The exception should be of type InvalidXml');
+ Assert.AreEqual('InvalidXml', Exception.CustomDimensions.Get('ExceptionName'), 'The exception name should be "InvalidXml"');
+ Assert.AreEqual('The content is not a valid XML.', Exception.Message, 'The message should be "The content is not a valid XML."');
+ end;
+}
\ No newline at end of file
diff --git a/src/System Application/Test/Rest Client/src/RequestMessageTests.Codeunit.al b/src/System Application/Test/Rest Client/src/RequestMessageTests.Codeunit.al
index 10d54896a4..48b82fabc7 100644
--- a/src/System Application/Test/Rest Client/src/RequestMessageTests.Codeunit.al
+++ b/src/System Application/Test/Rest Client/src/RequestMessageTests.Codeunit.al
@@ -30,7 +30,7 @@ codeunit 134972 "Request Message Tests"
HttpRequestMessage := ALHttpRequestMessage.GetHttpRequestMessage();
// [THEN] The request message is initialized correctly
- Assert.AreEqual(HttpRequestMessage.Method(), 'PATCH', 'The request message method is not correct.');
+ Assert.AreEqual('PATCH', HttpRequestMessage.Method(), 'The request message method is not correct.');
end;
[Test]
@@ -49,8 +49,8 @@ codeunit 134972 "Request Message Tests"
HttpRequestMessage := ALHttpRequestMessage.GetHttpRequestMessage();
// [THEN] The request message is initialized correctly
- Assert.AreEqual(HttpRequestMessage.Method(), 'GET', 'The request message method is not correct.');
- Assert.AreEqual(HttpRequestMessage.GetRequestUri(), 'https://www.microsoft.com/', 'The request message request URI is not correct.');
+ Assert.AreEqual('GET', HttpRequestMessage.Method(), 'The request message method is not correct.');
+ Assert.AreEqual('https://www.microsoft.com/', HttpRequestMessage.GetRequestUri(), 'The request message request URI is not correct.');
end;
[Test]
@@ -74,17 +74,17 @@ codeunit 134972 "Request Message Tests"
HttpRequestMessage := ALHttpRequestMessage.GetHttpRequestMessage();
// [THEN] The request message is initialized correctly
- Assert.AreEqual(HttpRequestMessage.Method(), 'POST', 'The request message method is not correct.');
- Assert.AreEqual(HttpRequestMessage.GetRequestUri(), 'https://www.microsoft.com/', 'The request message request URI is not correct.');
+ Assert.AreEqual('POST', HttpRequestMessage.Method(), 'The request message method is not correct.');
+ Assert.AreEqual('https://www.microsoft.com/', HttpRequestMessage.GetRequestUri(), 'The request message request URI is not correct.');
HttpRequestMessage.Content().ReadAs(ContentText);
- Assert.AreEqual(ContentText, 'Hello World!', 'The request message content is not correct.');
+ Assert.AreEqual('Hello World!', ContentText, 'The request message content is not correct.');
HttpRequestMessage.Content.GetHeaders(ContentHeaders);
- Assert.AreEqual(ContentHeaders.Contains('Content-Type'), true, 'The content type header is missing.');
+ Assert.AreEqual(true, ContentHeaders.Contains('Content-Type'), 'The content type header is missing.');
ContentHeaders.GetValues('Content-Type', ContentHeaderValues);
- Assert.AreEqual(ContentHeaderValues.Get(1), 'text/plain', 'The request message content type is not correct.');
+ Assert.AreEqual('text/plain', ContentHeaderValues.Get(1), 'The request message content type is not correct.');
end;
[Test]
@@ -110,19 +110,19 @@ codeunit 134972 "Request Message Tests"
HttpRequestMessage := ALHttpRequestMessage.GetHttpRequestMessage();
// [THEN] The request message is initialized correctly
- Assert.AreEqual(HttpRequestMessage.Method(), 'POST', 'The request message method is not correct.');
- Assert.AreEqual(HttpRequestMessage.GetRequestUri(), 'https://www.microsoft.com/', 'The request message request URI is not correct.');
+ Assert.AreEqual('POST', HttpRequestMessage.Method(), 'The request message method is not correct.');
+ Assert.AreEqual('https://www.microsoft.com/', HttpRequestMessage.GetRequestUri(), 'The request message request URI is not correct.');
HttpRequestMessage.Content().ReadAs(ContentText);
- Assert.AreEqual(ContentJson.ReadFrom(ContentText), true, 'The request message content is not a valid JSON object.');
- Assert.AreEqual(ContentJson.Contains('value'), true, 'The request message content does not contain the expected property "value".');
- Assert.AreEqual(GetJsonToken(ContentJson, 'value').AsValue().AsText(), 'Hello World!', 'The request message content property "value" is not correct.');
+ Assert.AreEqual(true, ContentJson.ReadFrom(ContentText), 'The request message content is not a valid JSON object.');
+ Assert.AreEqual(true, ContentJson.Contains('value'), 'The request message content does not contain the expected property "value".');
+ Assert.AreEqual('Hello World!', GetJsonToken(ContentJson, 'value').AsValue().AsText(), 'The request message content property "value" is not correct.');
HttpRequestMessage.Content.GetHeaders(ContentHeaders);
- Assert.AreEqual(ContentHeaders.Contains('Content-Type'), true, 'The content type header is missing.');
+ Assert.AreEqual(true, ContentHeaders.Contains('Content-Type'), 'The content type header is missing.');
ContentHeaders.GetValues('Content-Type', ContentHeaderValues);
- Assert.AreEqual(ContentHeaderValues.Get(1), 'application/json', 'The request message content type is not correct.');
+ Assert.AreEqual('application/json', ContentHeaderValues.Get(1), 'The request message content type is not correct.');
end;
[Test]
@@ -145,12 +145,86 @@ codeunit 134972 "Request Message Tests"
// [THEN] The request message is initialized correctly
HttpRequestMessage.GetHeaders(ContentHeaders);
- Assert.AreEqual(ContentHeaders.Contains('X-Custom-Header'), true, 'The custom header is missing.');
+ Assert.IsTrue(ContentHeaders.Contains('X-Custom-Header'), 'The custom header is missing.');
ContentHeaders.GetValues('X-Custom-Header', ContentHeaderValues);
- Assert.AreEqual(ContentHeaderValues.Get(1), 'My Request Header', 'The custom header value is not correct.');
+ Assert.AreEqual('My Request Header', ContentHeaderValues.Get(1), 'The custom header value is not correct.');
end;
+ [Test]
+ [NonDebuggable]
+ procedure TestAddSecretRequestHeader()
+ var
+ ALHttpRequestMessage: Codeunit "Http Request Message";
+ HttpRequestMessage: HttpRequestMessage;
+ ContentHeaders: HttpHeaders;
+ SecretHeaderText: SecretText;
+ ContentHeaderValues: List of [SecretText];
+ begin
+ // [GIVEN] An initialized Http Request Message
+ ALHttpRequestMessage.SetHttpMethod('GET');
+ ALHttpRequestMessage.SetRequestUri('https://www.microsoft.com/');
+
+ // [GIVEN] The request message has a secret header
+ SecretHeaderText := SecretStrSubstNo('My Secret Request Header');
+ ALHttpRequestMessage.SetHeader('X-Secret-Header', SecretHeaderText);
+
+ // [WHEN] The request message is read
+ HttpRequestMessage := ALHttpRequestMessage.GetHttpRequestMessage();
+
+ // [THEN] The request message is initialized correctly
+ HttpRequestMessage.GetHeaders(ContentHeaders);
+ Assert.IsTrue(ContentHeaders.ContainsSecret('X-Secret-Header'), 'The secret header is missing.');
+
+ ContentHeaders.GetSecretValues('X-Secret-Header', ContentHeaderValues);
+ Assert.AreEqual(SecretHeaderText.Unwrap(), ContentHeaderValues.Get(1).Unwrap(), 'The secret header value is not correct.');
+ end;
+
+ [Test]
+ procedure TestAddCookie()
+ var
+ ALHttpRequestMessage: Codeunit "Http Request Message";
+ HttpRequestMessage: HttpRequestMessage;
+ RequestCookie: Cookie;
+ begin
+ // [GIVEN] An initialized Http Request Message
+ ALHttpRequestMessage.SetHttpMethod('GET');
+ ALHttpRequestMessage.SetRequestUri('https://www.microsoft.com/');
+
+ // [GIVEN] The request message has a cookie
+ ALHttpRequestMessage.SetCookie('MyCookie', 'MyCookieValue');
+
+ // [WHEN] The request message is read
+ HttpRequestMessage := ALHttpRequestMessage.GetHttpRequestMessage();
+
+ // [THEN] The request message is initialized correctly
+ Assert.IsTrue(HttpRequestMessage.GetCookie('MyCookie', RequestCookie), 'The cookie is missing.');
+ Assert.AreEqual('MyCookieValue', RequestCookie.Value(), 'The cookie value is not correct.');
+ end;
+
+ [Test]
+ procedure TestRemoveCookie()
+ var
+ ALHttpRequestMessage: Codeunit "Http Request Message";
+ HttpRequestMessage: HttpRequestMessage;
+ RequestCookie: Cookie;
+ begin
+ // [GIVEN] An initialized Http Request Message
+ ALHttpRequestMessage.SetHttpMethod('GET');
+ ALHttpRequestMessage.SetRequestUri('https://www.microsoft.com/');
+
+ // [GIVEN] The request message has a cookie
+ ALHttpRequestMessage.SetCookie('MyCookie', 'MyCookieValue');
+ ALHttpRequestMessage.RemoveCookie('MyCookie');
+
+ // [WHEN] The request message is read
+ HttpRequestMessage := ALHttpRequestMessage.GetHttpRequestMessage();
+
+ // [THEN] The request message is initialized correctly
+ Assert.IsFalse(HttpRequestMessage.GetCookie('MyCookie', RequestCookie), 'The cookie is not removed.');
+ end;
+
+
local procedure GetJsonToken(JsonObject: JsonObject; Name: Text) JsonToken: JsonToken
begin
JsonObject.Get(Name, JsonToken);
diff --git a/src/System Application/Test/Rest Client/src/RestClientTests.Codeunit.al b/src/System Application/Test/Rest Client/src/RestClientTests.Codeunit.al
index a29dde8c92..96d5048d86 100644
--- a/src/System Application/Test/Rest Client/src/RestClientTests.Codeunit.al
+++ b/src/System Application/Test/Rest Client/src/RestClientTests.Codeunit.al
@@ -25,17 +25,42 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test GET request
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Get method is called
HttpResponseMessage := RestClient.Get('https://httpbin.org/get');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/get', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/get', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
+ end;
+
+ [Test]
+ procedure TestGetWithQueryParameters()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ JsonObject: JsonObject;
+ begin
+ // [SCENARIO] Test GET request with query parameters
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
+ RestClient.Initialize(HttpClientHandler);
+
+ // [WHEN] The Get method is called with query parameters
+ HttpResponseMessage := RestClient.Get('https://httpbin.org/get?param1=value1¶m2=value2');
+
+ // [THEN] The response contains the expected data
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
+ Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
+ JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
+ Assert.AreEqual('value1', SelectJsonToken(JsonObject, '$.args.param1').AsValue().AsText(), 'The response should contain the expected query parameter');
+ Assert.AreEqual('value2', SelectJsonToken(JsonObject, '$.args.param2').AsValue().AsText(), 'The response should contain the expected query parameter');
end;
[Test]
@@ -48,18 +73,19 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test POST request
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Post method is called
HttpResponseMessage := RestClient.Post('https://httpbin.org/post', HttpGetContent.Create('Hello World'));
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/post', 'The response should contain the expected url');
- Assert.AreEqual(GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'Hello World', 'The response should contain the expected data');
+ Assert.AreEqual('https://httpbin.org/post', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
+ Assert.AreEqual('Hello World', GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'The response should contain the expected data');
end;
[Test]
@@ -72,18 +98,19 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test PATCH request
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Patch method is called
HttpResponseMessage := RestClient.Patch('https://httpbin.org/patch', HttpGetContent.Create('Hello World'));
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/patch', 'The response should contain the expected url');
- Assert.AreEqual(GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'Hello World', 'The response should contain the expected data');
+ Assert.AreEqual('https://httpbin.org/patch', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
+ Assert.AreEqual('Hello World', GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'The response should contain the expected data');
end;
[Test]
@@ -96,18 +123,19 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test PUT request
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Put method is called
HttpResponseMessage := RestClient.Put('https://httpbin.org/put', HttpGetContent.Create('Hello World'));
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/put', 'The response should contain the expected url');
- Assert.AreEqual(GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'Hello World', 'The response should contain the expected data');
+ Assert.AreEqual('https://httpbin.org/put', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
+ Assert.AreEqual('Hello World', GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'The response should contain the expected data');
end;
[Test]
@@ -119,17 +147,18 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test DELETE request
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Delete method is called
HttpResponseMessage := RestClient.Delete('https://httpbin.org/delete');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/delete', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/delete', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
end;
[Test]
@@ -142,6 +171,7 @@ codeunit 134971 "Rest Client Tests"
// [SCENARIO] Test GET request with headers
// [GIVEN] An initialized Rest Client with default request headers
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
RestClient.SetDefaultRequestHeader('X-Test-Header', 'Test');
@@ -149,11 +179,11 @@ codeunit 134971 "Rest Client Tests"
HttpResponseMessage := RestClient.Get('https://httpbin.org/get');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/get', 'The response should contain the expected url');
- Assert.AreEqual(SelectJsonToken('$.headers.X-Test-Header', JsonObject).AsValue().AsText(), 'Test', 'The response should contain the expected header');
+ Assert.AreEqual('https://httpbin.org/get', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
+ Assert.AreEqual('Test', SelectJsonToken(JsonObject, '$.headers.X-Test-Header').AsValue().AsText(), 'The response should contain the expected header');
end;
[Test]
@@ -166,6 +196,7 @@ codeunit 134971 "Rest Client Tests"
// [SCENARIO] Test GET request with base address
// [GIVEN] An initialized Rest Client with base address
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
RestClient.SetBaseAddress('https://httpbin.org');
@@ -173,10 +204,10 @@ codeunit 134971 "Rest Client Tests"
HttpResponseMessage := RestClient.Get('/get');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/get', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/get', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
end;
[Test]
@@ -188,17 +219,18 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test GET request with default User-Agent header
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Get method is called using the default User-Agent header
HttpResponseMessage := RestClient.Get('https://httpbin.org/get');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.IsTrue(SelectJsonToken('$.headers.User-Agent', JsonObject).AsValue().AsText().StartsWith('Dynamics 365 Business Central '), 'The response should contain a User-Agent header');
+ Assert.IsTrue(SelectJsonToken(JsonObject, '$.headers.User-Agent').AsValue().AsText().StartsWith('Dynamics 365 Business Central '), 'The response should contain a User-Agent header');
end;
[Test]
@@ -211,6 +243,7 @@ codeunit 134971 "Rest Client Tests"
// [SCENARIO] Test GET request with custom User-Agent header
// [GIVEN] An initialized Rest Client with a customer User-Agent header
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
RestClient.SetUserAgentHeader('BC Rest Client Test');
@@ -218,10 +251,10 @@ codeunit 134971 "Rest Client Tests"
HttpResponseMessage := RestClient.Get('https://httpbin.org/get');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(SelectJsonToken('$.headers.User-Agent', JsonObject).AsValue().AsText(), 'BC Rest Client Test', 'The response should contain the expected User-Agent header');
+ Assert.AreEqual('BC Rest Client Test', SelectJsonToken(JsonObject, '$.headers.User-Agent').AsValue().AsText(), 'The response should contain the expected User-Agent header');
end;
[Test]
@@ -232,14 +265,40 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test GET request with JSON response
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The GetAsJson method is called
JsonObject := RestClient.GetAsJson('https://httpbin.org/get').AsObject();
// [THEN] The response contains the expected data
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/get', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/get', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
+ end;
+
+ [Test]
+ [ErrorBehavior(ErrorBehavior::Collect)]
+ procedure TestGetAsJsonWithCollectingErrors()
+ var
+ RestClient: Codeunit "Rest Client";
+ JsonToken: JsonToken;
+ ExceptionList: List of [ErrorInfo];
+ Exception: ErrorInfo;
+ begin
+ // [SCENARIO] Test GET request with JSON response
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
+ RestClient.Initialize(HttpClientHandler);
+
+ // [WHEN] The GetAsJson method is called
+ JsonToken := RestClient.GetAsJson('https://httpbin.org/xml');
+
+ // [THEN] The response contains the expected data
+ ExceptionList := GetCollectedErrors(true);
+ Exception := ExceptionList.Get(1);
+
+ Assert.AreEqual('The content is not a valid JSON.', Exception.Message, 'The collected error message should be as expected');
end;
[Test]
@@ -252,7 +311,8 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test POST request with JSON request and response
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [GIVEN] A Json object
@@ -264,10 +324,10 @@ codeunit 134971 "Rest Client Tests"
JsonObject2 := RestClient.PostAsJson('https://httpbin.org/post', JsonObject1).AsObject();
// [THEN] The response contains the expected data
- Assert.AreEqual(GetJsonToken(JsonObject2, 'url').AsValue().AsText(), 'https://httpbin.org/post', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/post', GetJsonToken(JsonObject2, 'url').AsValue().AsText(), 'The response should contain the expected url');
JsonObject2.ReadFrom(GetJsonToken(JsonObject2, 'data').AsValue().AsText());
- Assert.AreEqual(GetJsonToken(JsonObject2, 'name').AsValue().AsText(), 'John', 'The response should contain the expected data');
- Assert.AreEqual(GetJsonToken(JsonObject2, 'age').AsValue().AsInteger(), 30, 'The response should contain the expected data');
+ Assert.AreEqual('John', GetJsonToken(JsonObject2, 'name').AsValue().AsText(), 'The response should contain the expected data');
+ Assert.AreEqual(30, GetJsonToken(JsonObject2, 'age').AsValue().AsInteger(), 'The response should contain the expected data');
end;
[Test]
@@ -280,7 +340,8 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test PATCH request with JSON request and response
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [GIVEN] A Json object
@@ -292,10 +353,10 @@ codeunit 134971 "Rest Client Tests"
JsonObject2 := RestClient.PatchAsJson('https://httpbin.org/patch', JsonObject1).AsObject();
// [THEN] The response contains the expected data
- Assert.AreEqual(GetJsonToken(JsonObject2, 'url').AsValue().AsText(), 'https://httpbin.org/patch', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/patch', GetJsonToken(JsonObject2, 'url').AsValue().AsText(), 'The response should contain the expected url');
JsonObject2.ReadFrom(GetJsonToken(JsonObject2, 'data').AsValue().AsText());
- Assert.AreEqual(GetJsonToken(JsonObject2, 'name').AsValue().AsText(), 'John', 'The response should contain the expected data');
- Assert.AreEqual(GetJsonToken(JsonObject2, 'age').AsValue().AsInteger(), 30, 'The response should contain the expected data');
+ Assert.AreEqual('John', GetJsonToken(JsonObject2, 'name').AsValue().AsText(), 'The response should contain the expected data');
+ Assert.AreEqual(30, GetJsonToken(JsonObject2, 'age').AsValue().AsInteger(), 'The response should contain the expected data');
end;
[Test]
@@ -308,7 +369,8 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test PUT request with JSON request and response
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [GIVEN] A Json object
@@ -320,10 +382,10 @@ codeunit 134971 "Rest Client Tests"
JsonObject2 := RestClient.PutAsJson('https://httpbin.org/put', JsonObject1).AsObject();
// [THEN] The response contains the expected data
- Assert.AreEqual(GetJsonToken(JsonObject2, 'url').AsValue().AsText(), 'https://httpbin.org/put', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/put', GetJsonToken(JsonObject2, 'url').AsValue().AsText(), 'The response should contain the expected url');
JsonObject2.ReadFrom(GetJsonToken(JsonObject2, 'data').AsValue().AsText());
- Assert.AreEqual(GetJsonToken(JsonObject2, 'name').AsValue().AsText(), 'John', 'The response should contain the expected data');
- Assert.AreEqual(GetJsonToken(JsonObject2, 'age').AsValue().AsInteger(), 30, 'The response should contain the expected data');
+ Assert.AreEqual('John', GetJsonToken(JsonObject2, 'name').AsValue().AsText(), 'The response should contain the expected data');
+ Assert.AreEqual(30, GetJsonToken(JsonObject2, 'age').AsValue().AsInteger(), 'The response should contain the expected data');
end;
[Test]
@@ -335,17 +397,18 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test Send method without Getcontent
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Send method is called without Getcontent
HttpResponseMessage := RestClient.Send(Enum::"Http Method"::GET, 'https://httpbin.org/get');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/get', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/get', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
end;
[Test]
@@ -358,18 +421,19 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test Send method with Getcontent
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Send method is called with Getcontent
HttpResponseMessage := RestClient.Send(Enum::"Http Method"::POST, 'https://httpbin.org/post', HttpContent.Create('Hello World'));
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/post', 'The response should contain the expected url');
- Assert.AreEqual(GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'Hello World', 'The response should contain the expected data');
+ Assert.AreEqual('https://httpbin.org/post', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
+ Assert.AreEqual('Hello World', GetJsonToken(JsonObject, 'data').AsValue().AsText(), 'The response should contain the expected data');
end;
[Test]
@@ -382,7 +446,8 @@ codeunit 134971 "Rest Client Tests"
begin
// [SCENARIO] Test Send method with request message
- // [GIVEN] An uninitialized Rest Client
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
RestClient.Initialize(HttpClientHandler);
// [WHEN] The Send method is called with a request message
@@ -391,10 +456,10 @@ codeunit 134971 "Rest Client Tests"
HttpResponseMessage := RestClient.Send(ALHttpRequestMessage);
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'https://httpbin.org/get', 'The response should contain the expected url');
+ Assert.AreEqual('https://httpbin.org/get', GetJsonToken(JsonObject, 'url').AsValue().AsText(), 'The response should contain the expected url');
end;
[Test]
@@ -417,9 +482,152 @@ codeunit 134971 "Rest Client Tests"
HttpResponseMessage := RestClient.Get('https://httpbin.org/basic-auth/user01/Password123');
// [THEN] The response contains the expected data
- Assert.AreEqual(HttpResponseMessage.GetHttpStatusCode(), 200, 'The response status code should be 200');
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
+ JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
+ Assert.AreEqual(true, GetJsonToken(JsonObject, 'authenticated').AsValue().AsBoolean(), 'The response should contain the expected data');
+ end;
+
+ [Test]
+ procedure TestResponseWithCookies()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ begin
+ // [SCENARIO] Test GET request with cookies
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
+ RestClient.Initialize(HttpClientHandler);
+
+ // [WHEN] The Get method is called
+ HttpResponseMessage := RestClient.Get('https://postman-echo.com/get');
+
+ // [THEN] The response contains the expected data
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
+ Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
+ Assert.IsTrue(HttpResponseMessage.GetCookieNames().Contains('sails.sid'), 'The response should contain the expected cookie');
+ end;
+
+ [Test]
+ procedure TestRequestWithCookies()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpRequestMessage: Codeunit "Http Request Message";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ JsonObject: JsonObject;
+ begin
+ // [SCENARIO] Test GET request with cookies
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
+ RestClient.Initialize(HttpClientHandler);
+
+ // [GIVEN] A request message with cookies
+ HttpRequestMessage.SetRequestUri('https://httpbin.org/cookies');
+ HttpRequestMessage.SetCookie('cookie1', 'value1');
+ HttpRequestMessage.SetCookie('cookie2', 'value2');
+
+ // [WHEN] The Send method is called with a request message
+ HttpResponseMessage := RestClient.Send(HttpRequestMessage);
+
+ // [THEN] The response contains the expected data
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
+ Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
+ JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
+ Assert.AreEqual('value1', SelectJsonToken(JsonObject, '$.cookies.cookie1').AsValue().AsText(), 'The response should contain the expected cookie1');
+ Assert.AreEqual('value2', SelectJsonToken(JsonObject, '$.cookies.cookie2').AsValue().AsText(), 'The response should contain the expected cookie2');
+ end;
+
+ [Test]
+ procedure TestWithoutUseResponseCookies()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ JsonObject: JsonObject;
+ JsonToken: JsonToken;
+ begin
+ // [SCENARIO] Test GET request without using response cookies
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
+ RestClient.Initialize(HttpClientHandler);
+
+ // [GIVEN] Use response cookies is disabled
+ RestClient.SetUseResponseCookies(false);
+
+ // [GIVEN] Specific cookies are set
+ HttpResponseMessage := RestClient.Get('https://httpbin.org/cookies/set?cookie1=value1');
+
+ // [WHEN] The cookies list is retrieved
+ HttpResponseMessage := RestClient.Get('https://httpbin.org/cookies');
+
+ // [THEN] The response contains the expected data
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
+ Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
+ JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
+ Assert.IsFalse(JsonObject.SelectToken('$.cookies.cookie1', JsonToken), 'The response should not contain cookies');
+ end;
+
+ [Test]
+ procedure TestWithUseResponseCookies()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ JsonObject: JsonObject;
+ begin
+ // [SCENARIO] Test GET request with using response cookies
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
+ RestClient.Initialize(HttpClientHandler);
+
+ // [GIVEN] Use response cookies is enabled
+ RestClient.SetUseResponseCookies(true);
+
+ // [GIVEN] Specific cookies are set
+ HttpResponseMessage := RestClient.Get('https://httpbin.org/cookies/set?cookie1=value1');
+
+ // [WHEN] The cookies list is retrieved
+ HttpResponseMessage := RestClient.Get('https://httpbin.org/cookies');
+
+ // [THEN] The response contains the expected data
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
+ Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
+ JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
+ Assert.AreEqual('value1', SelectJsonToken(JsonObject, '$.cookies.cookie1').AsValue().AsText(), 'The response should contain the expected cookie');
+ end;
+
+ [Test]
+ procedure TestUseResponseCookiesWithAdditionalCookies()
+ var
+ RestClient: Codeunit "Rest Client";
+ HttpRequestMessage: Codeunit "Http Request Message";
+ HttpResponseMessage: Codeunit "Http Response Message";
+ JsonObject: JsonObject;
+ begin
+ // [SCENARIO] Test GET request with using response cookies and additional cookies
+
+ // [GIVEN] An initialized Rest Client
+ HttpClientHandler.Initialize();
+ RestClient.Initialize(HttpClientHandler);
+
+ // [GIVEN] Use response cookies is enabled
+ RestClient.SetUseResponseCookies(true);
+
+ // [GIVEN] Specific cookies are set
+ HttpResponseMessage := RestClient.Get('https://httpbin.org/cookies/set?cookie1=value1');
+
+ // [WHEN] The cookies list is retrieved with additional cookies
+ HttpRequestMessage.SetRequestUri('https://httpbin.org/cookies');
+ HttpRequestMessage.SetCookie('cookie2', 'value2');
+ HttpResponseMessage := RestClient.Send(HttpRequestMessage);
+
+ // [THEN] The response contains the expected data
+ Assert.AreEqual(200, HttpResponseMessage.GetHttpStatusCode(), 'The response status code should be 200');
+ Assert.IsTrue(HttpResponseMessage.GetIsSuccessStatusCode(), 'GetIsSuccessStatusCode should be true');
JsonObject := HttpResponseMessage.GetContent().AsJson().AsObject();
- Assert.AreEqual(GetJsonToken(JsonObject, 'authenticated').AsValue().AsBoolean(), true, 'The response should contain the expected data');
+ Assert.AreEqual('value1', SelectJsonToken(JsonObject, '$.cookies.cookie1').AsValue().AsText(), 'The response should contain the expected cookie1');
+ Assert.AreEqual('value2', SelectJsonToken(JsonObject, '$.cookies.cookie2').AsValue().AsText(), 'The response should contain the expected cookie2');
end;
local procedure GetJsonToken(JsonObject: JsonObject; Name: Text) JsonToken: JsonToken
@@ -427,7 +635,7 @@ codeunit 134971 "Rest Client Tests"
JsonObject.Get(Name, JsonToken);
end;
- local procedure SelectJsonToken(Path: Text; JsonObject: JsonObject) JsonToken: JsonToken
+ local procedure SelectJsonToken(JsonObject: JsonObject; Path: Text) JsonToken: JsonToken
begin
JsonObject.SelectToken(Path, JsonToken);
end;
diff --git a/src/System Application/Test/Rest Client/src/TestHttpClientHandler.Codeunit.al b/src/System Application/Test/Rest Client/src/TestHttpClientHandler.Codeunit.al
index 379b36ccf1..4f89e806a0 100644
--- a/src/System Application/Test/Rest Client/src/TestHttpClientHandler.Codeunit.al
+++ b/src/System Application/Test/Rest Client/src/TestHttpClientHandler.Codeunit.al
@@ -11,11 +11,62 @@ codeunit 134974 "Test Http Client Handler" implements "Http Client Handler"
{
SingleInstance = true;
+ var
+ MockConnectionFailed: Boolean;
+ MockIsBlockedByEnvironment: Boolean;
+ MockRequestFailed: Boolean;
+
procedure Send(HttpClient: HttpClient; HttpRequestMessage: Codeunit "Http Request Message"; var HttpResponseMessage: Codeunit "Http Response Message") Success: Boolean;
var
ResponseMessage: HttpResponseMessage;
begin
+ if MockConnectionFailed then begin
+ Success := false;
+ exit;
+ end;
+
+ if MockIsBlockedByEnvironment then begin
+ Success := false;
+ HttpResponseMessage.SetIsBlockedByEnvironment(true);
+ exit;
+ end;
+
+ if MockRequestFailed then begin
+ Success := true;
+ HttpResponseMessage.SetHttpStatusCode(400);
+ HttpResponseMessage.SetReasonPhrase('Bad Request');
+ exit;
+ end;
+
Success := HttpClient.Send(HttpRequestMessage.GetHttpRequestMessage(), ResponseMessage);
HttpResponseMessage.SetResponseMessage(ResponseMessage);
end;
+
+ procedure Initialize()
+ begin
+ MockConnectionFailed := false;
+ MockIsBlockedByEnvironment := false;
+ MockRequestFailed := false;
+ end;
+
+ procedure SetMockConnectionFailed()
+ begin
+ MockConnectionFailed := true;
+ MockIsBlockedByEnvironment := false;
+ MockRequestFailed := false;
+ end;
+
+ procedure SetMockIsBlockedByEnvironment()
+ begin
+ MockConnectionFailed := false;
+ MockIsBlockedByEnvironment := true;
+ MockRequestFailed := false;
+ end;
+
+ procedure SetMockRequestFailed()
+ begin
+ MockConnectionFailed := false;
+ MockIsBlockedByEnvironment := false;
+ MockRequestFailed := true;
+ end;
}
\ No newline at end of file