Skip to main content
Version: Next

HTTP Handlers

Overview

HTTP Request Handlers let you define how your application responds to HTTP requests by:

  • Listening for specific URL patterns (e.g., /api/users).

  • Handling different HTTP methods (e.g., GET, POST, PUT).

  • Linking these requests to specific logic in your application.

Why Use HTTP Request Handlers?

HTTP Request Handlers are ideal when:

  • Server-Side Logic is Required: Use HTTP Request Handlers to process server-side operations, such as interacting with databases, performing complex calculations, or handling business rules.

    Example

    Processing user authentication or generating reports dynamically.

  • API-Like Behavior is Needed: HTTP Request Handlers allow you to create RESTful endpoints that external systems or frontend applications can call.

    Example

    A mobile app might send a POST request to /api/login to authenticate a user.

  • Scalable Interactions Across Multiple Clients: Unlike UI events (which are specific to the client session), HTTP Request Handlers work server-side and can handle multiple client requests simultaneously.

    Example

    Processing orders submitted from multiple web users simultaneously.

  • Custom URL Patterns and Verbs: Handlers let you define flexible URL patterns and handle different HTTP methods like GET or POST for the same URL.

    Example

    Using GET /products for listing products and POST /products for adding a new product.

When NOT to use HTTP Request Handlers:
  • For purely UI-based interactions, such as button clicks or navigating between pages in your app. These should be handled by front-end navigation events or on-click handlers.

  • For real-time interactions, like live updates to a page. Consider using WebSockets or a similar real-time communication mechanism instead.

Accessing HTTP Handlers

HTTP Handlers can be accessed and managed in Qodly Studio via the HTTP Handlers menu in the Explorer:

  1. Locate the HTTP Handlers menu in the Explorer.

  2. If the menu item is greyed out , click it to create the HTTPHandlers.json file.

  3. Once created, the file will open for editing .

By default, the HTTP Handlers UI is displayed instead of the code editor, allowing handlers to be managed via an intuitive graphical interface.

Switching Between UI and Code Edito

Handlers can be modified using either the UI or the JSON editor.

  • To switch to the code editor view, clicking the code editor icon is required.

  • To return to the HTTP Handler UI, clicking the UI icon is necessary.

  • Changes made in one view are automatically synchronized with the other.

If no handlers are configured, a message appears stating: There are no HTTP Handlers configured yet. Click on the ➕ to add a new one..

Configuring HTTP Handlers

Add HTTP Handlers

HTTP Handlers can be added through both the UI and the code editor.

Using the HTTP Handler UI:

  1. Clicking the button opens a form for inputting handler details.

  2. The form requires specifying the following details:

    • Class: Selecting an existing class from the dropdown list or manually entering a class name.

    • Method: Choosing an available method from the selected class or entering a method manually.

    • Pattern: Defining the URL pattern.

    • As Regex: Enabling this if using a regular expression for URL matching.

    • Verbs: Selecting supported HTTP methods (GET, POST, PUT, DELETE).

  3. Clicking Save applies the configuration.

Handling Class and Method Errors

When manually entering a class name or method that does not exist, the system provides visual feedback to prevent misconfiguration.

  • If the specified class or method does not exist, a Nothing found message appears, and the input field turns red.

  • Unrecognized entries are automatically removed when pressing Enter.
Adding an Unsupported HTTP verb

Only the four HTTP methods (GET, POST, PUT, DELETE) are supported. If an invalid method is typed and Enter is pressed, it will not be added.

In contrast, supported methods (GET, POST, PUT, DELETE) will have a dark grey background to indicate they are valid.

Using the Code Editor:

Handlers can also be configured manually in the code editor, like:

[
{
"class": "CustomerHandler",
"method": "getCustomer",
"pattern": "customers",
"verbs": "GET"
},
{
"class": "AuthHandler",
"method": "login",
"regexPattern": "/auth/login",
"verbs": "POST"
}
]
Error Handling When Switching Views

If a class or method that does not exist is added directly through the code editor, there is no immediate validation or error handling. However, when switching to the UI view, the system detects invalid entries and highlights them in red. An error message appears below the affected fields, stating: The singleton "Class or Method name" doesn't exist.

Adding an Unsupported HTTP verb

The code editor does not enforce immediate validation when an invalid HTTP method is added. If an unsupported HTTP method is entered in the JSON file, it will be saved without an error. However, when switching to the UI view the invalid method will be highlighted with a dark red background , indicating that it is not a valid option.

Edit HTTP Handlers

Editing allows modifications to the class, method, URL pattern, or HTTP methods:

  • Use the UI to expand a handler and adjust its settings.

  • Or, edit the JSON file directly for manual changes from the code editor.

Delete HTTP Handlers

Removing unnecessary handlers keeps request processing efficient:

  • Click the trash icon in the UI to delete a handler, then confirm the action.

  • Alternatively, delete the handler entry from the code editor.

Duplicate Handlers

Duplicating handlers allows for quick replication:

  • Click the duplicate icon in the UI.

  • Copy and paste JSON objects for manual duplication.

Reorder Handlers

Execution order can be adjusted:

  • Drag and drop handlers in the UI .

  • Manually rearrange JSON objects in the file.

