Data & Services - REST Services
Register and manage RESTful web services in ColdFusion
Overview
The REST Services section in ColdFusion Administrator allows you to register, configure, and manage RESTful web services created with ColdFusion components (CFCs). REST services provide a lightweight, HTTP-based API for client applications to interact with your ColdFusion backend.
REST Service Registration
Configure REST services by mapping virtual paths to ColdFusion component directories.
Service Name
- Purpose
- Unique identifier for the REST service
- Format
- Alphanumeric string, no spaces
Used in API URLs and administrator interface to identify the service.
Service Mapping
- Purpose
- Virtual directory path for REST endpoints
- Example
/rest/api
URL path prefix for accessing REST endpoints (e.g., https://example.com/rest/api/users)
Physical Path
- Purpose
- File system location of REST CFCs
- Example
/var/www/myapp/api
Directory containing REST-enabled CFC files with remote access="remote" methods.
Active Status
- Purpose
- Enable or disable the REST service
- Default
- Enabled when registered
Deactivate services without removing registration - useful for maintenance windows.
Creating REST CFCs
Build RESTful web services using ColdFusion components with REST annotations.
Basic REST CFC Example
Simple REST service demonstrating GET, POST, PUT, and DELETE operations:
component restpath="/users" rest="true" {
// GET /rest/api/users
remote array function getUsers()
httpmethod="GET"
restpath=""
produces="application/json" {
var users = queryExecute("SELECT * FROM users");
return queryToArray(users);
}
// GET /rest/api/users/{id}
remote struct function getUser(required numeric id)
httpmethod="GET"
restpath="/{id}"
produces="application/json" {
var user = queryExecute(
"SELECT * FROM users WHERE id = :id",
{id: arguments.id}
);
if (user.recordCount == 0) {
restSetResponse({
status: 404,
content: {error: "User not found"}
});
return {};
}
return queryRowToStruct(user, 1);
}
// POST /rest/api/users
remote struct function createUser(
required string name,
required string email
)
httpmethod="POST"
restpath=""
produces="application/json" {
// Validate input
if (!isValid("email", arguments.email)) {
restSetResponse({
status: 400,
content: {error: "Invalid email address"}
});
return {};
}
var result = queryExecute(
"INSERT INTO users (name, email) VALUES (:name, :email)",
{name: arguments.name, email: arguments.email}
);
restSetResponse({
status: 201,
content: {message: "User created successfully"}
});
return {id: result.generatedKey, name: arguments.name, email: arguments.email};
}
// PUT /rest/api/users/{id}
remote struct function updateUser(
required numeric id,
required string name,
required string email
)
httpmethod="PUT"
restpath="/{id}"
produces="application/json" {
queryExecute(
"UPDATE users SET name = :name, email = :email WHERE id = :id",
{id: arguments.id, name: arguments.name, email: arguments.email}
);
return {id: arguments.id, name: arguments.name, email: arguments.email};
}
// DELETE /rest/api/users/{id}
remote struct function deleteUser(required numeric id)
httpmethod="DELETE"
restpath="/{id}"
produces="application/json" {
queryExecute("DELETE FROM users WHERE id = :id", {id: arguments.id});
restSetResponse({
status: 200,
content: {message: "User deleted successfully"}
});
return {};
}
// Helper function to convert query row to struct
private struct function queryRowToStruct(required query qry, required numeric row) {
var result = {};
for (var col in listToArray(arguments.qry.columnList)) {
result[col] = arguments.qry[col][arguments.row];
}
return result;
}
// Helper function to convert query to array of structs
private array function queryToArray(required query qry) {
var result = [];
for (var i = 1; i <= arguments.qry.recordCount; i++) {
arrayAppend(result, queryRowToStruct(arguments.qry, i));
}
return result;
}
}<cfcomponent restpath="/users" rest="true">
<!--- GET /rest/api/users --->
<cffunction name="getUsers" access="remote" returntype="array"
httpmethod="GET" restpath="" produces="application/json">
<cfquery name="users">
SELECT * FROM users
</cfquery>
<cfreturn queryToArray(users)>
</cffunction>
<!--- GET /rest/api/users/{id} --->
<cffunction name="getUser" access="remote" returntype="struct"
httpmethod="GET" restpath="/{id}" produces="application/json">
<cfargument name="id" type="numeric" required="true">
<cfquery name="user">
SELECT * FROM users
WHERE id = <cfqueryparam value="#arguments.id#" cfsqltype="cf_sql_integer">
</cfquery>
<cfif user.recordCount eq 0>
<cfset restSetResponse({
status: 404,
content: {error: "User not found"}
})>
<cfreturn {}>
</cfif>
<cfreturn queryRowToStruct(user, 1)>
</cffunction>
<!--- POST /rest/api/users --->
<cffunction name="createUser" access="remote" returntype="struct"
httpmethod="POST" restpath="" produces="application/json">
<cfargument name="name" type="string" required="true">
<cfargument name="email" type="string" required="true">
<!--- Validate input --->
<cfif NOT isValid("email", arguments.email)>
<cfset restSetResponse({
status: 400,
content: {error: "Invalid email address"}
})>
<cfreturn {}>
</cfif>
<cfquery name="result" result="insertResult">
INSERT INTO users (name, email)
VALUES (
<cfqueryparam value="#arguments.name#" cfsqltype="cf_sql_varchar">,
<cfqueryparam value="#arguments.email#" cfsqltype="cf_sql_varchar">
)
</cfquery>
<cfset restSetResponse({
status: 201,
content: {message: "User created successfully"}
})>
<cfreturn {
id: insertResult.generatedKey,
name: arguments.name,
email: arguments.email
}>
</cffunction>
<!--- PUT /rest/api/users/{id} --->
<cffunction name="updateUser" access="remote" returntype="struct"
httpmethod="PUT" restpath="/{id}" produces="application/json">
<cfargument name="id" type="numeric" required="true">
<cfargument name="name" type="string" required="true">
<cfargument name="email" type="string" required="true">
<cfquery>
UPDATE users
SET name = <cfqueryparam value="#arguments.name#" cfsqltype="cf_sql_varchar">,
email = <cfqueryparam value="#arguments.email#" cfsqltype="cf_sql_varchar">
WHERE id = <cfqueryparam value="#arguments.id#" cfsqltype="cf_sql_integer">
</cfquery>
<cfreturn {
id: arguments.id,
name: arguments.name,
email: arguments.email
}>
</cffunction>
<!--- DELETE /rest/api/users/{id} --->
<cffunction name="deleteUser" access="remote" returntype="struct"
httpmethod="DELETE" restpath="/{id}" produces="application/json">
<cfargument name="id" type="numeric" required="true">
<cfquery>
DELETE FROM users
WHERE id = <cfqueryparam value="#arguments.id#" cfsqltype="cf_sql_integer">
</cfquery>
<cfset restSetResponse({
status: 200,
content: {message: "User deleted successfully"}
})>
<cfreturn {}>
</cffunction>
<!--- Helper function to convert query row to struct --->
<cffunction name="queryRowToStruct" access="private" returntype="struct">
<cfargument name="qry" type="query" required="true">
<cfargument name="row" type="numeric" required="true">
<cfset var result = {}>
<cfloop list="#arguments.qry.columnList#" index="col">
<cfset result[col] = arguments.qry[col][arguments.row]>
</cfloop>
<cfreturn result>
</cffunction>
<!--- Helper function to convert query to array of structs --->
<cffunction name="queryToArray" access="private" returntype="array">
<cfargument name="qry" type="query" required="true">
<cfset var result = []>
<cfloop from="1" to="#arguments.qry.recordCount#" index="i">
<cfset arrayAppend(result, queryRowToStruct(arguments.qry, i))>
</cfloop>
<cfreturn result>
</cffunction>
</cfcomponent>rest="true"- Enable REST functionality on the componentrestpath="/users"- Base URL path for the resourcehttpmethod="GET|POST|PUT|DELETE"- HTTP method for the functionrestpath="/{id}"- URL parameters in curly bracesproduces="application/json"- Response content typeconsumes="application/json"- Request content type (optional)
Security Best Practices
Essential security measures for production REST APIs.
Always Use HTTPS
Implement Authentication
API Keys: Simple key-based authentication
OAuth 2.0: Industry-standard for third-party access
- Use JWT tokens with short expiration times (15-60 minutes)
- Implement refresh token rotation for long-lived sessions
- Store API keys securely - never commit to version control
- Rate limit failed authentication attempts
Input Validation & Sanitization
cfqueryparam for database queriesValidate data types with
isValid()Sanitize HTML output with
encodeForHTML()Whitelist allowed values instead of blacklisting
Rate Limiting
Unauthenticated: 100 requests/hour
Failed logins: 5 attempts per 15 minutes
CORS Configuration
Access-Control-Allow-Origin: * for APIs with authenticationHTTP Status Codes
201 Created: Successful POST creating new resource
400 Bad Request: Invalid input parameters
401 Unauthorized: Missing or invalid authentication
403 Forbidden: Valid auth but insufficient permissions
404 Not Found: Resource does not exist
500 Internal Server Error: Server-side error
restSetResponse() - don't rely on defaults.