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
└── .gitignore

Node.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:

FieldValue
Project sourceGit repository, with Git provider GitHub or Forgejo
RuntimeNode.js, version 24
Build Commandempty
Start Commandnpm start
Port3000
Environment variableDATABASE_URL with the PostgreSQL URI

Deploy

  1. Push the code, including package-lock.json, to a GitHub or Forgejo repository.
  2. In the console, choose Git repository as Project source and GitHub or Forgejo as Git provider, and select the repository.
  3. Select the main branch, set Deployment mode to Automatic by branch, and create the project.
  4. 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

On this page