How to Use ChatGPT to Build Node.js Backend APIs: Step-by-Step Guide with Codehooks.io
ChatGPT, GitHub Copilot, Cursor and other AI tools using Large Language Models (LLMs) can quickly generate a lot of code, but quite often the process is not straightforward and requires many iterations and a skilled developer to get the best results.
In this article we will show how a well-structured prompt can improve the AI-supported development effort.
What makes this guide special is that with Codehooks.io, you can deploy ChatGPT-generated code directly to production with minimal or no modifications and minimal setup. The combination of ChatGPT and Codehooks.io's "batteries included" approach means you can go from prompt to production-ready API and database in minutes.
This guide provides a practical prompt template that generates deployment-ready Codehooks.io code. Just copy the template, add your requirements, and let ChatGPT do the heavy lifting.
Best Practices for Prompting ChatGPT
To get the best results when generating code with ChatGPT for Codehooks.io, I tend to follow these principles:
- Provide Examples – Show the AI correct syntax so it doesn't invent one (included in the template).
- Be Explicit About Features – List key components (e.g., API routes, database interactions, worker queues).
- Include a Step-by-Step Structure – Help the model understand how the code should be structured.
- Instructions at the End – The most important details should come last in the prompt.
The ChatGPT / LLM Prompt Template
This template follows the principles above and is designed and tested to generate deployment-ready Codehooks.io code.
You are an expert in backend development using Codehooks.io. Your task is to generate correct, working JavaScript code for a serverless backend using codehooks-js.
Follow these rules:
- Use the `codehooks-js` package correctly.
- DO NOT use fs, path, os, or any other modules that require file system access.
- Create REST API endpoints using `app.get()`, `app.post()`, `app.put()`, and `app.delete()`.
- Use the built-in NoSQL document database via:
- `conn.insertOne(collection, document)`
- `conn.getOne(collection, ID | Query)`
- `conn.findOne(collection, ID | Query)`
- `conn.find(collection, query, options)` // returns a JSON stream - alias for getMany
- `conn.getMany(collection, query, options)`
- `conn.updateOne(collection, ID | Query, updateOperators, options)`
- `conn.updateMany(collection, query, document, options)`
- `conn.replaceOne(collection, ID | Query, document, options)`
- `conn.replaceMany(collection, query, document, options)`
- `conn.removeOne(collection, ID | Query)`
- `conn.removeMany(collection, query, options)`
- Utilize the key-value store with:
- `conn.set(key, value)`
- `conn.get(key)`
- `conn.getAll()`
- `conn.incr(key, increment)`
- `conn.decr(key, decrement)`
- `conn.del(key)`
- `conn.delAll()`
- Implement worker queues with `app.worker(queueName, workerFunction)` and enqueue tasks using `conn.enqueue(queueName, payload)`.
- Use job scheduling with `app.job(cronExpression, async () => { ... })`.
- Use `app.crudlify()` for instant database CRUD REST APIs with validation. Crudlify supports schemas using Zod (with TypeScript), Yup and JSON Schema.
- Use environment variables for sensitive information like secrets and API keys. Access them using `process.env.VARIABLE_NAME`.
- Generate responses in JSON format where applicable.
- Avoid unnecessary dependencies or external services.
- Always import all required npm packages explicitly. Do not assume a module is globally available in Node.js.
- If a function requires a third-party library (e.g., FormData from form-data), import it explicitly and list it in the dependencies.
- Do not use browser-specific APIs (like fetch) unless you include the correct polyfill.
- Always provide a package.json file using the "latest" version of each dependency and notify the user that they need to install the dependencies.
- Only implement the functionality I explicitly request. Do not assume additional features like CRUD operations, unless I specifically mention them.
- Implement proper error handling and logging.
Examples of Codehooks.io functionality:
Creating a simple API:
import { app } from 'codehooks-js';
app.get('/hello', (req, res) => {
res.json({ message: 'Hello, world!' });
});
Using the NoSQL Document Database:
import { app, Datastore } from 'codehooks-js';
app.post('/orders', async (req, res) => {
const conn = await Datastore.open();
const savedOrder = await conn.insertOne('orders', req.body);
res.json(savedOrder);
});
Querying the Database and returning JSON stream:
import { app, Datastore } from 'codehooks-js';
app.get('/pending-orders', async (req, res) => {
const conn = await Datastore.open();
const orders = conn.find('orders', {"status": "pending"});
orders.json(res);
});
Querying the Database and returning JSON array:
import { app, Datastore } from 'codehooks-js';
app.get('/processed-orders', async (req, res) => {
const conn = await Datastore.open();
const orders = await conn.find('orders', {status: "processed"}).toArray();
res.json(orders);
});
Using the Key-Value Store:
import { app, Datastore } from 'codehooks-js';
app.post('/settings/:userId', async (req, res) => {
const conn = await Datastore.open();
await conn.set(`settings-${req.params.userId}`, req.body);
res.json({ message: 'Settings saved' });
});
Implementing a Worker Queue:
import { app, Datastore } from 'codehooks-js';
app.worker('sendEmail', async (req,res) => {
console.log('Processing email:', req.body.payload);
res.end(); // done
});
app.post('/send-email', async (req, res) => {
const conn = await Datastore.open();
await conn.enqueue('sendEmail', req.body);
res.json({ message: 'Email request received' });
});
Scheduling Background Jobs:
import { app } from 'codehooks-js';
app.job('0 0 * * *', async () => {
console.log('Running scheduled task...');
res.end(); // done
});
Instant CRUD API with Validation:
import { app } from 'codehooks-js';
import * as Yup from 'yup';
const customerSchema = Yup.object({
name: Yup.string().required(),
email: Yup.string().email().required()
});
app.crudlify({ customer: customerSchema });
// bind to serverless runtime
export default app.init();
// end of example code
I need an API that [describe what you need here].
Insert Your Request to ChatGPT
To use this template effectively, insert your request at the bottom of the prompt. ChatGPT will use the provided examples to generate accurate Codehooks.io code.
For example:
I need an API that can receive orders from a client and send back a receipt in PDF using Mailgun's REST API. Required fields for the order are name, email, items (array of objects with name and price), total. You can use Yup for validation. Use a worker queue to generate the PDF and send the email.
Using the ChatGPT 4o model, this gave me the following working backend API:
import { app, Datastore } from 'codehooks-js';
import * as Yup from 'yup';
import PDFDocument from 'pdfkit';
import axios from 'axios';
import FormData from 'form-data';
const MAILGUN_API_KEY = process.env.MAILGUN_API_KEY;
const MAILGUN_DOMAIN = process.env.MAILGUN_DOMAIN;
const MAILGUN_FROM = process.env.MAILGUN_FROM;
// Order validation schema
const orderSchema = Yup.object({
name: Yup.string().required(),
email: Yup.string().email().required(),
items: Yup.array()
.of(
Yup.object({
name: Yup.string().required(),
price: Yup.number().required().positive(),
})
)
.required(),
total: Yup.number().required().positive(),
});
// POST /orders - Create new order
app.post('/orders', async (req, res) => {
try {
// Validate order data
const order = await orderSchema.validate(req.body);
const conn = await Datastore.open();
const savedOrder = await conn.insertOne('orders', order);
// Enqueue worker to generate PDF and send email
await conn.enqueue('processOrder', {
orderId: savedOrder._id,
email: order.email,
});
res.json({
message: 'Order received, receipt will be emailed shortly.',
orderId: savedOrder._id,
});
} catch (err) {
res.status(400).json({ error: err.message });
}
});
// Worker function to generate PDF and send email
app.worker('processOrder', async (req, res) => {
const { orderId, email } = req.body.payload;
const conn = await Datastore.open();
// Retrieve order from database
const order = await conn.getOne('orders', orderId);
if (!order) {
console.error('Order not found:', orderId);
return res.end();
}
// Generate PDF receipt
const pdfBuffer = await generateReceiptPDF(order);
// Send email with the receipt
await sendEmailWithAttachment(email, pdfBuffer, `Receipt_${orderId}.pdf`);
console.log('Receipt sent to:', email);
res.end();
});
// Function to generate PDF receipt
async function generateReceiptPDF(order) {
return new Promise((resolve, reject) => {
const doc = new PDFDocument();
const buffers = [];
doc.on('data', buffers.push.bind(buffers));
doc.on('end', () => resolve(Buffer.concat(buffers)));
doc.on('error', reject);
doc.fontSize(20).text('Order Receipt', { align: 'center' });
doc.moveDown();
doc.fontSize(14).text(`Name: ${order.name}`);
doc.text(`Email: ${order.email}`);
doc.moveDown();
doc.text('Items:');
order.items.forEach((item) => {
doc.text(`- ${item.name}: $${item.price.toFixed(2)}`);
});
doc.moveDown();
doc.text(`Total: $${order.total.toFixed(2)}`, { bold: true });
doc.end();
});
}
// Function to send email via Mailgun
async function sendEmailWithAttachment(to, pdfBuffer, filename) {
const formData = new FormData();
formData.append('from', MAILGUN_FROM);
formData.append('to', to);
formData.append('subject', 'Your Order Receipt');
formData.append('text', 'Please find attached your order receipt.');
formData.append('attachment', pdfBuffer, {
filename,
contentType: 'application/pdf',
});
try {
await axios.post(
`https://api.mailgun.net/v3/${MAILGUN_DOMAIN}/messages`,
formData,
{
auth: { username: 'api', password: MAILGUN_API_KEY },
headers: formData.getHeaders(),
}
);
} catch (err) {
console.error('Failed to send email:', err.response?.data || err.message);
}
}
// Initialize app
export default app.init();
Deploying the API with Codehooks.io
Deploying the new API with Codehooks.io is a straightforward process that allows you to quickly get your backend up and running. You can use either the CLI or the web-based Code Studio.
Using the web-based Codehooks Studio for development
Using the Codehooks Studio, you simply edit the package.json and the index.js files and replace their contents with the code from the ChatGPT prompt response. Click "NPM install" and "Deploy" and you are done (if it works, that is 😉). Also remember to set the environment variables in the Settings.
In the studio you can easily see database collections and documents, see live logs, change settings and more.
If you need to add files to source control or use CoPilot, Cursor or other AI IDEs, you can continue development on your local machine.
Just use the CLI command codehooks init
:
codehooks init
? Select project
analytix-yk1e
bsgenerator-94zl
demo-mlyg
❯ fideltech-ehyh
junglelab-5cqe
krypto-xogu
mongotest-mitn
(Move up and down to reveal more choices)
Select the project and space you used and the files will be downloaded to the current folder.
Using the Codehooks CLI
Follow these steps to deploy your API using the CLI and ensure it's configured correctly with the necessary environment variables.
Install Codehooks CLI
If you haven't already, install the Codehooks CLI by running:
npm install -g codehooks
(If you don't have a Codehooks.io account yet, you can create one at codehooks.io)
Create a new project
codehooks create order-api
Edit the files
Edit the index.js and package.json files and paste the code from the ChatGPT prompt response.
Install dependencies
npm install
Deploy Your Project
codehooks deploy
Set the environment variables
codehooks set-env MAILGUN_API_KEY <your-mailgun-api-key> --encrypted
codehooks set-env MAILGUN_DOMAIN <your-mailgun-domain>
codehooks set-env MAILGUN_FROM <your-email-address>
Test (or debug) your new API
You can test your API by sending requests to the /orders endpoint (you can use Postman or curl for example). To get the URL and curl examples run:
codehooks info --examples
Example curl request:
curl -X POST "https://lucky-zenith-2f2d.codehooks.io/orders" \
-H "Content-Type: application/json" \
-H "x-apikey: 5773d8fa-992e-4179-b653-d6daa7bf5e11" \
--data-raw '{
"name": "Emma Hansen",
"email": "[email protected]",
"items": [
{ "name": "Product A", "price": 29.99 },
{ "name": "Product B", "price": 49.99 }
],
"total": 79.98
}'
Example response:
{
"message": "Order received, receipt will be emailed shortly.",
"orderId": "66e94d786e3a3d0001a30e14"
}
Check the logs (and debug)
codehooks logs --follow
By following these steps, you can efficiently deploy the new API with Codehooks.io, ensuring that your application is secure and ready for production use. For use by a web client, you would need to add some form of authentication other than API keys.
Conclusion - A perfect solution ?
Well, no. But it's an improvement.
We've shown how to use a well-structured prompt to help ChatGPT to generate a non-trivial Node.js backend API with Codehooks.io. Being able to go from idea to (almost) production-ready API in minutes is a game changer.
The main Challenge of Prompting LLMs is consistency
Consistent output is not the norm when prompting LLMs. Given an identical prompt, ChatGPT might produce a different variant of the solution each time. It will probably work, but you would be wise to ask it why it made the choices it did. Providing a structured prompt will get you to a good starting point faster than just asking for code.
Well structured prompts provide real value
Good prompts provide real value and software developers with good prompting skills can be far more productive than those without. By following the template approach with codehooks.io, developers can quickly build and experiment with APIs.
Next Steps
- Copy the template and try it for your own use case.
- Modify the examples to fit your specific needs.
- Test and refine the LLM-generated code as necessary.
Happy coding! 🚀