
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@envage/hapi-pg-rest-api
Advanced tools
RESTful API builder for Postgres DB table within a HAPI v20 application
A module to create a simple REST API in a HAPI 20 application connected to a particular Postgres DB table.
Please read the contribution guidelines before submitting a pull request.
All routes return a standard response in form:
{
"error": // Error response
"data": // data returned from call
}
Routes that update also return a rowCount parameter showing the number of rows modified, e.g.:
{
"error": null,
"data": null,
"rowCount" : 3
}
When finding many records, pagination data is returned:
{
...,
"pagination": {
"page": 1,
"perPage": 100,
"totalRows": 200,
"pageCount": 2
}
}
When querying for the schema, JSON schema and configuration data is returned:
{
"error" : null,
"data" : {
"jsonSchema" : {
...
},
"config" : {
"primaryKey" : "field",
"primaryKeyAuto" : false,
"primaryKeyGuid" : true
}
}
}
const {Pool} = require('pg');
const server = new Hapi.Server();
const RestApi = require('rest-api');
// Create a new endpoint linked to a table
const SessionsApi = RestApi({
table : 'sessions',
connection : pool,
primaryKey : 'session_id',
endpoint : '/api/1.0/sessions',
onCreateTimestamp : 'date_created',
onUpdateTimestamp : 'date_updated',
validation : {
session_id : Joi.string().guid(),
ip : Joi.string(),
session_data : Joi.string(),
date_created : Joi.string(),
date_updated : Joi.string().allow(null)
}
});
// Import routes to HAPI
server.route([
...SessionsApi.getRoutes()
]);
// Or, import individual routes as required
server.route([
SessionsApi.findManyRoute(),
SessionsApi.findOneRoute(),
SessionsApi.createRoute(),
SessionsApi.updateOneRoute(),
SessionsApi.replaceOneRoute(),
SessionsApi.deleteOneRoute(),
SessionsApi.updateManyRoute(),
SessionsApi.schemaDefinitionRoute(),
]);
table : the PostGres table to connect toconnection : the pool connection instance created with pg moduleprimaryKey : the primary key field in the database table (must accept string GUID)endpoint : the base URL endpoint upon which the below calls are mountedonCreateTimestamp : a field which will be updated when the record is createdonUpdateTimestamp : a field which will be updated when the record is updatedvalidation : an object containing Joi validation for the entity (required)preUpdate : a function which can filter the data object being updatedpreInsert : a function which can filter the data object being insertedpreQuery : a function which can modify the data, filter and sort after a HAPI request has been interpretedpostSelect : a function which can modify data retrieved by select queryupsert : an object containing arrays fields and set - adds an on conflict clause to an insertprimaryKeyAuto : whether primary key field is auto-generated by the DB (default false)primaryKeyGuid : whether to use guids for primary key fields (default true)pagination : default pagination, specified as {page : 1, perPage : 200}showSql : for debugging, shows the generated SQL statementsmaxPayloadBytes : when posting large payloads, set this to override the HAPI defaultRequest:
POST /endpoint
Body:
{
field : 'value',
field2: 'value2'
}
Response:
201 Created
Body:
{
"error" : null,
"data" : {
"field" : "value",
"field2" : "value2"
}
}
Request:
GET /endpoint/:id
Success Response:
200 OK
Body:
{
"error" : null,
"data" : {
"field" : "value",
"field2" : "value2"
}
}
Not Found Response:
404 Not Found
Body:
{
"error" : {
"name" : "NotFoundError"
},
"data" : null
}
Request:
GET /endpoint
Success Response:
200 OK
Body:
{
"error" : null,
"data" : [{
"field" : "value",
"field2" : "value2"
},
{
"field" : "value",
"field2" : "value2"
}],
"pagination" : {
"page": 1,
"perPage": 100,
"totalRows": 10,
"pageCount": 2
}
}
Request:
GET /endpoint?filter={"field":"value"}&sort={"field":+1,"field2":-1}
Success Response:
200 OK
Body:
{
"error" : null,
"data" : [
...
]
}
You can also use mongo-style operators such as $gt, $gte, $lt, $lte, $like, $ilike, for example:
GET /endpoint?filter={"field": {$ilike : "%value"}}&sort={"field":+1,"field2":-1}
Internally, the mongo-sql library is used to build filter queries.
Request:
GET /endpoint?pagination={"page": 1, "perPage" : 5}
Success Response:
200 OK
Body:
{
"error" : null,
"data" : [
...
],
"pagination" : {
"page": 1,
"perPage": 5,
"totalRows": 10,
"pageCount": 2
}
}
Request:
PATCH /endpoint/:id
Body:
{
field : 'value',
field2: 'value2'
}
Success Response:
200 OK
Body:
{
"error" : null,
"data" : null
}
Not Found Response:
404 Not Found
Body:
{
"error" : {
"name" : "NotFoundError"
},
"data" : null
}
Request:
PATCH /endpoint?filter={"key" : "value"}
Body:
{
field : 'value',
field2: 'value2'
}
Success Response:
200 OK
Body:
{
"error" : null,
"data" : null,
"rowCount" : 5 // number of rows modified
}
Request:
DELETE /endpoint/:id
Success Response:
200 OK
Body:
{
"error" : null,
"data" : null
}
Not Found Response:
404 Not Found
Body:
{
"error" : {
"name" : "NotFoundError"
},
"data" : null
}
An endpoint is available that gets a basic JSON schema representation of the validation rules provided to Joi in the configuration object.
Request:
DELETE /endpoint/schema
Success Response:
200 OK
Body:
{
"error" : null,
"data" : {
"jsonSchema" : {
...
},
"config" : {
...
}
}
}
Currently supported options in the schema are:
Joi validation config:
{
id : Joi.string().guid(),
field_1 : Joi.string(),
field_2 : Joi.number(),
field_3 : Joi.string().required(),
field_4 : Joi.string().email(),
field_5 : Joi.string().min(4).max(16)
}
Success Response:
200 OK
Body:
{
"error" : null,
"data" : {
"jsonSchema" : {
"type" : "object",
"title" : "sessions",
"properties" : {
"id" : {
"type" : "string",
"pattern" : "/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i"
},
"field_1" : {
"type" : "string"
},
"field_2" : {
"type" : "number"
},
"field_3" : {
"type" : "string"
},
"field_4" : {
"type" : "string",
"format" : "email"
},
"field_5" : {
"type" : "string",
"minLength" : 4,
"maxLength" : 16
}
},
"required" : ["field_3"]
},
"config" : {
"primaryKey" : "id",
"primaryKeyAuto" : false,
"primaryKeyGuid" : true
}
}
}
Data is validated with Joi validation, and on failure, the 'error' key in the response is populated with the Joi error.
For example:
{
"data": null,
"error": {
"name": "ValidationError",
"isJoi": true,
"details": [
{
"message": "\"ip\" must be a string",
"path": [
"ip"
],
"type": "string.base",
"context": {
"value": 123,
"key": "ip",
"label": "ip"
}
}
],
"_object": {
"ip": 123,
"session_data": "{\"key\" : \"value\"}"
}
}
}
An API client is also available to connect with the server API. It depends on request-promise-native.
const APIClient = require('hapi-pg-rest-api').APIClient;
const rp = require('request-promise-native');
const client = new APIClient(rp, {
endpoint : 'http://localhost/some/api/endpoint',
headers : {
Authorization : '...'
}
});
const data = {field : 'value', field2 : 'value2'};
const filter = {field : 'value'};
const sort = {field2 : +1, field3 : -1};
const pagination = {page : 1, perPage : 5};
// Single record
var {data, error} = await client.create(data);
var {data, error} = await client.findOne('guid');
var {data, rowCount, error} = await client.updateOne('guid', data);
await client.delete('guid');
// Batch
var {data, error} = await client.findMany(filter, sort, pagination, columns);
var data = await client.findAll(filter, sort, pagination, columns); // Finds all pages in result set
var {data, rowCount, error} = await client.updateMany(filter, data);
// Schema
var {data, error} = await client.schema();
For errors returned by the API, e.g. Joi validation errors, this is returned as normal in the return from the call.
For other errors, e.g. those generates by the HTTP request (e.g. bad gateway), the error is thrown. All the client methods above throw an error if a n
This can be either an error returned by the API, e.g. a Joi validation error, or a status code error returned from request-promise-native.
To run the test suite
npm run migrate to set up the test database tablesnpm run test to run the lab test suiteTHIS INFORMATION IS LICENSED UNDER THE CONDITIONS OF THE OPEN GOVERNMENT LICENCE found at:
http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3
The following attribution statement MUST be cited in your products and applications when using this information.
Contains public sector information licensed under the Open Government license v3
The Open Government Licence (OGL) was developed by the Controller of Her Majesty's Stationery Office (HMSO) to enable information providers in the public sector to license the use and re-use of their information under a common open licence.
It is designed to encourage use and re-use of information freely and flexibly, with only a few conditions.
FAQs
RESTful API builder for Postgres DB table within a HAPI v20 application
The npm package @envage/hapi-pg-rest-api receives a total of 71 weekly downloads. As such, @envage/hapi-pg-rest-api popularity was classified as not popular.
We found that @envage/hapi-pg-rest-api demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 14 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.