Deploy an Express API
An Express API on app hosting follows the same rules as any Node.js server: it reads its port from the environment, listens on all interfaces and exposes a health route. The differences lie in route structure, input validation and error handling, which keep a malformed request from bringing the process down.
Minimal skeleton
const express = require('express');
const app = express();
app.use(express.json({ limit: '100kb' }));
app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});
app.get('/api/items', (req, res) => {
res.json([{ id: 1, name: 'example' }]);
});
app.post('/api/items', (req, res) => {
const { name } = req.body || {};
if (typeof name !== 'string' || name.length === 0) {
return res.status(400).json({ error: 'invalid_name' });
}
res.status(201).json({ id: 2, name });
});
app.use((req, res) => {
res.status(404).json({ error: 'not_found' });
});
app.use((err, req, res, next) => {
console.error(err);
const status = err.status || err.statusCode || 500;
res.status(status).json({ error: status === 500 ? 'internal_error' : 'bad_request' });
});
const port = Number(process.env.PORT || 3000);
app.listen(port, '0.0.0.0', () => console.log(`api on ${port}`));express.json caps the body size: without a limit, a large request can exhaust memory. The 404 route comes after every route, and the four-argument error handler comes last. A three-argument handler is not recognised as an error handler.
Routes and validation
A public API receives untrusted data. Validate type, length and allowed values before reaching the database. An explicit schema (Zod, Joi or a small function) returns a clear 400 instead of a 500 exception.
- Use prepared query parameters, never SQL string concatenation.
- Limit accepted fields: do not let the client choose a
roleor anowner_id. - Return error messages without internal details.
- Add targeted rate limiting on expensive routes.
Variables and configuration
DATABASE_URL=...
API_KEY=...These values belong in the panel variables. Validate them at startup and fail with a clear message when a required one is missing. Never return process.env in a response, even while debugging.
Robustness
A server must survive a route error: catch promise rejections, or an unhandled async failure can terminate the process depending on the Node version. Shut down cleanly on SIGTERM: stop accepting connections, finish in-flight requests, close the database, then exit. The platform may restart a service during maintenance.
Check
curl -i http://ADRESSE_FOURNIE:PORT/health
curl -i -X POST http://ADRESSE_FOURNIE:PORT/api/items \
-H 'Content-Type: application/json' \
-d '{"name":"test"}'Expect 200 on /health, 404 on an unknown route, 400 on invalid JSON, and no stack trace in the response. If the service runs but requests fail, check the listening interface before the routes.
Advertisement
Was this article helpful?
Read next
- Host a Node.js Discord botRun a discord.js bot with an environment token, minimal intents and bounded caches.
- Connect Node.js to a databaseConfigure a MySQL or PostgreSQL pool from panel variables and handle migrations and backups.
- Redeploy a Node.js applicationReplace code, reinstall dependencies, restart and verify without a mixed state.