npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

retold-data-service

v2.0.11

Published

Serve up a whole model!

Readme

Retold Data Service

An all-in-one Fable service that turns a Stricture schema into a complete REST API

Retold Data Service combines Meadow (data access), Orator (API server), and Meadow Endpoints (REST routes) into a single service provider. Point it at a compiled Stricture model and it auto-generates typed CRUD endpoints for every entity -- complete with filtering, pagination, soft deletes, and behavior injection hooks.

Features

  • Zero-Boilerplate REST - Define your schema once, get full CRUD endpoints for every entity automatically
  • Provider-Agnostic - Swap between MySQL, MSSQL, SQLite, or ALASQL without changing application code
  • Schema-Driven - Stricture DDL compiles into a model that drives endpoint generation, validation, and defaults
  • Lifecycle Hooks - onBeforeInitialize, onInitialize, and onAfterInitialize for custom startup logic
  • Behavior Injection - Pre- and post-operation hooks on every CRUD operation for custom business logic
  • DAL Access - Direct programmatic data access alongside the REST endpoints for server-side logic
  • Fable Service Provider - First-class service in the Fable ecosystem with logging, configuration, and DI
  • Double-Init Protection - Guards against accidental re-initialization

Quick Start

const libFable = require('fable');
const libRetoldDataService = require('retold-data-service');

const _Fable = new libFable({
	APIServerPort: 8086,
	MySQL: {
		Server: '127.0.0.1',
		Port: 3306,
		User: 'root',
		Password: 'secret',
		Database: 'bookstore',
		ConnectionPoolLimit: 20
	},
	MeadowConnectionMySQLAutoConnect: true
});

_Fable.serviceManager.addServiceType('RetoldDataService', libRetoldDataService);

_Fable.serviceManager.instantiateServiceProvider('RetoldDataService', {
	StorageProvider: 'MySQL',
	StorageProviderModule: 'meadow-connection-mysql',
	FullMeadowSchemaPath: `${__dirname}/model/`,
	FullMeadowSchemaFilename: 'MeadowModel-Extended.json'
});

_Fable.RetoldDataService.initializeService(
	(pError) =>
	{
		if (pError)
		{
			return console.log('Error initializing data service:', pError);
		}
		console.log('REST API is running on port 8086');
	});

Installation

npm install retold-data-service

How It Works

Retold Data Service orchestrates the full Meadow stack into a single initialization sequence:

Fable (Core)
  └── Retold Data Service
        ├── Orator (API Server)
        │     └── Restify (HTTP Engine)
        ├── Meadow (Data Access Layer)
        │     ├── Schema (from compiled Stricture model)
        │     ├── FoxHound (Query DSL)
        │     └── Provider (MySQL / MSSQL / SQLite / ALASQL)
        └── Meadow Endpoints (REST Routes)
              ├── Create   POST   /1.0/Entity
              ├── Read     GET    /1.0/Entity/:ID
              ├── Reads    GET    /1.0/Entities/:Begin/:Cap
              ├── Update   PUT    /1.0/Entity
              ├── Delete   DELETE /1.0/Entity/:ID
              ├── Count    GET    /1.0/Entities/Count
              ├── Schema   GET    /1.0/Entity/Schema
              └── New      GET    /1.0/Entity/Schema/New

Options

| Option | Default | Description | |--------|---------|-------------| | StorageProvider | 'MySQL' | Database provider name | | StorageProviderModule | 'meadow-connection-mysql' | Node module for the provider | | FullMeadowSchemaPath | process.cwd() + '/model/' | Path to the compiled schema | | FullMeadowSchemaFilename | 'MeadowModel-Extended.json' | Compiled model filename | | AutoStartOrator | true | Start the HTTP server automatically | | APIServerPort | 8080 | Port for the HTTP server |

SQLite Example

For embedded or test scenarios, use the in-memory SQLite provider:

const libMeadowConnectionSQLite = require('meadow-connection-sqlite');

const _Fable = new libFable({
	APIServerPort: 8086,
	SQLite: { SQLiteFilePath: ':memory:' }
});

_Fable.serviceManager.addServiceType('RetoldDataService', libRetoldDataService);
_Fable.serviceManager.addServiceType('MeadowSQLiteProvider', libMeadowConnectionSQLite);
_Fable.serviceManager.instantiateServiceProvider('MeadowSQLiteProvider');

_Fable.MeadowSQLiteProvider.connectAsync(
	(pError) =>
	{
		_Fable.serviceManager.instantiateServiceProvider('RetoldDataService', {
			StorageProvider: 'SQLite',
			StorageProviderModule: 'meadow-connection-sqlite',
			FullMeadowSchemaPath: `${__dirname}/model/`,
			FullMeadowSchemaFilename: 'MeadowModel-Extended.json'
		});

		_Fable.RetoldDataService.initializeService(
			(pError) =>
			{
				console.log('REST API running with in-memory SQLite');
			});
	});

Behavior Injection

Add custom logic before or after any CRUD operation:

_Fable.MeadowEndpoints.Book.controller.BehaviorInjection.setBehavior(
	'Create-PreOperation',
	(pRequest, pRequestState, fRequestComplete) =>
	{
		if (!pRequestState.RecordToCreate.Title)
		{
			pRequest.CommonServices.sendCodedResponse(
				pRequestState.response, 400, 'Title is required');
			return fRequestComplete(true);
		}
		return fRequestComplete(false);
	});

Lifecycle Hooks

Customize initialization by subclassing:

class MyDataService extends libRetoldDataService
{
	onAfterInitialize(fCallback)
	{
		this.fable.log.info('Injecting custom behaviors...');
		this.fable.MeadowEndpoints.Book.controller.BehaviorInjection
			.setBehavior('Read-PostOperation', myCustomHook);
		return fCallback();
	}
}

DAL Access

Query data directly alongside the REST endpoints:

let tmpQuery = _Fable.DAL.Book.query
	.addFilter('Genre', 'Science Fiction')
	.addSort({ Column: 'PublicationYear', Direction: 'Descending' })
	.setCap(25)
	.setBegin(0);

_Fable.DAL.Book.doReads(tmpQuery,
	(pError, pQuery, pRecords) =>
	{
		console.log(`Found ${pRecords.length} sci-fi books`);
	});

Backplane Endpoints

For dynamic model loading at runtime, Retold Data Service provides backplane endpoints:

| Endpoint | Method | Description | |----------|--------|-------------| | /BackPlane/:Version/Load/MeadowModel | POST | Load a full Meadow model | | /BackPlane/:Version/Load/MeadowSchema | POST | Load a Meadow entity schema | | /BackPlane/:Version/Load/StrictureDDL | POST | Load and compile a Stricture DDL | | /BackPlane/:Version/Model/Primary/ | GET | Get the primary service model | | /BackPlane/:Version/Model/Composite/ | GET | Get composite models | | /BackPlane/:Version/Settings | POST | Merge in provider settings | | /BackPlane/:Version/SetProvider/:Name | GET | Set the default provider | | /BackPlane/:Version/SetProvider/:Name/:Entity | GET | Set a per-entity provider |

Testing

npm test

Tests use an in-memory SQLite provider and require no external database server.

Documentation

Detailed documentation is available in the docs/ folder and can be served locally:

npx docsify-cli serve docs

Related Packages

License

MIT

Contributing

Pull requests are welcome. For details on our code of conduct, contribution process, and testing requirements, see the Retold Contributing Guide.