Examples
Example — REST API + PostgreSQL
A production-like REST API with Express, PostgreSQL, and proper error handling.
Project structure
my-api/
├── index.js
├── package.json
├── package-lock.json
└── .gitignoreNode.js project builds install dependencies with npm ci, which requires package-lock.json. Run npm install locally and push the generated file with your code.
Code
package.json
{
"name": "my-api",
"version": "1.0.0",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^5.1.0",
"pg": "^8.16.0"
}
}index.js
const express = require('express');
const { Pool } = require('pg');
const app = express();
app.use(express.json());
// The console URI uses sslmode=verify-full&sslrootcert=system.
// node-postgres does not read sslrootcert=system; with ssl: true it validates
// the certificate and hostname using the Node.js trusted authorities.
const databaseUrl = new URL(process.env.DATABASE_URL);
databaseUrl.searchParams.delete('sslmode');
databaseUrl.searchParams.delete('sslrootcert');
const pool = new Pool({
connectionString: databaseUrl.toString(),
ssl: true,
});
// Create tables on startup
async function initDB() {
await pool.query(`
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
)
`);
}
// Routes
app.get('/users', async (req, res) => {
const { rows } = await pool.query('SELECT * FROM users ORDER BY created_at DESC');
res.json(rows);
});
app.get('/users/:id', async (req, res) => {
const { rows } = await pool.query('SELECT * FROM users WHERE id = $1', [req.params.id]);
if (rows.length === 0) return res.status(404).json({ error: 'User not found' });
res.json(rows[0]);
});
app.post('/users', async (req, res) => {
const { name, email } = req.body ?? {};
if (!name || !email) return res.status(400).json({ error: 'Name and email required' });
const { rows } = await pool.query(
'INSERT INTO users (name, email) VALUES ($1, $2) RETURNING *',
[name, email]
);
res.status(201).json(rows[0]);
});
app.delete('/users/:id', async (req, res) => {
const { rowCount } = await pool.query('DELETE FROM users WHERE id = $1', [req.params.id]);
if (rowCount === 0) return res.status(404).json({ error: 'User not found' });
res.json({ message: 'Deleted' });
});
// Health check
app.get('/health', (req, res) => res.json({ status: 'ok' }));
// Express 5 forwards errors from async routes to this handler
app.use((error, req, res, next) => {
if (error.code === '23505') return res.status(409).json({ error: 'Email already exists' });
if (error.code === '22P02') return res.status(400).json({ error: 'Invalid id' });
console.error(error);
res.status(500).json({ error: 'Internal server error' });
});
const PORT = process.env.PORT || 3000;
initDB()
.then(() => {
app.listen(PORT, '0.0.0.0', () => {
console.log(`API running on port ${PORT}`);
});
})
.catch((error) => {
console.error('Database initialization failed', error);
process.exit(1);
});Console configuration
First create a managed PostgreSQL and copy the connection URI. Then create the HTTP project with:
| Field | Value |
|---|---|
| Project source | Git repository, with Git provider GitHub or Forgejo |
| Runtime | Node.js, version 24 |
| Build Command | empty |
| Start Command | npm start |
| Port | 3000 |
| Environment variable | DATABASE_URL with the PostgreSQL URI |
Deploy
- Push the code, including
package-lock.json, to a GitHub or Forgejo repository. - In the console, choose Git repository as Project source and GitHub or Forgejo as Git provider, and select the repository.
- Select the main branch, set Deployment mode to Automatic by branch, and create the project.
- Push to the branch to publish a new version automatically.
Test it
Use the project URL on *.clients.zenifra.com to test the /users routes.
Expected responses
// POST /users → 201
{ "id": 1, "name": "Alice", "email": "[email protected]", "created_at": "2026-04-30T14:00:00.000Z" }
// GET /users → 200
[ { "id": 1, "name": "Alice", "email": "[email protected]", "created_at": "2026-04-30T14:00:00.000Z" } ]
// GET /users/999 → 404
{ "error": "User not found" }Next examples
Last updated on