• Stars
    star
    832
  • Rank 54,811 (Top 2 %)
  • Language
    JavaScript
  • Created almost 12 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Node server for dynamic, fake JSON.

dyson

Node server for dynamic, fake JSON.

Introduction

Dyson allows you to define JSON endpoints based on a simple path + template object:

# my-stubs/users.js
module.exports = {
  path: '/users/:userId',
  template: {
    id: params => Number(params.userId),
    name: () => faker.name.findName(),
    email: () => faker.internet.email(),
    status: (params, query) => query.status,
    lorem: true
  }
};
$ dyson ./my-stubs
$ curl http://localhost:3000/users/1?status=active
{
  "id": 1,
  "name": "Josie Greenfelder",
  "email": "[email protected]",
  "status": "active",
  "lorem": true
}

When developing client-side applications, often either static JSON files, or an actual server, backend, datastore, or API, is used. Sometimes static files are too static, and sometimes an actual server is not available, not accessible, or too tedious to set up.

This is where dyson comes in. Get a full fake server for your application up and running in minutes.

Build Status npm package dependencies npm version

Overview

  • Dynamic responses, based on
    • Request path
    • GET/POST parameters
    • Query parameters
    • Cookies
  • HTTP Methods: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
  • Dynamic HTTP status codes
  • CORS
  • Proxy (e.g. fallback to actual services)
  • Delayed responses
  • Required parameter validation
  • Includes random data generators
  • Includes dummy image generator
    • Use any external or local image service (included)
    • Supports base64 encoded image strings

Endpoint Configuration

Configure endpoints using simple objects:

module.exports = {
  path: '/user/:id',
  method: 'GET',
  template: {
    id: (params, query, body) => params.id,
    name: g.name,
    address: {
      zip: g.zipUS,
      city: g.city
    }
  }
};

The path string is the usual argument provided to Express, as in app.get(path, callback);.

The template object may contain properties of the following types:

  • A Function will be invoked with arguments (params, query, body, cookies, headers).
  • Primitives of type String, Boolean, Number, Array are returned as-is
  • An Object will be recursively iterated.
  • A Promise will be replaced with its resolved value.

Note: the template itself can also be a function returning the actual data. The template function itself is also invoked with arguments (params, query, body, cookies, headers).

Defaults

The default values for the configuration objects:

module.exports = {
  cache: false,
  delay: false,
  proxy: false,
  size: () => _.random(2, 10),
  collection: false,
  callback: response.generate,
  render: response.render
};
  • cache: true means that multiple requests to the same path will result in the same response
  • delay: n will delay the response with n milliseconds (or between [n, m] milliseconds)
  • proxy: false means that requests to this file can be skipped and sent to the configured proxy
  • size: fn is the number of objects in the collection
  • collection: true will return a collection
  • callback: fn
    • the provided default function is doing the hard work (can be overridden)
    • used as middleware in Express
    • must set res.body and call next() to render response
  • render: fn
    • the default function to render the response (basically res.send(200, res.body);)
    • used as middleware in Express

Fake data generators

You can use anything to generate data. Here are some suggestions:

Just install the generator(s) in your project to use them in your templates:

npm install dyson-generators --save-dev

Containers

Containers can help if you need to send along some meta data, or wrap the response data in a specific way. Just use the container object, and return the data where you want it. Functions in the container object are invoked with arguments (params, query, data):

module.exports = {
  path: '/users',
  template: user.template,
  container: {
    meta: (params, query, data) => ({
      userCount: data.length
    }),
    data: {
      all: [],
      the: {
        way: {
          here: (params, query, data) => data
        }
      }
    }
  }
};

And an example response:

{
  "meta": {
    "userCount": 2
  },
  "data": {
    "all": [],
    "the": {
      "way": {
        "here": [
          {
            "id": 412,
            "name": "John"
          },
          {
            "id": 218,
            "name": "Olivia"
          }
        ]
      }
    }
  }
}

Combined requests

Basic support for "combined" requests is available, by means of a comma separated path fragment.

For example, a request to /user/5,13 will result in an array of the responses from /user/5 and /user/13.

The , delimiter can be configured (or disabled).

Status codes

By default, all responses are sent with a status code 200 (and the Content-Type: application/json header).

This can be overridden with your own status middleware, e.g.:

module.exports = {
  path: '/feature/:foo?',
  status: (req, res, next) => {
    if (req.params.foo === '999') {
      res.status(404);
    }
    next();
  }
};

Would result in a 404 when requesting /feature/999.

Images

In addition to configured endpoints, dyson registers a dummy image service at /image. E.g. requesting /image/300x200 serves an image with given dimensions.

