Skip to main content

Express

Express is a lightweight and flexible Node.js Web framework renowned for its simplicity and high scalability. It offers a clean API design, supports middleware mechanisms, and enables rapid development of RESTful APIs or full-stack applications. With a rich plugin ecosystem, Express seamlessly integrates features like databases and authentication while maintaining high performance and low learning curve, making it a top choice among Node.js developers.

This guide describes how to deploy Express applications on CloudBase HTTP cloud functions.

Prerequisites

Before you begin, ensure that you have:

  • Installed Node.js 18.x or a later version
  • Have a Tencent Cloud account and have activated the CloudBase service
  • Have a basic knowledge of Node.js and Express development

Step 1: Create an Express Application

💡 Note: If you already have an Express application, you can skip this step.

Create the project directory

mkdir express-cloudbase
cd express-cloudbase

Use Express Generator to create an application

# Use Express Generator to create an application
npx express-generator --view=pug express-app

# Go to the project directory
cd express-app

# Install dependencies.
npm install

This will create an Express application using Pug as the view engine.

Test the application locally

Start up the development server:

npm start

Open your browser and visit http://localhost:3000. You should see the Express welcome page.

Step 2: Add API routes

Let's create a RESTful API to demonstrate the features of Express.

Create user routes

Create the users.js file in the routes directory:

const express = require('express');
const router = express.Router();

// Mock user data
const users = [
{ id: 1, name: 'zhangsan', email: 'zhangsan@example.com' },
{ id: 2, name: 'lisi', email: 'lisi@example.com' },
{ id: 3, name: 'wangwu', email: 'wangwu@example.com' }
];

/* GET users listing */
router.get('/', function(req, res, next) {
const { page = 1, limit = 10 } = req.query;
const startIndex = (page - 1) * limit;
const endIndex = startIndex + parseInt(limit);

const paginatedUsers = users.slice(startIndex, endIndex);

res.json({
success: true,
data: {
total: users.length,
page: parseInt(page),
limit: parseInt(limit),
items: paginatedUsers
}
});
});

/* GET user by ID */
router.get('/:id', function(req, res, next) {
const userId = parseInt(req.params.id);
const user = users.find(u => u.id === userId);

if (!user) {
return res.status(404).json({
success: false,
message: 'User not found'
});
}

res.json({
success: true,
data: user
});
});

/* POST create user */
router.post('/', function(req, res, next) {
const { name, email } = req.body;

if (!name || !email) {
return res.status(400).json({
success: false,
message: 'Name and email are required'
});
}

const newUser = {
id: users.length + 1,
name,
email
};

users.push(newUser);

res.status(201).json({
success: true,
data: newUser
});
});

module.exports = router;

Create healthcheck route

Create the health.js file in the routes directory:

const express = require('express');
const router = express.Router();

/* GET health check */
router.get('/', function(req, res, next) {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
framework: 'Express',
version: process.env.npm_package_version || '1.0.0',
node_version: process.version
});
});

module.exports = router;

Update app configuration

Edit the app.js file to add new routes and middleware:

var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var healthRouter = require('./routes/health');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('combined'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

// Route configuration
app.use('/', indexRouter);
app.use('/api/users', usersRouter);
app.use('/health', healthRouter);

// 404 error handling
app.use(function(req, res, next) {
next(createError(404));
});

// Global error handling
app.use(function(err, req, res, next) {
// Set error information, providing detailed errors only in development environment
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};

// Return error information in JSON format
if (req.path.startsWith('/api/') || req.path.startsWith('/health')) {
res.status(err.status || 500).json({
success: false,
message: err.message,
error: req.app.get('env') === 'development' ? err.stack : undefined
});
} else {
// Render error page
res.status(err.status || 500);
res.render('error');
}
});

module.exports = app;

Modify startup configuration

Edit the bin/www file to ensure the application listens on the correct port:

#!/usr/bin/env node

/**
* Module dependencies.
*/

var app = require('../app');
var debug = require('debug')('express-app:server');
var http = require('http');

/**
* Get port from environment and store in Express.
*/

var port = normalizePort(process.env.PORT || '9000');
app.set('port', port);

/**
* Create HTTP server.
*/

var server = http.createServer(app);

/**
* Listen on provided port, on all network interfaces.
*/

server.listen(port, '0.0.0.0');
server.on('error', onError);
server.on('listening', onListening);

/**
* Normalize a port into a number, string, or false.
*/

function normalizePort(val) {
var port = parseInt(val, 10);

if (isNaN(port)) {
// named pipe
return val;
}

if (port >= 0) {
// port number
return port;
}

return false;
}

/**
* Event listener for HTTP server "error" event.
*/

function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}

var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;

// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}

/**
* Event listener for HTTP server "listening" event.
*/

function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
console.log('Express server listening on ' + bind);
}

Step 3: Local Testing

⚠️ Important: CloudBase HTTP cloud functions require the application to listen on port 9000.

