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 🙏

© 2024 – Pkg Stats / Ryan Hefner

rest-easy-loki

v1.5.5

Published

A REST interface for lokijs supporting CRUD operations and automatic creation of new collections.

Downloads

13

Readme

REST-EASY-LOKI

A simple REST interface for the in-memory database, lokijs, featuring:

  • Automatic creation of collections, including CRUD actions, pagination and MongoDB-like queries.
  • Simple authorization using whitelisting domain names and API keys via environment variables.
  • Statically sharing the public folder
  • Uploading files using the upload folder
  • Retrieving environment variables starting with LOKI_ via REST
  • Configuring the database collections using a config file
  • Add support for CORS and compression

This version has moved from the default LokiFsAdapter to the more performing LokiFsStructuredAdapter. Besides a performance gain, it also means that we don't end up with a single database file anymore, but one overall database file and one per collection.

Development

npm install # Or pnpm i
npm start # Will transpile the TypeScript project to JavaScript and run node on every change.

Usage

To simply run the lokijs server and expose the CRUD services.

npm run serve

To embed it in your own project, do something like the following:

import * as Koa from 'koa'; // You only need to include @types/koa in your devDependencies, not Koa itself.
import { createApi, db } from 'rest-easy-loki';

export const collectionName = 'documents';

const port = process.env.LOKI_PORT || '3000';
const dbName = process.env.LOKI_DB;
const cors = (process.env.LOKI_CORS || 'true') === 'true';
const sizeLimit = process.env.LOKI_SIZE_LIMIT || '25mb';

export const startService = () => {
  db.startDatabase(dbName, () => {
    const { api } = createApi({ 
      cors,
      sizeLimit,
      compression: true, // Compress data using gzip
      upload: 'upload',  // Allow uploading data to this folder
      public: 'public'   // Serve all files in this folder, e.g. SPA
    }) as Koa;
    api.listen(port);
    console.log(`Server running on port ${port}.`);
  });
};
startService();

Configuration

Reads .env file for specifying the database name, port, CORS and message size limits. E.g.

LOKI_PORT=3030
LOKI_DB="simple.db"
LOKI_CORS=true
LOKI_COMPRESSION=true
LOKI_CONFIG="config.json"
LOKI_SIZE_LIMIT="250mb"
LOKI_PRETTY=true
LOKI_AUTHZ_READ=""
LOKI_AUTHZ_CREATE="key1"
LOKI_AUTHZ_UPDATE="key1"
LOKI_AUTHZ_DELETE="key1"
LOKI_AUTHZ_WHITELIST="localhost"

When creating the database for the first time, you optionally can also configure the database collections using LokiJS options, e.g. by specifying unique property names, or properties that must be indexed. In addition, you can import any existing JSON file in one go. For example, see config.json below: with it, you create two collections, users and projects, and each collection has a unique property id and several indices. In addition, it imports the file specified by jsonImport.

{
  "collections": {
    "users": {
      "jsonImport": "./employees.json",
      "unique": ["id"],
      "indices": ["first", "last", "keywords", "summary"]
    },
    "projects": {
      "jsonImport": "./projects.json",
      "unique": ["id"],
      "indices": ["name", "keywords", "summary"]
    }
  }
}

The configuration file needs to adhere to the ILokiConfiguration interface, as specified below:

/** From LokiJS typings, but not exported */
export interface CollectionOptions<E> {
  disableMeta: boolean;
  disableChangesApi: boolean;
  disableDeltaChangesApi: boolean;
  adaptiveBinaryIndices: boolean;
  asyncListeners: boolean;
  autoupdate: boolean;
  clone: boolean;
  cloneMethod: 'parse-stringify' | 'jquery-extend-deep' | 'shallow' | 'shallow-assign' | 'shallow-recurse-objects';
  serializableIndices: boolean;
  transactional: boolean;
  ttl: number;
  ttlInterval: number;
  exact: (keyof E)[];
  unique: (keyof E)[];
  indices: keyof E | (keyof E)[];
}

export interface ExtendedCollectionOptions<E> extends CollectionOptions<E> {
  /** JSON file to import: expects a JSON array which will be inserted into the collection */
  jsonImport?: string;
}

export interface ILokiConfiguration<T = {}> {
  /** Create collections on startup if there are no collections yet */
  collections?: {
    /** Name of the collection */
    [collectionName: string]: ExtendedCollectionOptions<T>;
  };
}

If you do specify one or more unique names, you can query the REST interface via https://localhost:3000/api/COLLECTION_NAME/USERS/THOR.

Managing collections (CRUD)

export interface IMutation extends ILokiObj {
  /**
   * Save changes to collection: if set, save this object,
   * except the `saveChanges` property, to the `saveChanges` collection
   */
  saveChanges?: string;
  /** RFC6902 JSON patch */
  patch?: Operation[];
}

Filtering collections

Sharing the public folder

You can use the public folder for sharing static files or your own web application. Enabled by default.

Uploading files

You can use the upload folder for uploading files to a (automatically created) CONTEXT folder, if enabled on start-up using the -u instruction. Test it via curl -F "[email protected]" http://localhost:3030/upload/:CONTEXT. Files will be served from http://localhost:3030/:CONTEXT/ORG_FILENAME. When uploading the same filename in the same context, the previous version will be overwritten. No index file is created, so the contents of the locally created folders are not visible externally. Also note that the CONTEXT supports sub-folders too.

Socket.io support

If enabled using the io flag (or -i) so clients can subscribe to receive updates when a value has changed. Clients can either subscribe to a collection socket.subscribe('COLLECTION_NAME'), or to a collection item socket.subscribe('COLLECTION_NAME/$LOKI'). The latter is, for example, useful when you have multiple editors. Subscribers receive the updated item.

Serving environment variables

The http://localhost:3000/api/env serves all environment variables that start with LOKI_ (except the LOKI_AUTHZ_, so you don't accidentally share secrets). Since all key-value pairs are strings, a type conversion to boolean, number and arrays (using the , as separator) is performed.

Authorization

  • Simple authorization can be enabled by specifying environment variables: LOKI_AUTHZ_CREATE, LOKI_AUTHZ_READ, LOKI_AUTHZ_UPDATE, LOKI_AUTHZ_DELETE, where the value is a comma-separated list of API keys. If no authz is set, all CRUD actions are allowed. Otherwise, your query needs to set the x-api-key header.
  • You can require it in your own project.