Mocks Server

repository·master·Indexed 43 days ago

https://github.com/mocks-server/main

A Node.js-based tool for running live, interactive mock APIs. It allows developers to define multiple responses for the same route and modify API behavior dynamically during runtime without restarting the server. The ecosystem includes the AdminApiClient for programmatic server management, a configuration provider (@mocks-server/config), and specialized data providers for React and Redux.

Tokens
38.3K
Snippets
139
Records
171
Agent score
54%

What's inside Mocks Server

  1. Overview of Mocks Server

    master

    Mocks Server is a Node.js mock server designed to run live, interactive mocks in place of real APIs. A key feature is the ability to define multiple different responses for the same route, allowing you to change the behavior of your mocked API dynamically while the server is running without needing a restart.

    Note: This project is discontinued and is no longer maintained. It will not receive new features, bug fixes, or security updates.

  2. Use @mocks-server/core for programmatic control or custom distributions

    master

    The @mocks-server/core package is the pluggable engine of the Mocks Server project. It is intended for developers who need to:

    1. Start Mocks Server programmatically: Control the server lifecycle directly within your own JavaScript/TypeScript code.
    2. Create custom distributions: Build a tailored version of Mocks Server by selecting and composing specific plugins.

    If you want the standard, pre-configured Mocks Server experience, use the @mocks-server/main package instead.

  3. How nested namespaces work in @mocks-server/logger

    master

    The @mocks-server/logger package uses a hierarchical namespace system built on top of Winston. You can create a root logger and then derive child namespaces using the .namespace(label) method.

    Key behaviors:

    • Path Tracking: Each namespace includes its full path in the logs (e.g., [parent:child]).
    • Log Storage: Logs are stored in two ways: a local store array specific to that namespace, and a single globalStore array that aggregates logs from all namespaces in the hierarchy.
    • Level Inheritance: Child namespaces inherit the log level of their parent by default, but you can control this behavior using setLevel options.
    • Event Emission: You can listen for changes to either the local namespace store or the global store using onChangeStore and onChangeGlobalStore.
    const { Logger } = require("@mocks-server/logger");
    
    const logger = new Logger();
    const dbLogger = logger.namespace("db");
    const dbConnectionLogger = dbLogger.namespace("connection");
    
    dbConnectionLogger.debug("Connecting");
    // Log format: 18:41:43:16 [debug][db:connection] Connecting
    
    // Accessing logs
    console.log(dbConnectionLogger.store); // Logs for 'connection' namespace
    console.log(logger.globalStore);       // Logs for all namespaces
  4. How to define and use mocked API routes

    master

    You can define mocked API routes using several formats and methods:

    File-based definition

    Define routes in any of the following file formats. Mocks Server automatically loads these files and watches them for changes:

    • YAML
    • JSON
    • JavaScript
    • TypeScript

    Programmatic definition

    Routes can be defined using the available APIs. They can range from:

    • Plain objects
    • Plain text
    • Express middlewares

    Route behaviors

    Routes can be configured to perform different actions, such as:

    • Sending a specific response
    • Proxying the request to another host (via the plugin-proxy plugin)
  5. Configuration priority and sources

    master

    The @mocks-server/config library resolves option values from multiple sources. When load() or init() is called, it searches in the following order (from lowest to highest priority):

    1. Default option value: The default property provided when the option is created.
    2. Programmatic config: An object passed to the load() or init() methods.
    3. Configuration file: Files searched in process.cwd() using [Cosmiconfig]. Supported formats include:
      • A [moduleName] property in package.json.
      • .[moduleName]rc (JSON or YAML).
      • .[moduleName]rc.json, .[moduleName]rc.yaml, .[moduleName].yml, .[moduleName]rc.js, or .[moduleName]rc.cjs.
      • [moduleName].config.js or [moduleName].config.cjs (can export an object, a function, or an async function).
    4. Environment variables: Variables prepended with the moduleName in SCREAMING_SNAKE_CASE.
    5. Process arguments: Command line arguments starting with --.
  6. Understand the Config lifecycle: init vs load

    master

    The Config instance follows a specific lifecycle:

    1. config.init(): Preloads all configuration sources and assigns values to existing options. Validation is not executed during this step, allowing you to add more namespaces or options dynamically (e.g., loading plugins that then register their own options). Option events are not yet emitted.
    2. config.load(): Executes validation (unknown properties will cause errors) and starts emitting events. This is the standard method to call to finalize configuration.
  7. How to control multiple Mocks Servers

    master

    To control multiple Mocks Server processes, you can pass an AdminApiClient instance as a second argument to all cy.mocks* commands. This allows you to target specific servers by their unique host/port configurations.

    import { AdminApiClient } from "@mocks-server/cypress-commands";
    
    const usersApiClient = new AdminApiClient({
      port: 3500,
      host: "127.0.0.1"
    });
    
    const gravatarApiClient = new AdminApiClient({
      port: 3200,
      host: "localhost"
    });
    
    describe("multi-server test", () => {
      before(() => {
        // Target the users server
        cy.mocksSetCollection("normal-user", usersApiClient);
        // Target the gravatar server
        cy.mocksSetCollection("server-error", gravatarApiClient);
      });
    });
  8. How namespaces and nested namespaces work

    master

    Namespaces allow for isolated configuration blocks, preventing collisions between different components or plugins. You can create namespaces using config.addNamespace(name). Namespaces can also be nested.

    Accessing namespaced options via different sources

    If you have a nested structure: moduleName: "mocks", namespaceA, and namespaceB containing optionA:

    • Configuration files or programmatic objects:
      {
        "namespaceA": {
          "namespaceB": {
            "optionA": "foo-value"
          }
        }
      }
    • Environment variables (use SCREAMING_SNAKE_CASE with all parent names): MOCKS_NAMESPACE_A_NAMESPACE_B_OPTION_A="foo-value"
    • Command line arguments (use dot notation): --namespaceA.namespaceB.optionA="foo-value"
    const config = new Config({ moduleName: "mocks" });
    
    config
      .addNamespace("namespaceA")
      .addNamespace("namespaceB")
      .addOption({ name: "optionA", type: "string", default: "foo" });
  9. What are Nested Collections?

    master

    Nested Collections is a collections manager that allows you to store items consisting of an id and a value. It supports a recursive structure where you can create descendant collections within a parent collection.

    A key feature is the ability to retrieve all items from the entire hierarchy in a single flat array via the flat property, where each item is augmented with a collection path (e.g., parent:child:grandchild). It also supports event listening via onChange to react to any changes in the hierarchy.

    const { NestedCollections } = require("@mocks-server/nested-collections");
    
    const alerts = new NestedCollections("alerts");
    alerts.set("root", "This alert is stored in the root collection");
    
    const pluginsAlerts = alerts.collection("plugins");
    pluginsAlerts.set("foo-alert-id", "This alert is stored in the plugins collection");
    
    console.log(alerts.flat);
    /*
    [
      { id: 'root', value: '...', collection: 'alerts' },
      { id: 'foo-alert-id', value: '...', collection: 'alerts:plugins' }
    ]
    */
  10. Quickstart with @mocks-server/config

    master

    To use the configuration provider, instantiate the Config class, create namespaces for different components, and define options with specific types. After defining your configuration structure, call config.load() to resolve values from various sources (files, env vars, etc.). You can also listen for changes to option values using option.onChange().

    const Config = require("@mocks-server/config");
    
    // Create config
    const config = new Config({ moduleName: "mocks" });
    
    // Create namespace
    const namespace = config.addNamespace("fooNamespace");
    
    // Create option
    const option = namespace.addOption({
      name: "fooOption",
      type: "string",
      default: "foo-value",
    });
    
    // Load configuration
    config.load().then(() => {
      // Read value
      console.log(option.value);
      // Set value
      option.value = "foo-new-value";
    });
    
    // Listen to onChange events
    option.onChange((newValue) => {
      console.log(`Option has a new value: ${newValue}`);
    });
  11. Configure Mocks Server

    master

    Mocks Server can be configured using three primary methods:

    1. Configuration File: Modify the configuration file located at the root folder of your project.
    2. Command Line Arguments: Pass configuration options directly via the CLI.
    3. Environment Variables: Use environment variables to set server options.

    To change options dynamically while the server is running, use integration tools like the administration REST API or the interactive CLI.