This service is a proxy to Dynamic Dummy Image Generator by Russell Heimlich.

JSONP

Override the render method of the Express middleware in the endpoint definition. In the example below, depending on the existence of the callback parameter, either raw JSON response is returned or it is wrapped with the provided callback:

module.exports = {
  render: (req, res) => {
    const callback = req.query.callback;
    if (callback) {
      res.append('Content-Type', 'application/javascript');
      res.send(`${callback}(${JSON.stringify(res.body)});`);
    } else {
      res.send(res.body);
    }
  }
};

File Upload

Ex: return file name
formDataName = 'file'

module.exports = {
  render: (req, res) => {
    if (callback) {
      res.send({ fileName: req.files.file.name });
    } else {
      res.send(res.body);
    }
  }
};

HTTPS

If you want to run dyson over SSL you have to provide a (authority-signed or self-signed) certificate into the options.https the same way it's required for NodeJS built-in https module. Example:

const fs = require('fs');

const app = dyson.createServer({
  configDir: `${__dirname}/dummy`,
  port: 3001,
  https: {
    key: fs.readFileSync(`${__dirname}'/certs/sample.key`),
    crt: fs.readFileSync(`${__dirname}/certs/sample.crt`)
  }
});

Note: if running SSL on port 443, it will require sudo privileges.

GraphQL

If you want dyson to support GraphQL endpoints, you can build your own logic with the render override, or use dyson-graphql. Example:

npm install dyson-graphql --save-dev
const dysonGraphQl = require('dyson-graphql');

const schema = `
  type User {
    id: Int!
    name: String!
  }

  type Query {
    currentUser: User!
  }

  type Mutation {
    createUser(name: String!): User!
    updateUser(id: Int!, name: String!): User!
  }
`;

module.exports = {
  path: '/graphql',
  method: 'POST',
  render: dysonGraphQl(schema)
    .query('currentUser', { id: 987, name: 'Jane Smart' })
    .mutation('createUser', ({ name }) => ({ id: 456, name }))
    .mutation('updateUser', ({ id, name }) => {
      if (id < 1000) {
        return { id, name };
      }

      throw new Error("Can't update user");
    })
    .build()
};

Custom middleware

If you need some custom middleware before or after the endpoints are registered, dyson can be initialized programmatically. Then you can use the Express server instance (appBefore or appAfter in the example below) to install middleware before or after the dyson services are registered. An example:

const dyson = require('dyson');
const path = require('path');

const options = {
  configDir: path.join(__dirname, 'services'),
  port: 8765
};

const configs = dyson.getConfigurations(options);
const appBefore = dyson.createServer(options);
const appAfter = dyson.registerServices(appBefore, options, configs);

console.log(`Dyson listening at port ${options.port}`);

Dyson configuration can also be installed into any Express server:

const express = require('express');
const dyson = require('./lib/dyson');
const path = require('path');

const options = {
  configDir: path.join(__dirname, 'services')
};

const myApp = express();
const configs = dyson.getConfigurations(options);

dyson.registerServices(myApp, options, configs);

myApp.listen(8765);

Installation

The recommended way to install dyson is to install it locally and put it in your package.json:

npm install dyson --save-dev

Then you can use it from scripts in package.json using e.g. npm run mocks:

{
  "name": "my-package",
  "version": "1.0.0",
  "scripts": {
    "mocks": "dyson mocks/"
  }
}

You can also install dyson globally to start it from anywhere:

npm install -g dyson

Project

You can put your configuration files anywhere. The HTTP method is based on:

  • The method property in the configuration itself.
  • The folder, or an ancestor folder, containing the configuration is an HTTP method. For example mocks/post/sub/endpoint.js will be an endpoint listening to POST requests.
  • Defaults to GET.
dyson [dir]

This starts the services configured in [dir] at localhost:3000.

You can also provide an alternative port number by just adding it as a second argument (e.g. dyson path/ 8181).

Demo

Project Configuration

Optionally, you can put a dyson.json file next to the configuration folders (inside [dir]). It enables to configure some behavior of dyson:

{
  "multiRequest": ",",
  "proxy": true,
  "proxyHost": "http://dyson.jit.su",
  "proxyPort": 8080,
  "proxyDelay": [200, 800]
}
  • Setting multiRequest to false disables the combined requests feature.
  • Setting bodyParserJsonLimit or bodyParserUrlencodedLimit to 1mb increases the limit to 1mb from the bodyParser's default of 100kb.
  • By default, the proxy is set to false

Watch/auto-restart

If you want to automatically restart dyson when you change your configuration objects, you can add nodemon as a devDependency. Say your configuration files are in the ./api folder, you can put this in your package.json:

