DevLearningTools

MODULE 14 · LESSON 02

Creating REST APIs

Building a real REST API in ColdFusion: the cfcomponent/cffunction REST attributes, path parameters, registering the service with restInitApplication, a full CRUD example, and a real Lucee-vs-Adobe difference in the registration call itself.

New lessons are added one at a time as the course gets built out — a graded quiz for each lesson is still on the way.

The previous lesson covered REST concepts generally. This one builds a real one: the CFC attributes that turn a component into a REST resource, registering it so ColdFusion actually knows it exists, and a complete CRUD example.

Learning Objectives

After completing this lesson, you'll be able to:

  • Turn a CFC into a REST resource with rest and restPath.
  • Expose functions as endpoints with httpMethod, produces, and consumes.
  • Accept a path parameter with restArgSource.
  • Register a REST service with restInitApplication, and know the real Lucee-vs-Adobe difference in that call.

How a Request Actually Reaches Your Code

CFC With rest="true"

restInitApplication() Registers It

/rest/[mapping]/[restPath]

Matching Function Runs

A Basic REST Component

CFScript
component rest="true" restPath="products" {

    remote array function getAllProducts() httpMethod="GET" produces="application/json" {
        return [
            { id: 1, name: "Laptop", price: 999.99 },
            { id: 2, name: "Smartphone", price: 499.99 }
        ];
    }

}

cfcomponent's REST Attributes

AttributeMeaning
restMarks the component as REST-enabled (true/false)
restPathThe base path this component's resources are exposed under, case-sensitive

cffunction's REST Attributes

AttributeMeaning
accessMust be remote to expose the function; as of ColdFusion 2018, it can be omitted entirely on a REST-enabled component
httpMethodget, post, put, delete, head, or options; defaults to GET
restPathA function-level sub-path, combined with the component's own restPath
producesComma-delimited MIME types this function can return; defaults to */*
consumesComma-delimited MIME types this function accepts from the client; defaults to */*
NOTE

produces and consumes each override the component-level setting when specified on an individual function.

A Real Example: A Path Parameter

CFScript
remote struct function getProductById(required numeric id restArgSource="Path")
    httpMethod="GET"
    restPath="{id}"
    produces="application/json" {

    return { id: arguments.id, name: "Sample Product", price: 0.00 };
}
NOTE

restArgSource="Path" (Path, Form, Query, or Header) tells ColdFusion where to pull the value from, matched against the argument's own name, id in this case, against the {id} placeholder in restPath.

Registering the Service: restInitApplication

Application.cfc
component {
    this.name = "MyRestAPIApp";

    public boolean function onApplicationStart() {
        restInitApplication(expandPath("./api"), "api_v1");
        return true;
    }
}
NOTE

Every CFC in the given folder (and subfolders) that's REST-enabled gets registered under the service mapping name, api_v1 here. If you change a CFC's methods later, you need to re-run restInitApplication or click Refresh in the ColdFusion Administrator for the change to take effect.

A Real Engine Difference: restInitApplication's Signature

AspectAdobe ColdFusionLucee
ParametersdirPath, serviceMappingdirPath, serviceMapping, default, password
Password requirementNot requiredRequires the web admin password as a parameter
NOTE

Code written for Adobe ColdFusion's simpler two-argument call needs the admin password added when porting to Lucee, it isn't optional there.

The URL Structure

NOTE

http://server/rest/[serviceMapping]/[restPath] — the /rest/ segment is ColdFusion's fixed servlet mapping, api_v1 (or whatever you chose) is the serviceMapping from restInitApplication, and products (or {id}) comes from the component and function-level restPath values.

A Real Example: A Complete CRUD Component

CFScript
component rest="true" restPath="products" {

    remote array function getAllProducts() httpMethod="GET" produces="application/json" {
        return productService.getAll();
    }

    remote struct function getProductById(required numeric id restArgSource="Path")
        httpMethod="GET" restPath="{id}" produces="application/json" {
        return productService.getById(arguments.id);
    }

    remote struct function createProduct(required string name restArgSource="Form", required numeric price restArgSource="Form")
        httpMethod="POST" produces="application/json" {
        return productService.create(arguments.name, arguments.price);
    }

    remote struct function updateProduct(required numeric id restArgSource="Path", required string name restArgSource="Form")
        httpMethod="PUT" restPath="{id}" produces="application/json" {
        return productService.update(arguments.id, arguments.name);
    }

    remote void function deleteProduct(required numeric id restArgSource="Path")
        httpMethod="DELETE" restPath="{id}" {
        productService.delete(arguments.id);
    }

}
NOTE

productService here stands in for your actual data-access logic (a separate CFC, a query, whatever the real implementation is), the point of this example is the REST attribute wiring, not the business logic behind it.

A Real Feature Worth Knowing: PATCH Support

NOTE

As of the ColdFusion 2018 release, httpMethod="PATCH" is supported for partial updates, but it requires a corresponding GET resource to already exist at the same path.

Beyond Native CFCs: Taffy and ColdBox

Native rest="true" CFCs work well for a straightforward API, but larger production APIs often reach for a dedicated framework instead: Taffy is a long-standing, lightweight REST framework built specifically for CFML, and ColdBox (with its Relax module) is the option if you're already using ColdBox's full MVC framework, covered later in this course. Both add built-in routing, authentication filtering, and custom status code handling that native CFCs leave you to build yourself.

Common Beginner Mistakes

Changing a REST CFC and expecting the change to appear immediately

ColdFusion scanned and registered the CFC when restInitApplication last ran. A code change needs restInitApplication re-run, or a manual Refresh in the ColdFusion Administrator, to actually take effect.

Assuming access="remote" is always required

As of ColdFusion 2018, it can be omitted entirely on a REST-enabled component's functions. Older code (or Lucee) may still need it set explicitly.

Mismatching the path placeholder and the argument name

restPath="{id}" has to match the actual argument name (id) that restArgSource="Path" is pulling from, a typo between them silently fails to bind.

Porting Adobe's two-argument restInitApplication call to Lucee unchanged

Lucee's version also requires the web admin password as a parameter, code written for Adobe's simpler signature needs that added.

Best Practices

  • Keep REST-enabled CFCs organized in a dedicated folder, matching what restInitApplication scans.
  • Set produces/consumes explicitly when content negotiation actually matters, rather than relying on the */* default everywhere.
  • Use restArgSource="Path" for identifiers and Form (or a JSON body) for created/updated payloads, matching how the data actually arrives.
  • Reach for Taffy or ColdBox/Relax once a native-CFC API's routing and auth needs start outgrowing what rest="true" alone comfortably handles.

Interview Questions

What two attributes turn a CFC into a REST resource?

rest="true" and restPath on the cfcomponent tag (or component syntax).

What does restArgSource control, and what are its possible values?

Where a function argument's value comes from: Path, Form, Query, or Header, matched against the argument's own name.

Why might a code change to a REST CFC not show up when you call the endpoint?

The service was registered by restInitApplication at an earlier point. Re-running it, or clicking Refresh in the ColdFusion Administrator, is needed for the change to actually take effect.

What's a real, concrete difference between Adobe's and Lucee's restInitApplication?

Lucee's version requires the web admin password as a parameter; Adobe's simpler two-argument form (dirPath, serviceMapping) doesn't need one at all.

Summary

In this lesson, you turned a CFC into a REST resource, exposed functions with httpMethod/produces/consumes, accepted a path parameter with restArgSource, registered the service with restInitApplication, built a complete CRUD example, and covered a real Lucee-vs-Adobe difference in that registration call.

What's Next?

The next lesson covers consuming APIs, calling an external REST service from ColdFusion with cfhttp.

MORE IN APIS & MODERN DEVELOPMENT