How to Send a POST Request with a Specific Content-type Header Using HTTP_FETCH()

Description

The content type cannot be set when using HTTP_POST() to POST data to a server. If the server expects a different Content-type header, HTTP_FETCH() can be used instead.

When sending a request using HTTP_POST, you may receive content type errors such as the one shown below indicating the content sent did not meet expectations:

? response
= body = <?xml version="1.0" encoding="UTF-8"?>
<response success="false">
  <messages>
    <message key="invalid-xml">Illegal Input. Input data must be an XML document.</message>
  </messages>
</response>

HTTP_POST() is an Xbasic function for sending an HTTP POST requests. To make the function easy to use, HTTP_POST() does not allow full control over the request and makes assumptions about the type of data sent to the server. HTTP_POST() always sets the Content-Type header to application/x-www-form-urlencoded.

Because the Content-type cannot be changed, POSTing any other content type using HTTP_POST() will not work as expected. Instead, HTTP_FETCH() must be used. HTTP_FETCH() allows any header to be set to any value.

Additionally, HTTP_FETCH() supports using the HTTP/1.0 protocol. HTTP_FETCH() will default to HTTP/1.1. HTTP_POST() (and HTTP_GET()) only use HTTP/1.1.

In the example below, a POST request is created and sent using HTTP_FETCH to generate an authentication ticket for accessing the Quickbase API. The Content-type is set to "application/xml" via the settings.header property. The settings dot variable is used to define the protocol, headers, and other instructions for sending the request:

dim settings as p
settings.host = "mycompany.quickbase.com"
settings.page = "/db/main"
settings.protocol = "HTTP/1.0"
settings.port = 443
settings.ssl_on = .t.
settings.method = "POST"
settings.header =<<%txt%
Content-Type: application/xml
QUICKBASE-ACTION: API_Authenticate
%txt%
settings.body =<<%body%
<qdbapi>
    <username>sarah@mycompany.com</username>
    <password>SomePassword123</password>
</qdbapi>
%body%

dim results as p
results = HTTP_FETCH(settings)

Once the response is received, the status code must be checked first to verify that the request was successful (i.e. a status code "200") The status code should always be checked when using any HTTP_* function. The status code can be found in the response.parsed_headers property returned by the HTTP_FETCH() function:

? response.parsed_headers.status_code
= 200
HTTP_FETCH (or any other HTTP_* function) does not automatically redirect the request when a 301 or 302 (redirect) code is received. You must examine the results in result.parsed_headers.status_code and try the URL in result.parsed_headers.location, if appropriate.

If the request succeeds, the response.body will contain the conent from the response. In this example, the content returned is XML:

? results.body
= <?xml version="1.0" ?>
<qdbapi>
    <action>API_Authenticate</action>
    <errcode>0</errcode>
    <errtext>No error</errtext>
    <ticket>db4d5y4bd76u86dsd27px44inx72nanzdacmnkwicb3hxxkct7aqr6d</ticket>
    <userid>123456789</userid>
</qdbapi>

See Also