Start up the application:

npm start

Test API endpoints:

# Test Health Check
curl http://localhost:9000/health

# Test User List
curl http://localhost:9000/api/users

# Test Pagination
curl "http://localhost:9000/api/users?page=1&limit=2"

# Test Obtaining a Single User
curl http://localhost:9000/api/users/1

# Test Creating a User
curl -X POST http://localhost:9000/api/users \
-H "Content-Type: application/json" \
-d '{"name":"New User","email":"newuser@example.com"}'

Step 4: Create the Startup Script

💡 Note:

  • When creating the scf_bootstrap file on windows, it is recommended to use
  • When creating the scf_bootstrap file using vscode on windows, deploying to an HTTP cloud function may result in an error: scf_bootstrap file does not exist
  • This error occurs because the script file contains Windows-style carriage returns (^M), causing Linux to fail to recognize the interpreter path correctly. This is a common issue in WSL

Create the scf_bootstrap file (with no extension):

#!/bin/bash
export PORT=9000
npm start

Grant execute permissions to the startup script:

chmod +x scf_bootstrap

💡 Note:

  • scf_bootstrap is the startup script for CloudBase cloud functions
  • Set the PORT=9000 environment variable to ensure the application listens on the correct port
  • Start the application using npm start

Step 5: Prepare Deployment Files

Ensure your project directory structure is as follows:

express-app/
├── bin/
│ └── www # Startup file
├── public/ # Static assets
├── routes/ # Route files
│ ├── index.js
│ ├── users.js
│ └── health.js
├── views/ # View templates
├── app.js # Application main file
├── package.json # Project configuration
├── package-lock.json # Dependency lock file
└── scf_bootstrap # Startup script

Step 6: Deploy to CloudBase HTTP cloud function

Deploy via the console

  1. Log in to the CloudBase console
  2. Select your environment and go to the cloud function page
  3. Click "New Cloud Function"
  4. Select "HTTP cloud function"
  5. Fill in the function name (such as: express-app)
  6. Select runtime: Node.js 18.x (or other supported versions)
  7. Select submit method: Local folder upload
  8. Select the express-app directory for function code upload
  9. Automatic dependency installation: Enable this option
  10. Click the "Create" button and wait for deployment to complete

Deploy via CLI

For details, see Deploy HTTP cloud function

Package and deploy

If you need to package manually:

# Create deployment package (excluding development files)
zip -r express-app.zip . -x "node_modules/*" ".git/*" "*.log"

Step 7: Access Your Application

After successful deployment, you can refer to Accessing Cloud Functions via HTTP to set up custom domain access to the

You can test the following endpoints:

  • Root path: / - Express welcome page
  • Health Check: /health - View application status
  • User List: /api/users - Obtain the user list
  • User Details: /api/users/1 - Retrieve a specific user
  • Create User: POST /api/users - Create a new user

Frequently Asked Questions

Q: Why must port 9000 be used?

A: CloudBase HTTP cloud functions require the application to listen on port 9000, which is the standard configuration of the platform.

Q: How to handle static files?

A: The static file middleware in Express automatically handles static resources in the public directory.

Q: How to view application logs?

A: On the Cloud Functions page of the CloudBase console, click the function name to go to the details page and view the runtime logs.

Q: Which Node.js versions are supported?

A: CloudBase supports Node.js 16.x, 18.x, 20.x and other versions. It is recommended to use the latest LTS version.

Q: How to handle CORS cross-origin issues?

A: You can use the cors middleware or manually set response headers to handle cross-origin requests.

Best Practices

1. Environment Variable Management

Add environment variable support in app.js:

// Load environment variables
require('dotenv').config();

// Use environment variables
const isDevelopment = process.env.NODE_ENV === 'development';
const port = process.env.PORT || 9000;

2. Add CORS support

Install and configure the CORS middleware:

npm install cors
const cors = require('cors');

// Configure CORS
app.use(cors({
origin: process.env.ALLOWED_ORIGINS?.split(',') || '*',
credentials: true
}));

3. Request Log

Use the Morgan middleware to log requests:

const morgan = require('morgan');

// Configure log format
app.use(morgan(process.env.NODE_ENV === 'production' ? 'combined' : 'dev'));

4. Error Handling

Implement global error handling middleware:

// Global error handling
app.use((err, req, res, next) => {
console.error(err.stack);

res.status(err.status || 500).json({
success: false,
message: err.message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
});

5. Security Configuration

Install and configure the Helmet middleware:

npm install helmet
const helmet = require('helmet');

// Security headers configuration
app.use(helmet());

Advanced Features

Database Integration

Integrate MongoDB or MySQL:

npm install mongoose
# or
npm install mysql2

Authentication

Add JWT authentication:

npm install jsonwebtoken bcryptjs

API Documentation

Use Swagger to generate API documentation:

npm install swagger-jsdoc swagger-ui-express

Next steps