HTTP Cloud Function Routing
Based on the @cloudbase/functions-framework framework, you can split a large function into multiple sub-functions and route different requests to different handler functions through request paths
Why Function Routing is Needed
In traditional cloud function development models, each function needs to be deployed and run independently, which brings the following problems:
- Resource Waste: Each function occupies a dedicated instance and needs to keep running even with small request volumes
- Frequent Cold Starts: More functions mean more cold start instances
- Complex Deployment: Need to deploy and manage multiple functions separately
- Higher Costs: More instances lead to higher resource costs
Using function routing can solve these problems:
- Resource Sharing: Multiple functions share the same instance, fully utilizing computing resources
- Cost Reduction: Reduce instance count and cold start frequency
- Simplified Deployment: Deploy multiple functions at once with unified management
- Performance Improvement: Share resources like memory and connection pools to improve response speed
Prerequisites
Using function routing requires installing the @cloudbase/functions-framework dependency:
npm install @cloudbase/functions-framework
This framework provides core capabilities such as function loading, route distribution, and request handling.
Quick Start
Step 1: Create Project Structure
Create a project directory that supports multiple functions:
my-functions/
├── package.json # Project configuration
├── scf_bootstrap # Bootstrap script
├── cloudbase-functions.json # Function routing configuration (key)
├── index.js # Default function entry
├── user/ # user function directory
│ └── index.js
└── order/ # order function directory
└── index.js
Step 2: Create Function Code
Default Function (index.js):
exports.main = function (event, context) {
return {
message: 'Hello from default function',
path: context.httpContext.url,
};
};
user Function (user/index.js):
exports.main = function (event, context) {
return {
message: 'User API',
path: context.httpContext.url,
method: context.httpContext.httpMethod,
};
};
order Function (order/index.js):
exports.main = function (event, context) {
return {
message: 'Order API',
path: context.httpContext.url,
};
};
Step 3: Configure Function Routing
Create a cloudbase-functions.json configuration file:
{
"functionsRoot": ".",
"functions": [
{
"name": "default",
"directory": "."
},
{
"name": "user",
"directory": "user",
"triggerPath": "/api/user" // triggerPath is the simplified write method of routes, which can directly specify the trigger path in the function definition
},
{
"name": "order",
"directory": "order",
"triggerPath": "/api/order"
}
],
"routes": [
{
"functionName": "echo",
"path": "/echo"
}
]
}
Step 4: Configure package.json
{
"name": "my-functions",
"version": "1.0.0",
"main": "index.js",
"dependencies": {
"@cloudbase/functions-framework": "latest"
}
}
Step 5: Create Bootstrap Script
Create a scf_bootstrap file (without extension):
#!/bin/bash
node node_modules/@cloudbase/functions-framework/bin/tcb-ff.js \
--port=9000 \
--logDirname=/tmp/logs \
--interceptOutput=false \
--extendedContextKey=X-Cloudbase-Context \
--functionsConfigFile=cloudbase-functions.json
⚠️ Important: The
scf_bootstrapfile needs to have executable permissions. On Linux/macOS systems, use thechmod +x scf_bootstrapcommand to set permissions.
Bootstrap Parameters:
| Parameter | Description | Default Value |
|---|---|---|
--port | Function listening port | 9000 |
--logDirname | Log storage directory | /tmp/logs |
--interceptOutput | Whether to intercept standard output | false |
--extendedContextKey | Extended context request header key name | X-Cloudbase-Context |
--functionsConfigFile | Function routing configuration file path | cloudbase-functions.json |
Step 6: Install Dependencies
npm install
Step 7: Local Testing
Start the function service:
./scf_bootstrap
Test different routes:
# Test default function
curl http://localhost:9000/
# Test user function
curl http://localhost:9000/api/user
# Test order function
curl http://localhost:9000/api/order
Step 8: Deploy to Cloud
Deploy the function using CloudBase CLI or console, then access after deployment:
# Default function
https://your-function.run.tcloudbase.com/
# user function
https://your-function.run.tcloudbase.com/api/user
# order function
https://your-function.run.tcloudbase.com/api/order
Route Matching Rules
Understanding route matching rules is crucial for correctly configuring function routing:
1. Prefix Matching
Route matching uses prefix matching mode. When a request path starts with a route rule's path, it can match that route.
Example:
{
"routes": [
{
"functionName": "user",
"path": "/api/user"
}
]
}
The following request paths will all match the user function:
/api/user✅/api/user/✅/api/user/profile✅/api/user/list✅
The following request paths will not match:
/api/users❌ (does not start with/api/user)/api❌ (path incomplete)
2. Longest Match
When multiple route rules can match the same request path, the framework will select the longest route rule.
Example:
{
"routes": [
{
"functionName": "user",
"path": "/api/user"
},
{
"functionName": "userProfile",
"path": "/api/user/profile"
}
]
}
Routing results:
/api/user→userfunction/api/user/list→userfunction/api/user/profile→userProfilefunction (longest match)/api/user/profile/detail→userProfilefunction (longest match)
3. Trailing Slash Handling
The trailing / in paths does not affect matching results; /api/user and /api/user/ are considered equivalent.
Example:
{
"routes": [
{
"functionName": "user",
"path": "/api/user"
}
]
}
The following paths will all match:
/api/user✅/api/user/✅
4. Path Unit Exact Matching
Route matching splits paths by / into path units, and each path unit requires exact matching.
Example:
{
"routes": [
{
"functionName": "user",
"path": "/api/user"
}
]
}
Routing results:
/api/user✅/api/users❌ (usersdoes not matchuser)/api/user123❌ (user123does not matchuser)
5. One Function Multiple Routes
A function can be configured with multiple trigger paths, accessing the same function from different URL paths.
Example:
{
"routes": [
{
"functionName": "user",
"path": "/api/user"
},
{
"functionName": "user",
"path": "/v1/user"
},
{
"functionName": "user",
"path": "/v2/user"
}
]
}
All three paths above will route to the user function.
6. One Route One Function
The same path can only point to one function and cannot point to multiple functions simultaneously.
Error Example:
{
"routes": [
{
"functionName": "userA",
"path": "/api/user"
},
{
"functionName": "userB",
"path": "/api/user"
}
]
}
⚠️ Note: The above configuration will cause route conflicts and the framework will report an error.
7. Default Route
You can configure a route with path as / as the default route to handle all unmatched requests.
Example:
{
"routes": [
{
"functionName": "user",
"path": "/api/user"
},
{
"functionName": "order",
"path": "/api/order"
},
{
"functionName": "default",
"path": "/"
}
]
}
Routing results:
/api/user→userfunction/api/order→orderfunction/→defaultfunction/about→defaultfunction/health→defaultfunction
Advanced Usage
Using triggerPath to Simplify Configuration
triggerPath is a simplified version of routes, allowing you to specify the trigger path directly in the function definition.
Comparison:
Using triggerPath:
{
"functions": [
{
"name": "user",
"directory": "user",
"triggerPath": "/api/user"
}
],
"routes": []
}
Equivalent to:
{
"functions": [
{
"name": "user",
"directory": "user"
}
],
"routes": [
{
"functionName": "user",
"path": "/api/user"
}
]
}
💡 Tip: It's recommended to use
triggerPathfor more concise configuration. If you need one function to correspond to multiple routes, useroutesconfiguration.
Combining with Express/Koa Frameworks
Function routing can be combined with Express, Koa and other web frameworks, where each sub-function can be a complete web application.
Example:
// user/index.js
const express = require('express');
const app = express();
app.get('/profile', (req, res) => {
res.json({ user: 'profile' });
});
app.get('/list', (req, res) => {
res.json({ users: [] });
});
exports.main = app;
Access:
https://your-function.api.tcloudbasegateway.com/v1/functions/{function-name}/api/user/profile?webfn=truehttps://your-function.api.tcloudbasegateway.com/v1/functions/{function-name}/api/user/list?webfn=true
Mixing SSE and WebSocket
Different sub-functions can handle different types of requests, such as one function handling HTTP requests and another handling WebSocket connections.
Example:
.
├── cloudbase-functions.json
├── index.js # HTTP function
└── ws/ # WebSocket function
└── index.js
cloudbase-functions.json:
{
"functionsRoot": ".",
"functions": [
{
"name": "default",
"directory": "."
},
{
"name": "ws",
"directory": "ws",
"triggerPath": "/ws"
}
]
}
VSCode Editor Support
After installing the @cloudbase/functions-framework dependency, you can get schema auto-completion for cloudbase-functions.json in VSCode.
Create a .vscode/settings.json file in the project root directory:
{
"json.schemas": [
{
"fileMatch": ["cloudbase-functions.json"],
"url": "./node_modules/@cloudbase/functions-framework/functions-schema.json"
}
]
}
After configuration, field and type suggestions will automatically appear when editing the cloudbase-functions.json file.
Complete Example
Project Structure
my-api-service/
├── .vscode/
│ └── settings.json # VSCode configuration
├── package.json # Project configuration
├── scf_bootstrap # Bootstrap script
├── cloudbase-functions.json # Function routing configuration
├── index.js # Default function
├── user/ # User API
│ └── index.js
├── order/ # Order API
│ └── index.js
├── product/ # Product API
│ └── index.js
└── sse/ # SSE streaming response
└── index.js
cloudbase-functions.json
{
"functionsRoot": ".",
"functions": [
{
"name": "default",
"directory": ".",
"triggerPath": "/"
},
{
"name": "user",
"directory": "user",
"triggerPath": "/api/user"
},
{
"name": "order",
"directory": "order",
"triggerPath": "/api/order"
},
{
"name": "product",
"directory": "product",
"triggerPath": "/api/product"
},
{
"name": "sse",
"directory": "sse",
"triggerPath": "/stream"
}
]
}
FAQ
1. Route Configuration Not Taking Effect
Problem: Configured routing rules but still routing to the wrong function when accessing.
Solutions:
- Check if the
cloudbase-functions.jsonfile is in the correct location - Check if the
--functionsConfigFileparameter is specified in thescf_bootstrapstartup script - Check the order of routing rules to ensure longest match rules are first
- Use
console.logto outputcontext.httpContext.urlto view the actual request path
2. Function Not Found
Problem: Startup error: Function xxx not found.
Solutions:
- Check if the
functions[].directorypath is correct - Check if the
functions[].sourcefile exists - Check if the function name exported by
functions[].targetis correct - Ensure
functionsRootis set correctly
3. Route Conflict
Problem: Startup error: Route conflict.
Solutions:
- Check if multiple route rules point to the same path
- Check if there are duplicate configurations in
triggerPathandroutes - Ensure each path corresponds to only one function
4. Default Function Not Working
Problem: Configured default route with path: "/" but getting 404 when accessing.
Solutions:
- Ensure the default route configuration is at the end of the
routesarray - Check if other route rules override the default route
- Ensure the default function's
directoryandsourceconfigurations are correct
5. Hot Reload Not Working in Local Development
Problem: After modifying function code, need to restart the service for changes to take effect.
Solutions:
The @cloudbase/functions-framework framework does not currently support hot reload, requiring manual service restart:
# Stop service (Ctrl+C)
# Restart
./scf_bootstrap