Hapi PostgreSQL People Plugin
pg-people is a Hapi plugin designed to manage 'people' and 'organisations' data within a PostgreSQL database. As of version 2.3.0, it provides a structured approach for user management, including adding users, updating passwords, retrieving user and organization details, and toggling account activity. It integrates with Hapi by exposing its functions via the `request.server.pg.people` and `request.server.pg.organisations` objects after registration. The plugin automatically creates necessary tables (`people`, `organisations`, `tags_organisations`) if they don't exist, and offers an option to reset tables with initial data. Its release cadence appears tied to the Hapi ecosystem, targeting older Node.js environments (engine `^6.5.0`). A key differentiator is its seamless integration with Hapi's request lifecycle, extending `request.pg` which implies a reliance on another Hapi plugin to establish the underlying PostgreSQL connection.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'people')
cause The `pg-people` plugin was either not registered with the Hapi server, or the `request.pg` object (from a separate PostgreSQL connection plugin) was not available when `pg-people` attempted to decorate it.fixVerify that `server.register(PgPeople)` is called correctly and that a Hapi plugin providing `request.pg` (e.g., `hapi-pg`) is registered and configured *before* `pg-people`. -
Error: Role "your_user" does not exist
cause The PostgreSQL database credentials used by the underlying `request.pg` connection are incorrect, or the specified database user does not have the necessary permissions.fixEnsure your PostgreSQL connection plugin (which populates `request.pg`) is configured with the correct username, password, host, and database name, and that the user has appropriate database privileges. -
Error: Column 'column_name' does not exist
cause The plugin's automatic table creation might have failed, or the database schema expected by `pg-people` has been altered or is out of sync with the plugin's internal expectations.fixCheck your database logs for table creation errors during Hapi server startup. If safe to do so (e.g., in a development environment), you might try running the plugin with `reset: true` (after backing up data) to force table recreation. Ensure no external process modifies the tables `people`, `organisations`, `tags_organisations`. -
Boom.notFound, 404 error
cause An operation like `edit`, `toggleActive`, or `getBy(id, ...)` was attempted with a `userId` or `orgId` that does not exist in the database.fixBefore performing update or toggle operations, verify the existence of the `userId` or `orgId` using a retrieval method. Implement client-side validation or appropriate error handling for non-existent entities.
Warnings
- breaking The `reset: true` option in the plugin configuration will truncate and re-populate the `people`, `organisations`, and `tags_organisations` tables with the data provided in `people`, `organisations`, and `tags_orgs` options. This will lead to irreversible data loss if used carelessly.
- gotcha This plugin implicitly relies on an existing PostgreSQL client being exposed on the Hapi `request.pg` object. It does not provide its own database connection mechanism. Without another Hapi plugin (e.g., `hapi-pg` or `hapi-pg-promise`) that sets up `request.pg`, the plugin will fail.
- gotcha The `engines.node` specification (`^6.5.0`) in its `package.json` suggests that this package might not be fully compatible with recent Node.js versions (e.g., Node.js 14+ or 16+ which are LTS) or modern Hapi versions (@hapi/hapi v17+). This could lead to runtime errors or unexpected behavior.
- gotcha Several exposed functions, such as `edit`, `toggleActive` (for both people and organizations), and `getBy` for `id`, return a `Boom.notFound, 404 error` (or simply an empty array for `edit` under certain conditions) if the specified `userId` or `orgId` does not exist. Developers must handle these specific error types or empty array responses.
Install
-
npm install pg-people -
yarn add pg-people -
pnpm add pg-people
Imports
- PgPeoplePlugin
import PgPeople from 'pg-people'; // Not directly compatible with Node 6.5 and CommonJS export
const PgPeople = require('pg-people'); // then register with Hapi server.register({ plugin: PgPeople, options: ... }) - getAllPeople
import { getAllPeople } from 'pg-people'; // Functions are exposed via Hapi's request/server object, not direct imports.await request.server.pg.people.getAllPeople();
- add
const { add } = require('pg-people'); // Functions are not directly importable from the package.await request.server.pg.people.add(userObj, cb);
Quickstart
const Hapi = require('@hapi/hapi');
const PgPeople = require('pg-people');
const init = async () => {
const server = Hapi.server({
port: 3000,
host: 'localhost'
});
// In a real application, you would register a Hapi plugin for PostgreSQL
// connectivity, e.g., hapi-pg or hapi-pg-promise, to provide `request.pg`.
// For this quickstart, we'll mock `request.pg` to simulate its presence.
await server.register({
plugin: {
name: 'mock-pg-connector',
version: '1.0.0',
register: async function (serverInstance) {
serverInstance.decorate('request', 'pg', {
query: async (sql, params) => {
console.log('Mock PG query:', sql, params);
if (sql.includes('SELECT') && sql.includes('people')) {
return { rows: [{ id: 1, first_name: 'Mock', last_name: 'Person', email: 'mock@example.com' }] };
}
return { rows: [] };
}
});
}
}
});
await server.register({
plugin: PgPeople,
options: {
// WARNING: `reset: true` will clear existing data in `people` and `organisations` tables.
// Use with extreme caution, especially in production environments.
reset: false,
people: []
}
});
server.route({
method: 'GET',
path: '/people',
handler: async (request, h) => {
try {
// Accessing functions via request.server.pg.people as shown in README
const people = await request.server.pg.people.getAllPeople();
return h.response(people).code(200);
} catch (error) {
console.error('Error fetching people:', error.message);
return h.response({ message: 'Failed to fetch people' }).code(500);
}
}
});
await server.start();
console.log(`Server running on ${server.info.uri}`);
};
process.on('unhandledRejection', (err) => {
console.error(err);
process.exit(1);
});
init();