HttpClient.Post(Text, HttpContent, var HttpResponseMessage) Method

Version: Available or changed with runtime version 1.0.

Sends a POST request to the specified URI as an asynchronous operation.

Syntax

[Ok := ]  HttpClient.Post(Path: Text, Content: HttpContent, var Response: HttpResponseMessage)

Parameters

HttpClient
 Type: HttpClient
An instance of the HttpClient data type.

Path
 Type: Text
The path the request is sent to.

Content
 Type: HttpContent
The HTTP request content sent to the server.

Response
 Type: HttpResponseMessage
The response received from the remote endpoint.

Return Value

[Optional] Ok
 Type: Boolean
Accessing the HttpContent property of HttpResponseMessage in a case when the request fails will result in an error. If you omit this optional return value and the operation does not execute successfully, a runtime error will occur.

Ways that HttpClient.Post calls can fail

The method HttpClient.Post can fail and return false in the following ways:

  • The requestUri is not an absolute URI.
  • The request failed due to an underlying issue such as network connectivity, DNS failure, server certificate validation or timeout.
  • The request failed due to timeout.

Important

Outbound HTTP calls from apps/extensions are blocked by default and must be approved for each extension, otherwise instead of an external call, the system will display the following error message: The request was blocked by the runtime to prevent accidental use of production services.

To enable outbound HTTP calls, go to the Extension Management page in Business Central, and choose Configure. Then, on the Extension Settings page, make sure that Allow HttpClient Requests is selected. This setting must be enabled for each app/extension, including library apps.

Example (HTTP POST)

A POST request sends data to the server for processing. The Content-Type header of the request signifies what MIME type the body is sending. To make an HTTP POST request, given an HttpClient and a Uri, use the HttpClient.Post method:

    local procedure PostRequest(json: Text;) ResponseText: Text
    var
        Client: HttpClient;
        Content: HttpContent
        ContentHeaders: HttpHeaders;
        IsSuccessful: Boolean;
        Response: HttpResponseMessage;
        ResponseText: Text;
    begin
        Content.GetHeaders(ContentHeaders);

        if ContentHeaders.Contains('Content-Type') then headers.Remove('Content-Type');
        ContentHeaders.Add('Content-Type', 'application/json');

        if ContentHeaders.Contains('Content-Encoding') then headers.Remove('Content-Encoding');
        ContentHeaders.Add('Content-Encoding', 'UTF8');

        // assume that the json parameter contains the following data
        //
        // {
        //    userId = 77,
        //    id = 1,
        //    title = "write code sample",
        //    completed = false
        // }
        Content.WriteFrom(json);

        IsSuccessful := Client.Post('https://jsonplaceholder.typicode.com/todos', Content, Response);

        if not IsSuccessful then begin
            // handle the error
        end;

        if not Response.IsSuccessStatusCode() then begin
            HttpStatusCode := response.HttpStatusCode();
            // handle the error (depending on the HTTP status code)
        end;

        Response.Content().ReadAs(ResponseText);

        // Expected output:
        //   POST https://jsonplaceholder.typicode.com/todos HTTP/1.1
        //   {
        //     "userId": 77,
        //     "id": 201,
        //     "title": "write code sample",
        //     "completed": false
        //   }
    end;

The preceding code:

  • Prepares an HttpContent instance with the JSON body of the request (MIME type of "application/json" and using the character encoding UTF8).
  • Makes a POST request to "https://jsonplaceholder.typicode.com/todos".
  • Ensures that the response is successful.
  • Reads the response body as a string.

Example (How to upload a file using multipart/form-data)

The Content-Type multipart/form-data allows you to post multiple types of data in the same HTTP request and is commonly used for streaming data to an endpoint.

To use multipart/form-data with Httpclient, you need to do the following:

  1. Create a content payload, including defining the boundary between data elements
  2. Add the file content and file name to the content payload
  3. Set up the HTTP content header multipart/form-data

After these steps, your AL code should follows usual practices for Httpclient POST requests.

The methods for adding file content to the content payload differs depending if the file is a text file such as JSON or XML, or if it's a binary file. So we provided two different code examples below, one for each scenario:

Example (How to upload a text file using multipart/form-data)

    procedure UploadJson(json: Text; Url: Text)
    var
        Client: HttpClient;
        Content: HttpContent;
        Headers: HttpHeaders;
        Response: HttpResponseMessage;
        MultiPartBody: TextBuilder;
        Boundary: Text;
        ResponseMessage: Text;
    begin
        Boundary := CreateGuid();
        MultiPartBody.AppendLine('--' + Format(Boundary));
        MultiPartBody.AppendLine('Content-Disposition: form-data; name="<add your formname here>"');
        MultiPartBody.AppendLine();
        MultiPartBody.AppendLine('--' + Format(Boundary));
        MultiPartBody.AppendLine('Content-Disposition: form-data; name="file"; filename="<add filename here>"');
        MultiPartBody.AppendLine('Content-Type: application/octet-stream');
        MultiPartBody.AppendLine();
        MultiPartBody.AppendLine(json);
        MultiPartBody.AppendLine('--' + Format(Boundary) + '--');

        Content.WriteFrom(MultiPartBody.ToText());

        Content.GetHeaders(Headers);
        if Headers.Contains('Content-Type') then
            Headers.Remove('Content-Type');
        Headers.Add('Content-Type', 'multipart/form-data; boundary="' + Format(Boundary) + '"');

        IsSuccessful := Client.Post(Url, Content, Response);

        if not IsSuccessful then begin
            // handle the error
        end;

        if not Response.IsSuccessStatusCode() then begin
            HttpStatusCode := response.HttpStatusCode();
            // handle the error (depending on the HTTP status code)
        end;

    end;

Example (How to upload a binary file using multipart/form-data)

The main reason for the code example being different when dealing with binary data is that we need to preserve the encoding of the data. A conversion to text might change the encoding.

    procedure UploadBinaryFile(ContentToBeUploaded: InStream; Url: Text)
    var
        Client: HttpClient;
        Content: HttpContent;
        Headers: HttpHeaders;
        Response: HttpResponseMessage;
        MultiPartBody: TextBuilder;
        MultiPartBodyOutStream: OutStream;
        MultiPartBodyInStream: InStream;
        TempBlob: Record TempBlob temporary;
        Boundary: Text;
        ResponseMessage: Text;
    begin
        TempBlob.Blob.CreateOutStream(MultiPartBodyOutStream);

        Boundary := CreateGuid();
        MultiPartBody.AppendLine('--' + Format(Boundary));
        MultiPartBody.AppendLine('Content-Disposition: form-data; name="<add your formname here>"');
        MultiPartBody.AppendLine();
        MultiPartBody.AppendLine('--' + Format(Boundary));
        MultiPartBody.AppendLine('Content-Disposition: form-data; name="file"; filename="<add filename here>"');
        //add file Content-Type eg. image/jpeg, image/png. If not known, use application/octet-stream.
        MultiPartBody.AppendLine('Content-Type: <add file Content-Type here>');
        MultiPartBody.AppendLine();
        MultiPartBodyOutStream.WriteText(MultiPartBody.ToText());

        CopyStream(MultiPartBodyOutStream, ContentToBeUploaded);

        MultiPartBody.Clear();
        MultiPartBody.AppendLine();
        MultiPartBody.AppendLine('--' + Format(Boundary) + '--');
        MultiPartBodyOutStream.WriteText(MultiPartBody.ToText());

        TempBlob.Blob.CreateInStream(MultiPartBodyInStream);
        Content.WriteFrom(MultiPartBodyInStream);

        Content.GetHeaders(Headers);
        if Headers.Contains('Content-Type') then
            Headers.Remove('Content-Type');
        Headers.Add('Content-Type', 'multipart/form-data; boundary="' + Format(Boundary) + '"');

        IsSuccessful := Client.Post(Url, Content, Response);

        if not IsSuccessful then begin
            // handle the error
        end;

        if not Response.IsSuccessStatusCode() then begin
            HttpStatusCode := response.HttpStatusCode();
            // handle the error (depending on the HTTP status code)
        end;

    end;

Example (How to upload large files using multipart/form-data)

Some endpoints have restrictions on the size of files that can be uploaded and hence you might need to split and upload the file in chunks. The system application SharePoint module has an implementation for how to achieve this. For more information, see Share Point module.

Content headers

By default, the content headers contain a header for 'Content-Type', namely 'text/plain; charset=utf-8'. This is important to adjust if the endpoint you're calling expects a different content type, for example, multipart/form-data or application/json.

The following AL code examples illustrate ways to change the content header.

    local procedure SendRequest(HttpMethod: Text[6]) ResponseText: Text
    var
        Client: HttpClient;
        Content: HttpContent;
        ContentHeaders: HttpHeaders;
    begin
        Content.GetHeaders(ContentHeaders);

        // If you want to set all the headers yourself, do it this way
        ContentHeaders.Clear();
        ContentHeaders.Add('Content-Type', 'multipart/form-data;boundary=boundary');

        // from here on, the method must deal with calling out to the external service. 
    end;
    local procedure SendRequest(HttpMethod: Text[6]) ResponseText: Text
    var
        Client: HttpClient;
        Content: HttpContent;
        ContentHeaders: HttpHeaders;
    begin
        Content.GetHeaders(ContentHeaders);

        // In this example, you just change the headers you need
        if ContentHeaders.Contains('Content-Type') then ContentHeaders.Remove('Content-Type');
        ContentHeaders.Add('Content-Type', 'multipart/form-data;boundary=boundary');

        // from here on, the method must deal with calling out to the external service. 
    end;

When calling an endpoint, you get a response back from the service you called. The response is saved in the data type HttpResponseMessage, where you can parse it to use the information in your app. The service call itself might not succeed, so make sure that you check the HTTP status code in your AL code. In the case of setting the wrong content type header, you'll typically receive the 415 Unsupported Media Type return code. This return code can also be due to the request's Content-Encoding header, or if the data you send doesn't match what the endpoint expects.

Supported HTTP methods

The HttpClient datatype supports the following HTTP methods:

  • DELETE
  • GET
  • PATCH
  • POST
  • PUT

The following table includes links to help you get started with calling external services using different HTTP methods.

To See
Dynamically set the HTTP method from AL, set it on the HttpRequestMessage datatype and use the HttpClient.Send method to call the service. HttpClient.Send(HttpRequestMessage, var HttpResponseMessage) Method
HttpRequestMessage.Method([Text]) Method
Delete data in a service endpoint using the HTTP DELETE method. HttpClient.Delete(Text, var HttpResponseMessage) Method
Read data from a service endpoint using the HTTP GET method. HttpClient.Get(Text, var HttpResponseMessage) Method
Update data in a service endpoint using the HTTP PATCH method (no specific AL method exists for PATCH, so use HttpClient.Send). HttpClient.Send(Text, HttpContent, var HttpResponseMessage) Method
Send data to a service endpoint using the HTTP POST method. HttpClient.Post(Text, HttpContent, var HttpResponseMessage) Method
Send data to a service endpoint using the HTTP PUT method. HttpClient.Put(Text, HttpContent, var HttpResponseMessage) Method

Contributors

This article is maintained by Microsoft. Parts of the examples were originally written by the following contributors.

See Also

Call external services with the HttpClient data type
HttpClient Data Type
Get Started with AL
Developing Extensions