Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@jota-one/drosse

Package Overview
Dependencies
Maintainers
2
Versions
124
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jota-one/drosse

Mock your backend the right way.

  • 1.0.0
  • Source
  • npm
  • Socket score

Version published
Weekly downloads
175
increased by157.35%
Maintainers
2
Weekly downloads
 
Created
Source

What is it ?

Drosse is the last mock server you'll ever need.

Installation

via npm

  1. Simply install it as a dev dependency of the project you want to mock.
npm install --save-dev @jota-one/drosse
  1. Define a script in your package.json file for simpler usage
{
  "name": "my-node-project",
  "scripts": {
    "mock-server": "npx drosse serve -r path/to/mocks-directory"
  },
  "devDependencies": {
    "@jota-one/drosse": "^1.0.0"
  }
}

Usage

You need a directory where you will store all your mocks definitions.

  1. Create a directory anywhere in your project repository (or anywhere else).
  2. Update the package.json script you just added in the Installation phase to target your new mocks directory.
  3. In your mocks directory, create a routes.json file. This file will hold every single mocked route of your server.
  4. In the same directory, you can also create a .drosserc.js file. This file allows you to configure your mock server. It's optional but you will very likely need it.

Yes there are a couple of things to do yourself. But you're a developer, right? You know how to edit a JSON file or a JS file. In the upcoming releases, we will add a CLI and a UI, don't worry!

Let's focus first on these 2 files.

The routes.json file

This file is mandatory but you can customize its name in the .drosserc.js file (see below). This is where you define all the routes you want to mock. Each route is defined as a tree, with slash as separator.

:dizzy_face: Woot ? Tree ? Slash ? I just want to mock a couple of routes...

Ooook, an example worth a thousand sentences of bad explanation. Let's say you want to mock these 2 routes:

GET /api/users
GET /api/users/:id

You would create a tree in your routes.json file like this:

{
  "api": {
    "users": {
      ":id": {
        
      }
    }
  }
}

That's what we mean by "a tree". We consider that an API can be completely described in such a structure.

:smirk: Okay, but where do the actual mocks go ? And if have a GET AND a POST on /api/users ?

Good questions, thanks for asking.

The DROSSE object

That's where the DROSSE object comes in and saves our souls. Look at this:

{
  "api": {
    "users": {
      "DROSSE": {
        "get": {},
        "post": {}
      },
      ":id": {
        "DROSSE": {
          "get": {}
        }
      }
    }
  }
}

Everything happens inside the DROSSE object. You can insert a DROSSE object anywhere in the tree. A DROSSE object can contain HTTP verbs, like in the above example and a couple of other keys (more on these later).

:triumph: I WANT TO MOCK MY ROUTES!!! WHERE DO I PUT MY MOCKED CONTENTS???

There we go! You can mock your datas in 3 different ways:

  1. directly inside the routes.json file, using the body key (inlined mocks).
  2. in a static JSON file with a constrained name
  3. in a dynamic JS file (we consider it a service) with a constrained name
Inline mocks

Let's focus first on the body key, by far the simplest but by far the less cool. If you calm down, you'll be allowed to know about the 2 other solutions. Here's how you can mock your routes with inlined mocks.

{
  "api": {
    "users": {
      "DROSSE": {
        "get": {
          "body": [
            {"id": 1, "name": "Jorinho", "premium": false},
            {"id": 2, "name": "Tadai", "premium": true}
          ]
        },
        "post": {
          "body": {"success": true}
        }
      },
      ":id": {
        "DROSSE": {
          "get": {
            "body": {"id": 1, "name": "Jorinho", "premium": false}
          }
        }
      }
    }
  }
}

The above JSON is a fully working routes.json file. If you run your mock-server with this file, you will see something like this in your console (amongst other things):

4:26:27 PM -> GET     /api/users/:id
4:26:27 PM -> GET     /api/users
4:26:27 PM -> POST    /api/users

4:26:27 PM App Example JSON app running at:
4:26:27 PM  - http://localhost:8000

Note that the routes are defined in the right order to make sure that a less precise route won't take over a more precise one. Let's create a new route to illustrate this better:

{
  "api": {
    "users": {
      "DROSSE": {
        "get": {
          "body": [
            {"id": 1, "name": "Jorinho", "premium": false},
            {"id": 2, "name": "Tadai", "premium": true}
          ]
        },
        "post": {
          "body": {"success": true}
        }
      },
      ":id": {
        "DROSSE": {
          "get": {
            "body": {"id": 1, "name": "Jorinho", "premium": false}
          }
        }
      },
      "premiums": {
        "DROSSE": {
          "get": {
            "body": [{"id": 2, "name": "Tadai"}]
          }
        }
      }
    }
  }
}

We defined a new route corresponding to this one GET /api/users/premiums. Of course, if Drosse was stupid it would define it in the same order as what we did in the routes.json file, which would make the route unreachable, because it would always be captured by the GET /api/users/:id, passing "premiums" as the :id parameter. Let's see what happens if we reload our mock server.

4:40:59 PM -> GET     /api/users/premiums
4:40:59 PM -> GET     /api/users/:id
4:40:59 PM -> GET     /api/users
4:40:59 PM -> POST    /api/users

4:40:59 PM App Example JSON app running at:
4:40:59 PM  - http://localhost:8000

:tada::tada::tada: The /premiums route was declared before the generic /:id route! Conclusion: you don't have to worry about sorting your routes when you define them inside routes.json.

:open_mouth: That's awesome! It calmed me down totally... I'm ready to know more about the 2 other ways to mock my stuffs!

Static mocks (in separated files)

As you've probably noticed, the inline mocks are not that dynamic... For instance, if we take the GET /api/users/:id route, you can call it with any value for :id, you will always get the same response. Although it can be enough for most usecases, sometimes we want a little bit more.

That's where the so-called static mocks can help you. Where you have only one mock possibility with the inline (body) mock even for parametrized routes, static mocks offer you the possibility to have a different mock for each value of each parameter!

That is why these mocks are stored in separated files. It would otherwise bloat your routes.json file.

To define a static mock, simply set the static property of your DROSSE object to true. Let's take the previous example and replace the parametrized route inline mock by a static mock:

{
  "api": {
    "users": {
      "DROSSE": {
        "get": {
          "body": [
            {"id": 1, "name": "Jorinho", "premium": false},
            {"id": 2, "name": "Tadai", "premium": true}
          ]
        },
        "post": {
          "body": {"success": true}
        }
      },
      ":id": {
        "DROSSE": {
          "get": {
            "static": true
          }
        }
      }
    }
  }
}

With such a definition, when you call GET /api/users/65, drosse will look for a specific JSON file in the static subdirectory of your mocks directory.

:fire: You can redefine this static directory name in your .drosserc.js file (see below).

Drosse will look for different filenames, from the more precise to the more generic until it finds one that matches. Let's keep the above example and see which filenames will be looked for:

api.users.65.get.json
api.users.65.json
api.users.:id.json

If you have a route with several path parameters, drosse will ignore them from left to right. Example, for this route:

GET /api/users/:id/posts/:type

Assuming that you have 2 types of posts, unread and read and a big quantity of users, it's more convenient to be able to define a mocked list of read posts and another mocked list of unread posts, independently of the user. For that usecase you can then create only 2 files in your static directory:

api.users.:id.posts.read.get.json
api.users.:id.posts.unread.get.json

:fire: If you are not sure of the precedence for a given route, just try and check the drosse console. It will log each failed attempts.

If we try to call GET /api/users/3 and we have defined the following static mocks files in our static directory.

api.users.1.json
api.users.2.json
api.users:id.json
1:11:29 AM App Example JSON static app running at:
1:11:29 AM  - http://localhost:8000
1:11:29 AM  - http://172.22.22.178:8000

1:11:29 AM Mocks root: /some/path/mymocks

1:17:27 AM loadStatic: tried with [/some/path/mymocks/static/api.users.3.get.json]. File not found.
1:17:27 AM loadStatic: tried with [/some/path/mymocks/static/api.users.3.json]. File not found.
1:17:27 AM loadStatic: tried with [/some/path/mymocks/static/api.users.:id.get.json]. File not found.

You can see above that the system has first tried with the very precise api.users.3.get.json (resolved parameter + verb). Then it tries the same without verb (api.users.3.json). As it still fails, it tries without resolving the parameter, but again with the verb (api.users.:id.get.json) and finally find a corresponding mock file with api.users.:id.json. Of course this last one is not logged as it was found.

Services (aka dynamic mocks)

With the services, we cross some sort of line between pure mocking and an actual alternative backend for our frontend app. But sometimes it can be really useful. For example when you want to test interactivity in your app, or you don't have the backend yet because you're on a big project with separated teams and the backend will be implemented after the frontend, but you still have to deliver a working frontend at the same time as the backend, etc.

Drosse provides everything you need to implement an interactive mocked backend and let you focus on your frontend usecases.

[to be continued]

The .drosserc.js file

This file holds your mock server general configuration. It's optional as all its keys have default values. It must simply export a configuration object.

Here is a typical example of what it could contain.

module.exports = {
  name: 'My mocks app',
  port: 8000
}
All configuration keys
KeyDefault valueDescription
name(empty)The name of your app. Mostly used to recognize it in your console or in drosse UI.
port8000The port on which your mock server will run.
If not specified in .drosserc.js and already in use, Drosse will use the next available port if finds (8001, 8002, etc.)
routesFileroutesName of the routes definition file.
collectionsPathcollectionsRelative path to the loki collections directory from your mocks directory.
shallowCollections[]List of collections that should be recreated/overriden on each server restart.
servicesPathservicesRelative path to the services directory from your mocks directory.
staticPathstaticRelative path to the static files directory from your mocks directory.
databasemocks.dbName of your loki database dump file.

Features

  • Cascading Proxies
  • Fallback to static JSON mocks
  • In-memory db
  • Seamless integration to your project OR
  • Standalone global mode

In progress

  • CLI + UI
  • Persist state (in-memory db dump to JSON file)

Future features

  • Anonymize data
  • Journey
  • Sync with OpenAPI (Swagger) ?
  • GraphQL support ?

Warning

This project is in an early stage and under active development. API might change without notice.

Keywords

FAQs

Package last updated on 28 Oct 2020

Did you know?

Socket

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.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc