Definition
Yes. ColdFusion (CFML), including Adobe ColdFusion and Lucee, can connect to REST APIs. You do this by making HTTP requests (GET, POST, PUT, DELETE, etc.) to RESTful endpoints using built-in Features like the cfhttp tag or its script equivalents, and by handling JSON or XML payloads with the platform’s native serialization and deserialization functions.
How It Works
The core building blocks
- cfhttp and cfhttpparam
- Tag-based:
sends the request; adds headers, query strings, bodies, and file uploads. - Script-based: Use cfhttp(…) { cfhttpparam(…) } or the HTTP component (new http()) with addParam() and send().
- Tag-based:
- JSON handling
- serializeJSON() to convert CFML structs/arrays into JSON for request bodies.
- deserializeJSON() to parse API responses into native CFML Data structures.
- HTTP response access
- Status codes and reason phrases via cfhttp.result.statusCode (e.g., “200 OK”).
- Body content via cfhttp.result.fileContent.
- Headers via cfhttp.result.responseHeader.
Authentication patterns and headers
- API key: Add to header (e.g., X-API-Key) or as a query param.
- Bearer token / JWT: Authorization: Bearer
. - Basic auth: Base64-encoded username:password as a header.
- OAuth 2.0: Obtain access token via a token endpoint; refresh token when expired.
- HMAC signatures: Compute and send signature headers as required by the provider.
Always send the correct Content-Type and Accept headers (e.g., application/json).
Data formats and HTTP verbs
- Formats: JSON is most common; XML and multipart/form-data are also supported.
- Verbs: GET for reads, POST for creating/commands, PUT/PATCH for updates, DELETE for removals.
- Query parameters vs body:
- GET uses query string.
- POST/PUT often sends a JSON body.
Step-by-Step Example
Example: GET data with cfhttp (GitHub API)
This example retrieves metadata for a public repository. GitHub requires a User-Agent header and accepts optional bearer tokens for higher rate limits.
- Tag-based
<cfif left(res.statusCode, 3) EQ “200”>
Repo: #repo.full_name# — Stars: #repo.stargazers_count#
Error: #res.statusCode#
- Script-based
cfhttp(
method=”get”,
url=”https://api.github.com/repos/adobe/coldfusion“,
result=”res”,
timeout=30,
charset=”utf-8″
){
cfhttpparam(type=”header”, name=”User-Agent”, value=”CFML-Client”);
cfhttpparam(type=”header”, name=”Accept”, value=”application/vnd.github+json”);
// cfhttpparam(type=”header”, name=”Authorization”, value=”Bearer #accessToken#”);
}
if ( left(res.statusCode,3) == “200” ) {
repo = deserializeJSON(res.fileContent);
writeOutput(“
Repo: #repo.full_name#
“);
} else {
writeOutput(“
Error: #res.statusCode#
“);
}
Example: POST JSON in CFScript
payload = {
name = “example”,
active = true
};
req = new http();
req.setUrl(“https://api.example.com/v1/resources“);
req.setMethod(“post”);
req.addParam(type=”header”, name=”Content-Type”, value=”application/json”);
req.addParam(type=”header”, name=”Authorization”, value=”Bearer #accessToken#”);
req.addParam(type=”body”, value=serializeJSON(payload));
res = req.send();
if ( left(res.statusCode,3) == “201” ) {
data = deserializeJSON(res.fileContent);
writeOutput(“Created ID: ” & data.id);
} else {
writeOutput(“API error: ” & res.statusCode & ” — ” & res.fileContent);
}
Handling errors, timeouts, and retry logic
- Set timeouts: Use timeout on cfhttp/new http().
- Check status codes: Consider 2xx success, 4xx client errors, 5xx server errors.
- Retry safely:
- Retry idempotent verbs (GET, sometimes PUT) on transient failures (429, 503).
- Respect Retry-After headers.
- Wrap parsing:
- Use try/catch around deserializeJSON to avoid breaking on invalid JSON responses.
Real-World Use Case: Payment Gateway Integration
Scenario: A ColdFusion web app charges customers via Stripe’s REST API and stores the result.
- Steps
- Collect payment intent details on the frontend.
- On the server, call Stripe’s /v1/payment_intents endpoint via cfhttp with Authorization: Bearer
. - Deserialize JSON, update order records, and return a response to the UI.
- Considerations
- Use HTTPS and secure the Stripe secret in environment variables.
- Handle idempotency keys to safely retry POST requests.
- Log request IDs returned by Stripe for auditability.
The same pattern applies to shipping APIs (e.g., Shippo), email providers (SendGrid), and CRM integrations (HubSpot, Salesforce REST).
Best practices
Security and Compliance
- Never hardcode credentials; load from environment variables or secure secrets storage.
- Validate SSL/TLS:
- Keep the JVM up to date for modern ciphers and TLS versions.
- Import vendor certificates into the JVM truststore when necessary.
- Use the least privilege:
- Scope API keys to specific permissions.
- Prefer short-lived OAuth 2.0 tokens; refresh when needed.
- Sanitize logs:
- Mask tokens and PII; log only necessary metadata.
- Enforce input/output validation to prevent injection or deserialization issues.
Performance and Scalability
- Caching:
- Cache GET responses with cachePut/cacheGet when appropriate.
- Use ETag/If-None-Match or If-Modified-Since headers to reduce bandwidth.
- Connection management:
- Set reasonable timeouts (connect/read).
- Use asynchronous calls via cfthread for parallel requests.
- Pagination:
- Implement cursors or page parameters to avoid fetching huge datasets at once.
- Rate limiting:
- Inspect 429 responses; implement exponential backoff.
- Throttle requests when approaching provider limits.
Observability and maintainability
- Structured logging:
- Log URL (without secrets), method, status code, latency, correlation IDs.
- Centralized Error handling:
- Wrap API calls in utility functions/components to standardize headers, retries, and error shapes.
- Contract tests:
- Validate payloads against expected schemas; flag breaking changes early.
Troubleshooting and Common pitfalls
- SSL/Certificate errors:
- Update the JVM cacerts truststore with the API provider’s certificate chain if trust fails.
- Ensure TLS 1.2+ is supported by your JVM.
- Content-Type mismatches:
- If API expects application/json, always set the header and send a JSON-encoded body.
- Character encoding:
- Set charset=”utf-8″ on cfhttp and ensure proper encoding when dealing with non-ASCII text.
- Proxy/firewall issues:
- Configure proxy settings in cfhttp or server-level network settings when required.
- JSON parsing failures:
- Not all APIs return JSON on errors; check Content-Type before deserializing or use try/catch.
Comparing Approaches
cfhttp vs new http() vs CFScript function Syntax
- cfhttp tag
- Simple, declarative, easy to read in tag-based templates.
- Widely documented and supported on Adobe CF and Lucee.
- new http() (HTTP component)
- Good for programmatic control, reuse, and Unit testing in CFScript.
- Clean for building dynamic requests with methods like addParam().
- CFScript tag-function form (cfhttp(…) { … })
- Best of both worlds when you prefer script but want tag semantics.
All three rely on the same underlying HTTP semantics. Choose what fits your codebase style and team familiarity.
Consuming vs exposing REST with ColdFusion
- Consuming (client):
- Use cfhttp/new http() as shown.
- Exposing (server):
- Adobe ColdFusion can expose RESTful services using CFCs: component rest=”true”, restPath, httpMethod, produces/consumes.
- Initialize with restInitApplication() and map a REST path.
- Lucee supports REST via extensions or frameworks (e.g., ColdBox, Taffy).
Key Takeaways
- ColdFusion fully supports consuming REST APIs using cfhttp and CFScript equivalents.
- JSON handling is first-class: serializeJSON/deserializeJSON make payload processing straightforward.
- Secure your credentials, enforce TLS, and implement retries, caching, and pagination for robustness.
- Standardize your HTTP client logic to simplify Authentication, headers, logging, and Error handling.
- CFML can both consume and expose RESTful services, making ColdFusion a capable Integration platform.
FAQ
Can ColdFusion handle OAuth 2.0 for REST APIs?
Yes. You can obtain access tokens by calling the provider’s token endpoint with cfhttp, then include Authorization: Bearer
How do I send multipart/form-data (file uploads) from ColdFusion?
Use cfhttpparam with type=”file” for file parts and type=”formField” for other fields. Set the method to POST and omit Content-Type; cfhttp will set the multipart boundary automatically.
What’s the easiest way to parse JSON responses?
Use deserializeJSON(res.fileContent) to convert the JSON string into CFML structs/arrays. Wrap it in try/catch in case the API returns non-JSON error bodies.
Is there a difference between Adobe ColdFusion and Lucee for cfhttp?
Both support cfhttp and cfhttpparam with largely compatible behavior. Differences may appear in defaults, SSL handling, and edge-case headers. Test on your target engine and version, especially for TLS and proxy scenarios.
How can I speed up multiple API calls in ColdFusion?
Run them in parallel using cfthread or a task framework, cache repeated GET results, and leverage provider pagination to fetch data in batches. Always respect API rate limits and implement backoff on 429/5xx responses.
