# REST Compat +

## BoxLang REST Compatibility Module

A comprehensive CFML RESTful services compatibility module for BoxLang that provides compatibility for the CFML REST specification including routing and serialization

### Overview

This module provides CFML-compatible REST services for BoxLang web applications, supporting:

* **RESTful Service Discovery & Registration**: Automatic discovery and registration of REST-enabled CFCs
* **Intelligent Routing**: Path-based routing with support for path parameters, query strings, and HTTP method matching
* **Content Negotiation**: Automatic serialization/deserialization based on Accept and Content-Type headers
* **OpenAPI Documentation**: Auto-generated OpenAPI 3.0 documentation for all registered services
* **CF-Compatible BIFs**: `restInitApplication`, `restSetResponse`, `restDeleteApplication`
* **Multiple HTTP Methods**: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
* **Rich Annotations Support**: All standard CF REST annotations including `httpMethod`, `produces`, `consumes`, `restPath`, `restArgSource`

### Installation

#### Add a servlet pass predicate which will match your default entry prefix in the `web` section of your `server.json`

```
"web":{
	"servletPassPredicate":"regex( '^/(.+?\\.cf[cms])(/.*)?$' ) or regex( '^/(.+?\\.bx[sm])(/.*)?$' ) or path-prefix-nocase( /rest/ )",
	...
}
```

#### Add a [web.xml override](https://commandbox.ortusbooks.com/embedded-server/configuring-your-server/web.xml-overrides) to your `server.json` to allow the servlet to pass REST routes to BoxLang

Place the following in a file ( for example `.rest-override.xml` ). Note the presence of the XML namespaces. They are required.

```
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" metadata-complete="true" version="5.0" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd">
    <servlet-mapping>
        <servlet-name>BoxLangServlet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>
</web-app>
```

Then update your `server.json` to point to your override file - which will append to the existing servlet mappings

```
"app" : {
	"webXMLOverride" : "./.rest-override.xml",
	...
}

```

#### Update your server file to install the module on your initial server start

`server.json` scripts block:

```
"scripts" : {
	"onServerInitialInstall" : "install bx-plus,bx-compat-rest",
	...
}
```

#### Start your server and go!

### Configuration

The following configuration items are supported and can be configured in the `modules` block of your `boxlang.json` or `.cfconfig.json` file:

```json
"bx-compat-rest":{
	"settings":{
		// The entry prefix to use for all rest applications
		"entryPrefix" : "/rest/",
		// A struct containing the service name and fully expanded route to the directory containing the REST classes
		"applications":{
			// Key-value pairs
			"api":"/home/resty/my/rest/api/classes",
			// Key with struct to specify default application
			"resty" : {
				"path" : "/home/resty/my/rest/defaultAPI",
				"default" : true
			}
		}
	}
}
```

### Quick Start

#### 1. Create a REST-Enabled Component

```java
// HelloService.bx
component rest="true" restPath="hello" {
    
    remote string function sayHello() httpMethod="GET" produces="application/json" {
        return "Hello, World!";
    }
    
    remote string function sayHelloTo(
        required string name restArgSource="Path"
    ) httpMethod="GET" restPath="{name}" produces="application/json" {
        return "Hello, #arguments.name#!";
    }
}
```

#### 2. Register Your REST Application

In your `Application.cfc`:

```java
component {
    this.name = "MyRESTApp";
    
    // Register REST application on startup
    function onApplicationStart() {
        restInitApplication(
            expandPath("./services"),  // Directory containing REST CFCs
            "api"                       // Service mapping name
        );
    }
}
```

#### 3. Access Your REST Endpoints

```
GET  /rest/api/hello
GET  /rest/api/hello/John
```

### Built-in Functions (BIFs)

#### restInitApplication()

Registers a REST application directory.

```java
restInitApplication(
    rootPath,      // Required: Directory containing REST CFCs
    serviceName,   // Optional: Service name/mapping
    options        // Optional: Struct with host, useHost, isDefault
)
```

Example:

```java
restInitApplication(expandPath("./api"), "myapi", {
    "host": "api.example.com",
    "isDefault": true
});
```

#### restSetResponse()

Sets a custom HTTP response with status, content, and headers.

```java
restSetResponse({
    "status": 201,
    "content": {"id": 123, "message": "Created"},
    "headers": {"Location": "/api/resource/123"}
});
```

#### restDeleteApplication()

Removes a registered REST application.

```java
restDeleteApplication("myapi");
```

### OpenAPI Documentation

Access auto-generated OpenAPI 3.0 documentation:

```
GET /bxrest/public/RestController.bx?method=docs
```

The documentation includes:

* All registered services and routes
* HTTP methods and paths
* Request parameters and their types
* Response schemas
* Content types (produces/consumes)

### Advanced Features

#### Path Parameters

```java
remote function getUser(
    required numeric id restArgSource="Path"
) httpMethod="GET" restPath="users/{id}" {
    return getUserById(arguments.id);
}
```

Access as: `/api/users/123`

#### Custom HTTP Status Codes

```java
remote function createUser(
    required string name restArgSource="Form"
) httpMethod="POST" {
    var newUser = saveUser(arguments.name);
    
    restSetResponse({
        "status": 201,
        "content": newUser,
        "headers": {"Location": "/api/users/" & newUser.id}
    });
    
    return newUser;
}
```

#### Content Negotiation

The module automatically handles content negotiation based on:

* `Accept` header for responses
* `Content-Type` header for requests

Supported formats:

* `application/json`, `text/json`
* `application/xml`, `text/xml`
* `application/x-www-form-urlencoded`
* `multipart/form-data`
* `text/plain`

#### Error Handling

```java
remote function getUser(required numeric id restArgSource="Path") {
    if (!userExists(id)) {
		restSetResponse( 
			{
				"status" : 404,
				"content" : "User not found"
			}
		);
		return;
    }
    return getUser By(id);
}
```

The module automatically returns appropriate HTTP status codes:

* 200 OK - Successful response with body
* 204 No Content - Successful response without body
* 400 Bad Request - Missing required parameters
* 404 Not Found - No matching route
* 405 Method Not Allowed - HTTP method not supported for route
* 406 Not Acceptable - Cannot produce requested content type
* 415 Unsupported Media Type - Cannot consume request content type
* 500 Internal Server Error - Exception during processing

### Compatibility

This module implements the CFML RESTful services specification as documented in: <https://helpx.adobe.com/CFML/developing-applications/changes-in-CFML/restful-web-services-in-CFML.html>

Supported features:

* ✅ REST component and function annotations
* ✅ HTTP method binding
* ✅ Path parameters and routing
* ✅ Content negotiation
* ✅ JSON and XML serialization
* ✅ Custom responses
* ✅ Parameter sources (Path, Query, Form, Header, Cookie, Body)
* ✅ restInitApplication, restSetResponse, restDeleteApplication BIFs
* ⚠️ Subresource locators (partial - basic implementation complete)
* ⚠️ Custom serializers (not yet implemented)

***

**Ortus Solutions, Corp** <https://www.ortussolutions.com>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://boxlang.ortusbooks.com/boxlang-+-++/modules/rest-compat-+.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