"scripts": {
  "mocks": "dyson mocks/",
  "watch": "nodemon --watch mocks --exec dyson mocks"
}

Development & run tests

git clone [email protected]:webpro/dyson.git
cd dyson
npm install
npm test

Articles about dyson

License

MIT

More Repositories

1

awesome-dotfiles

A curated list of dotfiles resources.
8,206
star
2

reveal-md

reveal.js on steroids! Get beautiful reveal.js presentations from any Markdown file
JavaScript
3,365
star
3

programming-principles

Categorized overview of programming principles & design patterns
2,424
star
4

knip

βœ‚οΈ Find unused files, dependencies and exports in your JavaScript and TypeScript projects. Knip it before you ship it!
TypeScript
1,842
star
5

dotfiles

Dotfiles for macOS
Shell
983
star
6

DOMtastic

Small, fast, and modular DOM and event library for modern browsers.
JavaScript
763
star
7

awesome-newsletters

The best (weekly) newsletters
379
star
8

component-styleguide

Simple styleguide framework
JavaScript
122
star
9

Automated-SPA-Testing

Automated unit & functional testing for web applications
105
star
10

responsive-web-apps

Building Responsive Web Applications
JavaScript
63
star
11

grunt-release-it

Interactive release task for Git repositories. Optionally release a build to distribution/component repository.
JavaScript
48
star
12

versionify

Browserify transform to replace placeholder with package version
JavaScript
33
star
13

react-redux-demo

Fun Fair
JavaScript
30
star
14

baseplate

The baseplate project provides excellent workflow & tooling to develop, build, and test non-trivial SPAs.
JavaScript
24
star
15

bron

πŸƒβ€β™‚οΈ Fast & tiny test runner for Node.js
JavaScript
18
star
16

frameground

Compare JavaScript Frameworks. Please share your knowledge!
JavaScript
17
star
17

dyson-generators

Fake data generators, used by dyson and dyson-image
JavaScript
17
star
18

dyson-demo

Demo package for dyson
JavaScript
14
star
19

requirejs-handlebars

Simple Handlebars plugin for RequireJS
JavaScript
13
star
20

precompiled-templates

Performance, footprint and configuration of template engines and precompiled templates
JavaScript
12
star
21

ts-morph-helpers

Helpers for ts-morph
TypeScript
12
star
22

component-styleguide-example

Example for component-styleguide
CSS
9
star
23

DuckJS

Tiny and powerful module loader to lazy load HTML+CSS+JS
JavaScript
8
star
24

benchrunner

Benchmark Suite Runner for benchmark.js
JavaScript
8
star
25

sandbox

Source files for sandbox.webpro.nl (offline)
JavaScript
6
star
26

dyson-image

JavaScript
6
star
27

webpro.nl

Source code of webpro.nl
Astro
6
star
28

doxstrap

Yet another documentation generator
HTML
5
star
29

vars

Common patterns in Vue, Angular, React and Svelte
JavaScript
5
star
30

parse-openapi

OpenAPI v3 parser
TypeScript
5
star
31

nx-tsc

Nx executor to type-check project source files using `tsc --noEmit`
JavaScript
5
star
32

hyte

HYbrid TEmplating for the browser and Node
JavaScript
4
star
33

Websites-vs-Web-Applications

Responsive Adaptive Rainwebs FTW!
4
star
34

release-it-monorepo

4
star
35

github-pages-example

GitHub Pages Example
3
star
36

bookstore

Simple application to learn GraphQL and Next.js.
JavaScript
3
star
37

markdown-rambler

Yet another opinionated & powerful static site generator.
TypeScript
3
star
38

bump-file

Bump JSON files (e.g. package.json and friends)
JavaScript
3
star
39

openapi-parser

OpenAPI v3 parser
TypeScript
2
star
40

fix-sourcemaps

Fix sources and file in sourcemaps
JavaScript
2
star
41

jaguarundi

Ant build script to optimize and version Javascript, CSS, and HTML files
JavaScript
2
star
42

requirejs-hogan

Simple Hogan plugin for RequireJS
JavaScript
2
star
43

requirejs-dust

Simple Dust plugin for RequireJS
JavaScript
2
star
44

deprecated-obj

Compares deprecations against a configuration object, and returns a compliant object and violations
JavaScript
2
star
45

DOMtastic-release

JavaScript
1
star
46

is-subdir

Check if a directory is a subdirectory
JavaScript
1
star
47

SpringbokJS

Installs modules (traditional object or AMD-style) based on HTML attributes.
JavaScript
1
star
48

last-publish

Get the date of the last published version of a package in the npm registry
JavaScript
1
star