Code-on-Demand in REST — The Optional Constraint for Extensible APIs
In this tutorial, you will learn about Code. We cover key concepts, practical examples, and best practices to help you master this topic.
Code-on-demand is the only optional REST constraint, allowing servers to transfer executable code or scripts to clients to extend functionality dynamically, as seen in JavaScript, Java applets, and WebAssembly.
What You'll Learn
- What code-on-demand means in REST
- When and why to use code-on-demand
- Security considerations for executable code transfer
Why It Matters
Code-on-demand lets you update client behavior without deploying new client software. A form validation script, a chart rendering library, or a business rule can be fetched from the server at runtime, enabling continuous deployment to browser-based clients.
Real-World Use
DodaTech's dashboard API includes code-on-demand for chart rendering. The API returns data plus a reference to a client-side JavaScript library for rendering. When the rendering logic changes, only the server-side script is updated. All clients automatically get the new behavior.
flowchart LR
A["Client\nBrowser"] -->|"GET /api/dashboard"| B["API Server"]
B -->|"JSON data\n+ script URL"| A
A -->|"GET /scripts/chart.js"| C["Script Server"]
C -->|"Rendering\nlibrary"| A
A --> D["Browser renders\nchart locally"]
style B fill:#dbeafe,stroke:#2563eb
style C fill:#fef3c7,stroke:#d97706
Server-Side Script Provision
from flask import Flask, jsonify, send_file, request
app = Flask(__name__)
# API endpoint that returns data and a script reference
@app.route('/api/dashboard')
def get_dashboard():
user_id = get_authenticated_user()
data = get_dashboard_data(user_id)
return jsonify({
"data": data,
"scripts": [
{
"url": "/scripts/chart-renderer.js",
"version": "2.1.0",
"integrity": "sha384-abc123...",
"type": "text/javascript"
},
{
"url": "/scripts/data-transformer.js",
"version": "1.0.5",
"integrity": "sha384-def456..."
}
],
"styles": [
{
"url": "/styles/dashboard.css",
"version": "1.0.0"
}
]
})
# Serve the executable scripts
@app.route('/scripts/<path:script_name>')
def get_script(script_name):
script_path = f"/opt/app/scripts/{script_name}"
response = send_file(script_path, mimetype='text/javascript')
response.headers['Cache-Control'] = 'public, max-age=3600'
response.headers['Content-Security-Policy'] = "script-src 'self'"
return response
Client-Side Script Loading
// Client dynamically loads scripts from the API
async function renderDashboard() {
const response = await fetch('/api/dashboard');
const dashboard = await response.json();
// Load required scripts dynamically
for (const script of dashboard.scripts) {
await loadScript(script.url, script.integrity);
}
// Load styles
for (const style of dashboard.styles) {
await loadStyle(style.url);
}
// Execute chart rendering (code-on-demand)
if (typeof renderChart !== 'undefined') {
renderChart(dashboard.data, '#chart-container');
}
}
function loadScript(url, integrity) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.src = url;
script.integrity = integrity;
script.crossOrigin = 'anonymous';
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
Security with Subresource Integrity
import hashlib
import base64
def compute_integrity(filepath):
"""Compute SHA-384 hash for subresource integrity"""
with open(filepath, 'rb') as f:
content = f.read()
digest = hashlib.sha384(content).digest()
b64_hash = base64.b64encode(digest).decode()
return f"sha384-{b64_hash}"
# Generate integrity hashes for all scripts
scripts = {
"chart-renderer.js": compute_integrity("/opt/app/scripts/chart-renderer.js"),
"data-transformer.js": compute_integrity("/opt/app/scripts/data-transformer.js")
}
for name, integrity in scripts.items():
print(f"{name}: {integrity}")
Common Mistakes
1. Requiring JavaScript for API Functionality
Code-on-demand is optional. Your API must work without executing any transferred code. Only enhance functionality with scripts.
2. Not Using Subresource Integrity
Without SRI hashes, an attacker who compromises the script server can inject malicious code. Always include integrity hashes.
3. Mixing Code and Data in Responses
Returning executable code mixed with JSON data creates security risks. Separate data (JSON) from scripts (JavaScript files).
4. Ignoring CSP (Content Security Policy)
If your clients use CSP, transferred scripts must be allowed by the policy. Set appropriate script-src directives.
5. Not Versioning Scripts
Without versioning in script URLs, cached scripts may conflict with updated API responses. Use versioned URLs.
Practice Questions
- Is code-on-demand a mandatory REST constraint?
- What is subresource integrity and why is it important?
- How do you separate code from data in a REST response?
- Why must the API work without executing transferred code?
- How do you version scripts for code-on-demand?
Answers
- No, it is the only optional REST constraint. 2. A hash that verifies the script hasn't been tampered with. 3. Return data in JSON, script URLs as metadata, not embedded code. 4. Because code-on-demand is optional and may not be supported by all clients. 5. Include version identifiers in script URLs or use content-based hashes.
Challenge
Build an API that demonstrates code-on-demand: a report generation endpoint returns data plus a reference to a client-side rendering script. The script version is determined by the API, and different API versions may return different script versions. Include SRI hashes and CSP headers.
FAQ
Mini Project
Build a dynamic dashboard API that uses code-on-demand: the API endpoint returns dashboard data and references to chart rendering scripts, scripts are served with versioned URLs and SRI hashes, clients dynamically load and execute scripts, and the API continues to work without executing any scripts (returns raw data for non-JS clients).
What's Next
- Learn about resource naming conventions for consistent URI design
- Explore resource relationships and sub-resources
- Continue to HTTP methods reference for RESTful CRUD operations
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro