TdjRestfulComponent – a REST framework for Delphi

A new version of the dwf REST framework is now available to all registered users of the Habari Web Components framework. It is implemented as an (experimental) Web Component.

The TdjRestfulComponent is inspired by existing frameworks for other programming languages like Sinatra, Spark and the Java API for RESTful Web Services (JAX-RS) specification.

How does it work?

Here is a short example, it registers a request handler at path hello which handles HTTP GET requests, but only if the HTTP request also specifies that the client accepts responses with content type text/html. (A HTTP error response will be returned if the HTTP client tries to submit a POST request, or if the client specifies a different content type).

&Path('hello');
&Produces('text/html');
GET
  (procedure(Request: TRequest; Response: TResponse)
  begin
    Response.ContentText := '<html>Hello world!</html>';
  end);

Available Commands

&Path(your_path) Sets the path to base URL + /your_path. For example, Path('hello') will mount the request handler at http://mydomain.com/context/hello
POST Indicates that the following method will answer to a HTTP POST request
GET Indicates that the following method will answer to a HTTP GET request
PUT Indicates that the following method will answer to a HTTP PUT request
DELETE Indicates that the following method will answer to a HTTP DELETE request
HEAD Indicates that the following method will answer to a HTTP HEAD request
&Produces Produces defines which MIME type is delivered by a method annotated with GET. In the example text ("text/html") is produced. Other examples would be "application/xml" or "application/json".
&Consumes Consumes defines which MIME type is consumed by this method.

Path Parameters

The framework supports path parameters, so that http://mydomain.local/myapp/orders/123 will be routed to this parametrized request handler:

&Path('orders/{orderId}')
GET
 (procedure(Request: TRequest; Response: TResponse)
  begin
    Response.ContentText :=
      Format('<html>Thank you for your order %s</html>',
        [Request.Params.Values['orderId']]);
  end);

Multiple path parameters are supported. For example, to handle a request for a specific order line, you could use

&Path('orders/{orderId}/lines/{lineNo');

or

&Path('orders/{orderId}/{lineNo');

If the server received a request for the URL

http://mydomain.local:8080/context/orders/65432/lines/1

the framework extracts the parameters (orderId=65432, lineNo=1) and adds them to the Request parameter list.

HTML Forms

HTML forms require a minimum of two event handlers - one to create the form when the browser sends the GET and one to handle the form input, which usually is sent with a POST request.

The example below shows all required code to build and process a simple form. First shown below is the GET handler, note the action attribute of the form element, which points to the URL of the POST event handler (action="form").

&Path('form');
GET
 (procedure(Request: TRequest; Response: TResponse)
  begin
    Response.ContentText := '<html>'
      + '<form action="form" method="POST">'
      + '  <input type="text" name="var" value="hello world" />'
      + '  <input type="submit" />'
      + '</form>'
      + '</html>';
  end);

The form handler, located at the path "form", receives the POST request and extracts the value of the "var" form parameter.

&Path('form');
POST
(procedure(Request: TRequest; Response: TResponse)
begin
  // store data
  Request.Session.Content.Values['Data'] :=
'var=' + Request.Params.Values['var'];
  // process data
  // ...
end);

Implementing the POST-Redirect-GET Pattern

The POST-Redirect-GET Pattern can be implemented with two simple changes

  • at the end of the POST handler, add a redirect command:
// redirect to thankyou handler
Response.Redirect('thankyou');
  • write a GET handler for the thankyou page
&Path('thankyou');
GET
(procedure(Request: TRequest; Response: TResponse)
begin
Response.ContentText := Format('<html>You entered: %s</html>',
[Request.Session.Content.Values['Data']]);
end);

Multiple Resource Representations

If a resource has more than one representation (HTML, XML or JSON), this can be handled using the same Path value but different MIME type Produces attributes:

// respond to HTML browsers
&Path('myresource');
&Produces('text/html');
GET(procedure(Request: TRequest; Response: TResponse)
    begin
      Response.ContentText :=
        '<html>Hello world!</html>';
    end);

// respond to XML client
&Path('myresource');
&Produces('application/xml');
GET(procedure(Request: TRequest; Response: TResponse)
    begin
      Response.ContentText := '<xml>Hello world!</xml>';
      Response.CharSet := 'utf-8';
end);

// respond to JSON client
&Path('myresource');
&Produces('application/json');
GET(procedure(Request: TRequest; Response: TResponse)
    begin
      Response.ContentText := '{"msg":"Hello world!"}';
      Response.CharSet := 'utf-8';
end);

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s