In today’s digital world, a smooth and intuitive user experience is key to any web application’s success. A critical part of this experience is providing users with easy access to various resources—whether documents, images, or other data types. To make this possible, your server must manage and deliver different content formats efficiently.
With 4D’s new REST server feature, managing diverse content delivery is now easier than ever. Previously, the REST server could only return scalar, entity, or entity selection data. Now, it can deliver full web content directly—content ready for a browser to handle.
Downloading files or receiving binary data from the REST server is now straightforward, thanks to the new OutgoingMessage class. With it, you can easily customize responses to suit your needs.
Read on to explore how the OutgoingMessage class can enhance your application!
calling an exposed function on the REST Server
Quick reminder: ORDA data model functions and singleton functions are callable as REST APIs. To refresh your memory, check out this blog post and this one.
Until now, the REST server could return various result types—scalars, entities, or entity selections—wrapped within an object using the result property.
example
This is the getSomeInfo() function on the Datastore class.
exposed Function getSomeInfo() : Text
return "This is the info"
And here is the result got when it is called with the /rest/$catalog/getSomeInfo request:
{
"result": "This is the info"
}
4D Web commands can’t be used in such functions, that’s why the new OutgoingMessage class comes with a great benefit.
The new OutgoingMessage class
The ORDA data model and singletons functions can now return an object instance of this new OutgoingMessage class.
Such objects are handled directly by any browser as web content.
Thus, you can propose to your end users features such as downloading files and pictures and receiving any content type via a browser.
This is the JSON representation of such an object instance of the OutgoingMessage class.
example
In this example, the getFile() function is implemented in the Datastore class. The purpose is to return the testFile.pdf file as a response to the request.
An object instance of the OutgoingMessage class is created.
The body contains the binary content of the testFile.pdf file and a header indicating that the content type is set.
exposed onHTTPGet Function getFile() : 4D.OutgoingMessage
var $result:=4D.OutgoingMessage.new()
var $file:=File("/RESOURCES/testFile.pdf")
$result.setBody($file.getContent()) // This is binary content
$result.setHeader("Content-Type"; "application/pdf")
return $result
The OutgoingMessage class contains three properties to fill according to your needs:
- header: Set any HTTP header that the client is bound to handle (e.g., content-type to indicate the type of the body content)
- body: set the content you want to send as a response to the request. It can be a String or a Blob (e.g., file, document, or image as binary content).
- status: Set any HTTP status code according to the result of the proceeded request. This provides the client with information on how the request went (e.g., status 403 if the request is refused). The default value is 200.
N.B. The body and status properties can be affected with the := operator or with the corresponding setBody() / setStatus() function.
ease the call of functions on the rest server
the new onHTTPGet keyword for functions
So far, the function calls (of ORDA data model classes and singletons) through the REST server had to be done with a POST verb. This was done for security reasons to avoid running sensitive code through an action as simple as clicking on a link.
Because the POST does not always fit the user experience you want to offer, those functions can also be called with a GET verb, i.e., callable by entering a URL in a browser.
Use the new onHTTPGet keyword for this. If this keyword is applied to a function, this function is also callable with a GET verb!
example
exposed onHTTPGet Function getSomeInfo() : 4D.OutgoingMessage
N.B. As this type of call is an easily offered action, the developer must ensure no sensitive action is done in such functions.
passing parameters
Parameters can be passed to the function with the $params parameter (must be enclosed in a collection).
example
In this example, the getThumbnail() function of the Products dataclass is called (to get a thumbnail photo of a given product).
It receives the product name and the required width + length.
IP:port/rest/Products/getThumbnail?$params='["Yellow Pack",200,200]'
Check the documentation for more information about sending parameters when calling a function.
A complete example
Here is the use case of this example: a link is proposed to an end user to download the user manual of a selected product with several formats available.
The request behind the link is: IP:port/rest/Products/getUserManual?$params='[1, “pdf”]’
The selected product id (1) is passed as a parameter and the required format (pdf).
The getUserManual() function of the Products dataclass is called. It receives the product id and the format as a parameter.
The corresponding document is retrieved. Its binary content is put as a body in the response with the corresponding content type.
exposed onHTTPGet Function getUserManual($productId : Integer; $type : Text) : 4D.OutgoingMessage
var $file : 4D.File
var $response:=4D.OutgoingMessage.new()
var $doc:="/RESOURCES/User manuals/product_"+String($productId)
Case of
: ($type="pdf")
$file:=File($doc+".pdf")
$response.setBody($file.getContent()) // This is binary content
$response.setHeader("Content-Type"; "application/pdf")
: ($type="jpeg")
$file:=File($doc+".jpeg")
$response.setBody($file.getContent()) // This is binary content
$response.setHeader("Content-Type"; "image/jpeg")
End case
return $response
Here is the scenario played in a browser:
Try It Yourself
Download the HDI to explore this new feature, and check out the documentation for more details about using the OutgoingMessage class in your web applications.