Expand/Collapse HTTP Handlers

For better organization, handlers in the UI can be expanded or collapsed to show or hide details.

Matching Rules

Handlers can define URL patterns in two ways:

  • Prefix (pattern): Matches any URL that starts with the specified prefix.

    Example

    A handler with "pattern": products matches /products, /products/list, and /products/123.

  • Regular Expression (regexPattern): Matches URLs that satisfy the specified regular expression.

    Example

    A handler with "regexPattern": /products/[0-9]+ matches /products/123 and /products/456, but not /products/list.

Matching Scenarios

Given the following configuration:

[
{
"class": "OrderHandler",
"method": "getOrder",
"regexPattern": "/orders/[0-9]+",
"verbs": "GET"
},
{
"class": "OrderHandler",
"method": "listOrders",
"pattern": "orders",
"verbs": "GET"
}
]
  • GET /orders/123: Matches the first handler (getOrder) because /orders/123 satisfies the regular expression /orders/[0-9]+.

  • GET /orders: Matches the second handler (listOrders) because /orders is a prefix of the URL.

  • POST /orders/123: Does not match any handler because neither handler supports the POST method.

Order of Execution

When an HTTP request is received, the system evaluates each handler in the order they appear in the HTTPHandlers.json file or the UI. The execution flow follows these steps:

  • The URL of the request is matched against the pattern or regexPattern of each handler.

  • The HTTP method (verb) of the request is checked against the verbs property of the handler.

  • Only the first matching handler is executed, even if subsequent handlers also match the request.

Example of First Match Execution

Given the following configuration:

[
{
"class": "ProductHandler",
"method": "getProductDetails",
"verbs": "GET",
"id": "2jSeKR6tDs4KTKXrH3vVzR",
"regexPattern": "/products/[0-9]+"
},
{
"class": "ProductHandler",
"method": "listProducts",
"verbs": "GET",
"id": "uJScfkSR6rkhoJSpfEiG6U",
"pattern": "products"
}
]

A request to GET /products/123 will match both handlers:

  • The first handler matches because the URL /products/123 satisfies the regular expression /products/[0-9]+.

  • The second handler matches because /products is a prefix of the URL.

However, only the first handler getProductDetails is executed, as it appears first in the configuration.

Request Handler Code

Function Configuration

The HTTP Request handler code must be implemented in a function of a Shared singleton class.

If the singleton is missing or not shared, an error Cannot find singleton is returned by the server. If the class or the function defined as handler is not found, an error Cannot find singleton function is returned by the server.

Request handler functions are not necessarily shared, unless some request handler properties are updated by the functions. In this case, you need to declare its functions with the shared keyword.

note

It is not recommended to expose request handler functions to external REST calls using exposed or onHttpGet keywords.

Handling Errors

If no handler matches a request, the system automatically returns a 404 error. This behavior ensures that unexpected or unsupported requests do not disrupt the application.

To handle unmatched requests explicitly, you can define a fallback handler. Fallback handlers can be used to return custom error messages, redirect requests, or log unexpected behavior.

{
"class": "ErrorHandler",
"method": "handleNotFound",
"regexPattern": "/.+",
"verbs": "*"
}

This handler catches all requests that are not matched by earlier handlers. It can be used to:

  • Return a custom 404 page.

  • Log details about unmatched requests.

  • Redirect users to a default page.

Input: 4D.IncomingMessage Class Instance

When a request is intercepted by the handler, it is received on the server as an instance of the 4D.IncomingMessage class.

This object provides all necessary request information, including the request URL, verb, headers, URL parameters, and request body. The request handler can use this information to trigger the appropriate business logic.

Output: 4D.OutgoingMessage Class Instance

The request handler can return an object instance of the 4D.OutGoingMessage class, which represents web content ready for a browser to handle, such as a file content or a structured response.

Example

The 4D.IncomingMessage class provides functions to retrieve headers and the body of the request.

Below is an example of an HTTP handler that processes a file upload.

HTTP Request Handler Configuration:
[
{
"class": "UploadFile",
"method": "uploadFile",
"regexPattern": "/putFile",
"verbs": "POST"
}
]

The request URL: /putFile?fileName=testFile

  • The binary content of the file is sent in the request body.

  • The POST verb is used.

  • The filename is included as a query parameter (fileName).

  • The filename is extracted using the urlQuery object.

Implementation of the UploadFile Class:
    //UploadFile class

shared singleton constructor()


function uploadFile(request : 4D.IncomingMessage) : 4D.OutgoingMessage

var response = 4D.OutgoingMessage.new()

var body = "Not supported file"
var fileName, fileType : string
var file : 4D.File
var picture : picture
var created : boolean

fileName = request.urlQuery.fileName
fileType = request.getHeader("Content-Type")

switch
: (fileType == "application/pdf")
file = file("/PACKAGE/Files/"+fileName+".pdf")
created = file.create()
file.setContent(request.getBlob())
body = "Upload OK - File size: "+string(file.size)

: (fileType == "image/jpeg")
file = file("/PACKAGE/Files/"+fileName+".jpg")
picture = request.getPicture()
body = "Upload OK - Image size: "+string(file.size)

end

response.setBody(body)
response.setHeader("Content-Type", "text/plain")

return response