From 2890397baa3defb09733d83ed6fcee46af4a1776 Mon Sep 17 00:00:00 2001 From: nenharper Date: Wed, 17 Sep 2025 15:07:39 -0500 Subject: [PATCH 1/2] New fastify page --- .../developers/applications/define-routes.md | 113 +++------------ .../reference/Applications/fastify-routes.md | 132 ++++++++++++++++++ 2 files changed, 152 insertions(+), 93 deletions(-) create mode 100644 versioned_docs/version-4.6/reference/Applications/fastify-routes.md diff --git a/versioned_docs/version-4.6/developers/applications/define-routes.md b/versioned_docs/version-4.6/developers/applications/define-routes.md index c442f9f1..f8286c7a 100644 --- a/versioned_docs/version-4.6/developers/applications/define-routes.md +++ b/versioned_docs/version-4.6/developers/applications/define-routes.md @@ -4,116 +4,43 @@ title: Define Fastify Routes # Define Fastify Routes -Harper’s applications provide an extension for loading [Fastify](https://www.fastify.io/) routes as a way to handle endpoints. While we generally recommend building your endpoints/APIs with Harper's [REST interface](../rest) for better performance and standards compliance, Fastify's route can provide an extensive API for highly customized path handling. Below is a very simple example of a route declaration. +Harper gives you a full REST API out of the box, but sometimes you want to shape requests and responses in your own way. That’s where Fastify routes come in. They let you define custom paths and behaviors while still working inside your Harper application. -The fastify route handler can be configured in your application's config.yaml (this is the default config if you used the [application template](https://github.com/HarperDB/application-template)): +## Getting Started + +Fastify routes are configured in your application’s `config.yaml`. By default, the application template already includes a section like this: ```yaml -fastifyRoutes: # This loads files that define fastify routes using fastify's auto-loader - files: routes/*.js # specify the location of route definition modules - path: . # relative to the app-name, like https://server/app-name/route-name +fastifyRoutes: + files: routes/*.js # route definition modules + path: . # base path, relative to app name ``` -By default, route URLs are configured to be: - -- \[**Instance URL**]:\[**HTTP Port**]/\[**Project Name**]/\[**Route URL**] +This tells Harper to auto-load any files you put in the `routes/` directory. -However, you can specify the path to be `/` if you wish to have your routes handling the root path of incoming URLs. +## Example: Dog Breeds Endpoint -- The route below, using the default config, within the **dogs** project, with a route of **breeds** would be available at **[http://localhost:9926/dogs/breeds](http://localhost:9926/dogs/breeds)**. +Let’s extend our `Dog` example from earlier. We’ll add a custom route that returns all distinct breeds in our table. -In effect, this route is just a pass-through to Harper. The same result could have been achieved by hitting the core Harper API, since it uses **hdbCore.preValidation** and **hdbCore.request**, which are defined in the "helper methods" section, below. +Create a file `routes/breeds.js`: ```javascript -export default async (server, { hdbCore, logger }) => { - server.route({ - url: '/', - method: 'POST', - preValidation: hdbCore.preValidation, - handler: hdbCore.request, +module.exports = async function (fastify, opts) { + fastify.get('/breeds', async (request, reply) => { + const results = await fastify.harper.table('Dog').distinct('breed'); + return results; }); }; ``` -## Custom Handlers - -For endpoints where you want to execute multiple operations against Harper, or perform additional processing (like an ML classification, or an aggregation, or a call to a 3rd party API), you can define your own logic in the handler. The function below will execute a query against the dogs table, and filter the results to only return those dogs over 4 years in age. - -**IMPORTANT: This route has NO preValidation and uses hdbCore.requestWithoutAuthentication, which- as the name implies- bypasses all user authentication. See the security concerns and mitigations in the "helper methods" section, below.** +Run your app in dev mode and visit: -```javascript -export default async (server, { hdbCore, logger }) => { - server.route({ - url: '/:id', - method: 'GET', - handler: (request) => { - request.body= { - operation: 'sql', - sql: `SELECT * FROM dev.dog WHERE id = ${request.params.id}` - }; - - const result = await hdbCore.requestWithoutAuthentication(request); - return result.filter((dog) => dog.age > 4); - } - }); -} ``` - -## Custom preValidation Hooks - -The simple example above was just a pass-through to Harper- the exact same result could have been achieved by hitting the core Harper API. But for many applications, you may want to authenticate the user using custom logic you write, or by conferring with a 3rd party service. Custom preValidation hooks let you do just that. - -Below is an example of a route that uses a custom validation hook: - -```javascript -import customValidation from '../helpers/customValidation'; - -export default async (server, { hdbCore, logger }) => { - server.route({ - url: '/:id', - method: 'GET', - preValidation: (request) => customValidation(request, logger), - handler: (request) => { - request.body = { - operation: 'sql', - sql: `SELECT * FROM dev.dog WHERE id = ${request.params.id}`, - }; - - return hdbCore.requestWithoutAuthentication(request); - }, - }); -}; +http://localhost:9926/dogs/breeds ``` -Notice we imported customValidation from the **helpers** directory. To include a helper, and to see the actual code within customValidation, see [Helper Methods](./define-routes#helper-methods). - -## Helper Methods - -When declaring routes, you are given access to 2 helper methods: hdbCore and logger. - -**hdbCore** - -hdbCore contains three functions that allow you to authenticate an inbound request, and execute operations against Harper directly, by passing the standard Operations API. - -- **preValidation** - - This is an array of functions used for fastify authentication. The second function takes the authorization header from the inbound request and executes the same authentication as the standard Harper Operations API (for example, `hdbCore.preValidation[1](./req, resp, callback)`). It will determine if the user exists, and if they are allowed to perform this operation. **If you use the request method, you have to use preValidation to get the authenticated user**. - -- **request** - - This will execute a request with Harper using the operations API. The `request.body` should contain a standard Harper operation and must also include the `hdb_user` property that was in `request.body` provided in the callback. - -- **requestWithoutAuthentication** - - Executes a request against Harper without any security checks around whether the inbound user is allowed to make this request. For security purposes, you should always take the following precautions when using this method: - - Properly handle user-submitted values, including url params. User-submitted values should only be used for `search_value` and for defining values in records. Special care should be taken to properly escape any values if user-submitted values are used for SQL. - -**logger** +You’ll see a JSON list of breeds pulled straight from the database. -This helper allows you to write directly to the log file, hdb.log. It’s useful for debugging during development, although you may also use the console logger. There are 5 functions contained within logger, each of which pertains to a different **logging.level** configuration in your harperdb-config.yaml file. +## What’s Next -- logger.trace(‘Starting the handler for /dogs’) -- logger.debug(‘This should only fire once’) -- logger.warn(‘This should never ever fire’) -- logger.error(‘This did not go well’) -- logger.fatal(‘This did not go very well at all’) +This page is designed to get you started quickly. For configuration options, advanced patterns, and security details, see the [Fastify Routes Reference](../../reference/Applications/fastify-routes). diff --git a/versioned_docs/version-4.6/reference/Applications/fastify-routes.md b/versioned_docs/version-4.6/reference/Applications/fastify-routes.md new file mode 100644 index 00000000..81630c42 --- /dev/null +++ b/versioned_docs/version-4.6/reference/Applications/fastify-routes.md @@ -0,0 +1,132 @@ +--- +title: Fastify Routes +--- + +# Fastify Routes + +This page documents the configuration, behavior, and advanced usage of Fastify routes in Harper applications. If you are looking for a quick introduction and example, start with [Define Fastify Routes](../../developers/applications/define-routes). + +## Configuration + +Fastify routes are enabled in your application’s `config.yaml`. + +```yaml +fastifyRoutes: + files: routes/*.js # Location of route definition modules + path: . # Base path for mounting routes +``` + +**Options** + +- `files`: Glob pattern specifying the location of route definition modules. Default: `routes/*.js`. +- `path`: The base path for mounted routes, relative to the application name. + - Default: `.` (results in `[ProjectName]/[Route]`) + - Set to `/` to mount directly at the root. + +## Route Definition + +Route modules are standard [Fastify auto-loader](https://github.com/fastify/fastify-autoload) plugins. Each file exports an async function that registers one or more routes. + +```javascript +module.exports = async function (fastify, opts) { + fastify.get('/example', async (request, reply) => { + return { hello: 'world' }; + }); +}; +``` + +**Parameters** +Each route handler has access to: + +- `request`: The incoming Fastify request object (query params, body, headers, etc.). +- `reply`: The response object, used to send back data or set headers. +- `fastify.harper`: The Harper database client, allowing direct table queries inside handlers. + +## URL Structure + +By default, routes are mounted as: + +``` +[Instance URL]:[Port]/[ProjectName]/[RoutePath] +``` + +Examples: + +- Project: `dogs` +- Route file: `routes/breeds.js` +- Handler path: `/breeds` + +Resulting URL: + +```bash +http://localhost:9926/dogs/breeds +``` + +If `path: /` is configured, routes are mounted at the root: + +```bash +http://localhost:9926/breeds +``` + +## Examples + +**Simple Route** + +```javascript +module.exports = async function (fastify, opts) { + fastify.get('/ping', async (request, reply) => { + return { pong: true }; + }); +}; +``` + +**Querying Harper Tables** + +```javascript +module.exports = async function (fastify, opts) { + fastify.get('/dogs', async (request, reply) => { + return fastify.harper.table('Dog').all(); + }); +}; +``` + +**Route With Params** + +```javascript +module.exports = async function (fastify, opts) { + fastify.get('/dogs/:id', async (request, reply) => { + const { id } = request.params; + return fastify.harper.table('Dog').get(id); + }); +}; +``` + +## Advanced Usage + +- Custom Middleware: Add validation, logging, or transformations by attaching hooks or decorators. +- Multiple Routes per File: A single route file can register multiple endpoints. +- Fastify Plugins: You can use the entire Fastify ecosystem (e.g., CORS, rate limiting). + +## Security Considerations + +Fastify routes do not automatically apply Harper’s table-level authentication and authorization. You should explicitly enforce access controls. + +Example using JWT: + +```javascript +fastify.get('/secure', { preValidation: [fastify.authenticate] }, async (request, reply) => { + return { secret: true }; +}); +``` + +For built-in authentication methods, see [Security](../../developers/security/). + +## Error Handling + +Use Fastify’s reply API for consistent error responses: + +```javascript +fastify.get('/error', async (request, reply) => { + reply.code(400).send({ error: 'Bad Request' }); +}); +``` From 8f0ff6fd9630e7d7394f7e7a22e2c28bf11294fe Mon Sep 17 00:00:00 2001 From: nenharper Date: Wed, 24 Sep 2025 08:03:11 -0500 Subject: [PATCH 2/2] Remove fastify --- .../developers/applications/define-routes.md | 119 ---------------- .../developers/components/built-in.md | 14 -- .../developers/applications/define-routes.md | 46 ------ .../reference/Applications/fastify-routes.md | 132 ------------------ .../components/built-in-extensions.md | 14 -- 5 files changed, 325 deletions(-) delete mode 100644 versioned_docs/version-4.5/developers/applications/define-routes.md delete mode 100644 versioned_docs/version-4.6/developers/applications/define-routes.md delete mode 100644 versioned_docs/version-4.6/reference/Applications/fastify-routes.md diff --git a/versioned_docs/version-4.5/developers/applications/define-routes.md b/versioned_docs/version-4.5/developers/applications/define-routes.md deleted file mode 100644 index c442f9f1..00000000 --- a/versioned_docs/version-4.5/developers/applications/define-routes.md +++ /dev/null @@ -1,119 +0,0 @@ ---- -title: Define Fastify Routes ---- - -# Define Fastify Routes - -Harper’s applications provide an extension for loading [Fastify](https://www.fastify.io/) routes as a way to handle endpoints. While we generally recommend building your endpoints/APIs with Harper's [REST interface](../rest) for better performance and standards compliance, Fastify's route can provide an extensive API for highly customized path handling. Below is a very simple example of a route declaration. - -The fastify route handler can be configured in your application's config.yaml (this is the default config if you used the [application template](https://github.com/HarperDB/application-template)): - -```yaml -fastifyRoutes: # This loads files that define fastify routes using fastify's auto-loader - files: routes/*.js # specify the location of route definition modules - path: . # relative to the app-name, like https://server/app-name/route-name -``` - -By default, route URLs are configured to be: - -- \[**Instance URL**]:\[**HTTP Port**]/\[**Project Name**]/\[**Route URL**] - -However, you can specify the path to be `/` if you wish to have your routes handling the root path of incoming URLs. - -- The route below, using the default config, within the **dogs** project, with a route of **breeds** would be available at **[http://localhost:9926/dogs/breeds](http://localhost:9926/dogs/breeds)**. - -In effect, this route is just a pass-through to Harper. The same result could have been achieved by hitting the core Harper API, since it uses **hdbCore.preValidation** and **hdbCore.request**, which are defined in the "helper methods" section, below. - -```javascript -export default async (server, { hdbCore, logger }) => { - server.route({ - url: '/', - method: 'POST', - preValidation: hdbCore.preValidation, - handler: hdbCore.request, - }); -}; -``` - -## Custom Handlers - -For endpoints where you want to execute multiple operations against Harper, or perform additional processing (like an ML classification, or an aggregation, or a call to a 3rd party API), you can define your own logic in the handler. The function below will execute a query against the dogs table, and filter the results to only return those dogs over 4 years in age. - -**IMPORTANT: This route has NO preValidation and uses hdbCore.requestWithoutAuthentication, which- as the name implies- bypasses all user authentication. See the security concerns and mitigations in the "helper methods" section, below.** - -```javascript -export default async (server, { hdbCore, logger }) => { - server.route({ - url: '/:id', - method: 'GET', - handler: (request) => { - request.body= { - operation: 'sql', - sql: `SELECT * FROM dev.dog WHERE id = ${request.params.id}` - }; - - const result = await hdbCore.requestWithoutAuthentication(request); - return result.filter((dog) => dog.age > 4); - } - }); -} -``` - -## Custom preValidation Hooks - -The simple example above was just a pass-through to Harper- the exact same result could have been achieved by hitting the core Harper API. But for many applications, you may want to authenticate the user using custom logic you write, or by conferring with a 3rd party service. Custom preValidation hooks let you do just that. - -Below is an example of a route that uses a custom validation hook: - -```javascript -import customValidation from '../helpers/customValidation'; - -export default async (server, { hdbCore, logger }) => { - server.route({ - url: '/:id', - method: 'GET', - preValidation: (request) => customValidation(request, logger), - handler: (request) => { - request.body = { - operation: 'sql', - sql: `SELECT * FROM dev.dog WHERE id = ${request.params.id}`, - }; - - return hdbCore.requestWithoutAuthentication(request); - }, - }); -}; -``` - -Notice we imported customValidation from the **helpers** directory. To include a helper, and to see the actual code within customValidation, see [Helper Methods](./define-routes#helper-methods). - -## Helper Methods - -When declaring routes, you are given access to 2 helper methods: hdbCore and logger. - -**hdbCore** - -hdbCore contains three functions that allow you to authenticate an inbound request, and execute operations against Harper directly, by passing the standard Operations API. - -- **preValidation** - - This is an array of functions used for fastify authentication. The second function takes the authorization header from the inbound request and executes the same authentication as the standard Harper Operations API (for example, `hdbCore.preValidation[1](./req, resp, callback)`). It will determine if the user exists, and if they are allowed to perform this operation. **If you use the request method, you have to use preValidation to get the authenticated user**. - -- **request** - - This will execute a request with Harper using the operations API. The `request.body` should contain a standard Harper operation and must also include the `hdb_user` property that was in `request.body` provided in the callback. - -- **requestWithoutAuthentication** - - Executes a request against Harper without any security checks around whether the inbound user is allowed to make this request. For security purposes, you should always take the following precautions when using this method: - - Properly handle user-submitted values, including url params. User-submitted values should only be used for `search_value` and for defining values in records. Special care should be taken to properly escape any values if user-submitted values are used for SQL. - -**logger** - -This helper allows you to write directly to the log file, hdb.log. It’s useful for debugging during development, although you may also use the console logger. There are 5 functions contained within logger, each of which pertains to a different **logging.level** configuration in your harperdb-config.yaml file. - -- logger.trace(‘Starting the handler for /dogs’) -- logger.debug(‘This should only fire once’) -- logger.warn(‘This should never ever fire’) -- logger.error(‘This did not go well’) -- logger.fatal(‘This did not go very well at all’) diff --git a/versioned_docs/version-4.5/developers/components/built-in.md b/versioned_docs/version-4.5/developers/components/built-in.md index b7f4498e..bb89efe9 100644 --- a/versioned_docs/version-4.5/developers/components/built-in.md +++ b/versioned_docs/version-4.5/developers/components/built-in.md @@ -7,7 +7,6 @@ title: Built-In Components Harper provides extended features using built-in components. They do **not** need to be installed with a package manager, and simply must be specified in a config to run. These are used throughout many Harper docs, guides, and examples. Unlike external components which have their own semantic versions, built-in components follow Harper's semantic version. - [Built-In Components](#built-in-components) - - [fastifyRoutes](#fastifyroutes) - [graphql](#graphql) - [graphqlSchema](#graphqlschema) - [jsResource](#jsresource) @@ -20,19 +19,6 @@ Harper provides extended features using built-in components. They do **not** nee -## fastifyRoutes - -Specify custom endpoints using [Fastify](https://fastify.dev/). - -This component is a [Resource Extension](./reference#resource-extension) and can be configured with the [`files`, `path`, and `root`](./reference#resource-extension-configuration) configuration options. - -Complete documentation for this feature is available here: [Define Fastify Routes](../applications/define-routes) - -```yaml -fastifyRoutes: - files: './routes/*.js' -``` - ## graphql > GraphQL querying is **experimental**, and only partially implements the GraphQL Over HTTP / GraphQL specifications. diff --git a/versioned_docs/version-4.6/developers/applications/define-routes.md b/versioned_docs/version-4.6/developers/applications/define-routes.md deleted file mode 100644 index f8286c7a..00000000 --- a/versioned_docs/version-4.6/developers/applications/define-routes.md +++ /dev/null @@ -1,46 +0,0 @@ ---- -title: Define Fastify Routes ---- - -# Define Fastify Routes - -Harper gives you a full REST API out of the box, but sometimes you want to shape requests and responses in your own way. That’s where Fastify routes come in. They let you define custom paths and behaviors while still working inside your Harper application. - -## Getting Started - -Fastify routes are configured in your application’s `config.yaml`. By default, the application template already includes a section like this: - -```yaml -fastifyRoutes: - files: routes/*.js # route definition modules - path: . # base path, relative to app name -``` - -This tells Harper to auto-load any files you put in the `routes/` directory. - -## Example: Dog Breeds Endpoint - -Let’s extend our `Dog` example from earlier. We’ll add a custom route that returns all distinct breeds in our table. - -Create a file `routes/breeds.js`: - -```javascript -module.exports = async function (fastify, opts) { - fastify.get('/breeds', async (request, reply) => { - const results = await fastify.harper.table('Dog').distinct('breed'); - return results; - }); -}; -``` - -Run your app in dev mode and visit: - -``` -http://localhost:9926/dogs/breeds -``` - -You’ll see a JSON list of breeds pulled straight from the database. - -## What’s Next - -This page is designed to get you started quickly. For configuration options, advanced patterns, and security details, see the [Fastify Routes Reference](../../reference/Applications/fastify-routes). diff --git a/versioned_docs/version-4.6/reference/Applications/fastify-routes.md b/versioned_docs/version-4.6/reference/Applications/fastify-routes.md deleted file mode 100644 index 81630c42..00000000 --- a/versioned_docs/version-4.6/reference/Applications/fastify-routes.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Fastify Routes ---- - -# Fastify Routes - -This page documents the configuration, behavior, and advanced usage of Fastify routes in Harper applications. If you are looking for a quick introduction and example, start with [Define Fastify Routes](../../developers/applications/define-routes). - -## Configuration - -Fastify routes are enabled in your application’s `config.yaml`. - -```yaml -fastifyRoutes: - files: routes/*.js # Location of route definition modules - path: . # Base path for mounting routes -``` - -**Options** - -- `files`: Glob pattern specifying the location of route definition modules. Default: `routes/*.js`. -- `path`: The base path for mounted routes, relative to the application name. - - Default: `.` (results in `[ProjectName]/[Route]`) - - Set to `/` to mount directly at the root. - -## Route Definition - -Route modules are standard [Fastify auto-loader](https://github.com/fastify/fastify-autoload) plugins. Each file exports an async function that registers one or more routes. - -```javascript -module.exports = async function (fastify, opts) { - fastify.get('/example', async (request, reply) => { - return { hello: 'world' }; - }); -}; -``` - -**Parameters** -Each route handler has access to: - -- `request`: The incoming Fastify request object (query params, body, headers, etc.). -- `reply`: The response object, used to send back data or set headers. -- `fastify.harper`: The Harper database client, allowing direct table queries inside handlers. - -## URL Structure - -By default, routes are mounted as: - -``` -[Instance URL]:[Port]/[ProjectName]/[RoutePath] -``` - -Examples: - -- Project: `dogs` -- Route file: `routes/breeds.js` -- Handler path: `/breeds` - -Resulting URL: - -```bash -http://localhost:9926/dogs/breeds -``` - -If `path: /` is configured, routes are mounted at the root: - -```bash -http://localhost:9926/breeds -``` - -## Examples - -**Simple Route** - -```javascript -module.exports = async function (fastify, opts) { - fastify.get('/ping', async (request, reply) => { - return { pong: true }; - }); -}; -``` - -**Querying Harper Tables** - -```javascript -module.exports = async function (fastify, opts) { - fastify.get('/dogs', async (request, reply) => { - return fastify.harper.table('Dog').all(); - }); -}; -``` - -**Route With Params** - -```javascript -module.exports = async function (fastify, opts) { - fastify.get('/dogs/:id', async (request, reply) => { - const { id } = request.params; - return fastify.harper.table('Dog').get(id); - }); -}; -``` - -## Advanced Usage - -- Custom Middleware: Add validation, logging, or transformations by attaching hooks or decorators. -- Multiple Routes per File: A single route file can register multiple endpoints. -- Fastify Plugins: You can use the entire Fastify ecosystem (e.g., CORS, rate limiting). - -## Security Considerations - -Fastify routes do not automatically apply Harper’s table-level authentication and authorization. You should explicitly enforce access controls. - -Example using JWT: - -```javascript -fastify.get('/secure', { preValidation: [fastify.authenticate] }, async (request, reply) => { - return { secret: true }; -}); -``` - -For built-in authentication methods, see [Security](../../developers/security/). - -## Error Handling - -Use Fastify’s reply API for consistent error responses: - -```javascript -fastify.get('/error', async (request, reply) => { - reply.code(400).send({ error: 'Bad Request' }); -}); -``` diff --git a/versioned_docs/version-4.6/reference/components/built-in-extensions.md b/versioned_docs/version-4.6/reference/components/built-in-extensions.md index 49ec5fcb..f107cf11 100644 --- a/versioned_docs/version-4.6/reference/components/built-in-extensions.md +++ b/versioned_docs/version-4.6/reference/components/built-in-extensions.md @@ -9,7 +9,6 @@ Harper provides extended features using built-in extensions. They do **not** nee For more information read the [Components, Applications, and Extensions](../../developers/applications/) documentation section. - [Built-In Extensions](#built-in-extensions) - - [fastifyRoutes](#fastifyroutes) - [graphql](#graphql) - [graphqlSchema](#graphqlschema) - [jsResource](#jsresource) @@ -31,19 +30,6 @@ dataLoader: files: 'data/*.json' ``` -## fastifyRoutes - -Specify custom endpoints using [Fastify](https://fastify.dev/). - -This component is a [Resource Extension](./extensions#resource-extension) and can be configured with the [`files` and `urlPath`](./extensions#resource-extension-configuration) configuration options. - -Complete documentation for this feature is available here: [Define Fastify Routes](../../developers/applications/define-routes) - -```yaml -fastifyRoutes: - files: 'routes/*.js' -``` - ## graphql > GraphQL querying is **experimental**, and only partially implements the GraphQL Over HTTP / GraphQL specifications.