// server.mjs
// One big difference between express and other frameworks is that Nile's route handlers
// do not return a response by default. In order to use them in a custom handler,
// you need some extra configuration and extra handling of all routes
import 'dotenv/config';
import express from 'express';
import { Nile } from '@niledatabase/server';
import { NileExpressHandler } from '@niledatabase/server/express';
const startServer = async () => {
try {
const app = express();
const nile = Nile({
// debug: true,
});
// muteResponse is set to true to avoid sending the response back to the client from the route handler
// this is useful when you want to override the route with your own logic
const { paths, handler } = await NileExpressHandler(nile, {
muteResponse: true,
});
console.log(paths);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Add custom Google OAuth callback route - This has to be done before all the default routes
app.get('/auth/google/callback', async (req, res, next) => {
const { status, headers, body } = await handler(req, res, next);
if (status === 200) {
// Fetch user information
const nileCtx = nile.withContext({ headers });
const me = await nileCtx.users.getSelf();
if ('id' in me) {
// Custom logic: register tenants
await registerTenants(me.id);
}
}
res.status(status).set(headers);
if (typeof body === 'string') {
res.send(body);
} else {
res.json(body ?? {});
}
return;
});
// Create response logging wrapper
// This is critical to ensure that the response is sent back to the client from the route handlers
// So make sure you use with `{ muteResponse: true }` even if you don't want to log all the responses.
const withResponseLogging = (handler) => async (req, res, next) => {
try {
// Wait for the handler to complete
const result = await handler(req, res, next);
// Log the result
console.log('Handler result:', result);
const { status, headers, body } = result;
res.status(status).set(headers);
if (typeof body === 'string') {
res.send(body);
} else {
res.json(body ?? {});
}
return;
} catch (error) {
console.error('Handler error:', error);
throw error;
}
};
// Apply wrapper to routes
app.get(paths.get, withResponseLogging(handler));
app.post(paths.post, withResponseLogging(handler));
app.put(paths.put, withResponseLogging(handler));
app.delete(paths.delete, withResponseLogging(handler));
const PORT = process.env.PORT || 3040;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
} catch (error) {
console.error('Error starting server:', error);
process.exit(1);
}
};
startServer();