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

matryoshka-server

v0.1.6

Published

Create a mock API Gateway by rewrite your existing APIs with mock fields and generating new API on the fly.

Downloads

9

Readme

Matryoshka

Create a mock API Gateway by rewrite your existing APIs with mock fields and generating new API on the fly.

Installation

# npm
npm i matryoshka-server

# yarn
yarn add matryoshka-server

QuickStart

Start the proxy server

  1. create a file server.js with the following content.
const {ProxyServer} = require('matryoshka-server')

const server = new ProxyServer({
  upstreamUrl: "http://localhost:3000",
  port: 8081
})

// The proxy server forward
// all the request to the upStreamUrl and 
// change the name of 'posts' API to 'new-posts'

// now when you call http://localhost:8081/new-posts
// it will redirect the request to http://localhost:3000/posts
server.proxy("posts")
  .renameTo("new-posts")

// server running 
server.serve()
  1. Run node server.js and you can access your proxy server on http://localhost:8081
  2. To generate a public https url (especially for mobile development),
    • Download localtunnel and run lt -p 8081.
    • This will generate a https url for your proxy server

Basic Functions

update/delete/create API Endpoints

const {OverrideResponse, ProxyServer} = require('matryoshka-server')

const server = new ProxyServer({
   upstreamUrl:"http://localhost:3000",
   port:8080
})

// rename http://localhost:3000/posts => http://localhost:8080/new-posts
server.proxy("posts")
        .renameTo("new-posts")

// remove http://localhost:8080/comments (return 404)
server.remove("comments")

// create GET http://localhost:8080/new-endpoint (return {success:true})
server.addEndPoint("new-endpoint","GET").response(
        OverrideResponse({
           success:true
        })
)

// server running
server.serve()

Rewrite request and response


server.updateEndPoint("posts","GET")
        // rewrite request
        .request(
                // update query
                // when you call      http://localhost:8080/posts?page=2&page_size=2&new_name=value
                // it will convert to http://localhost:3000/posts?_page=2&_limit=2&old_name=value
                RewriteQuery(
                        Rename({
                           "page":"_page",
                           "page_size":"_limit",
                           "new_name":"old_name"
                        })
                ),
                // update body
                RewriteBody(
                        Rename({
                           "new_name":"old_name",
                           "field1":{
                              "field2":"old_name2" // nested field
                           }
                        }),
                        Update({
                           "field3.field4": "new value", // set new value
                           "field5.field6": (currentValue:number)=>currentValue * 2, // set new value according to current value
                        })
                ),
                RewriteHeader(
                        Add({
                           "new-header":"some value" // add new header
                        })
                )
        )
        .proxy() // call upstream
        .response(
                // rewrite response
                RewriteResponse(
                        Add({
                           "[].new_field":"new_value" // add new field on every item inside array
                        })
                ),
                // rewrite return status code
                OverrideStatus(201),
                // rewrite response header
                RewriteResponseHeader(
                        Remove("vary")
                )
        )

Conditional rewrite


server.updateEndPoint("posts","GET")
        // rewrite response only when status code is 200
        .proxy()
        // when status code is 200
        .when(Status(200),
                RewriteResponse(
                        Add("[].new_field","new_value") // add new field on every item inside array
                )
        )
        // when status code is not 200
        .when(not(Status(200)),
                RewriteResponse(
                        Add("error","some error message")
                )
        )

Generate Mock data

server.addEndPoint("users","GET")
        // generate mock data
        .response(
                OverrideResponse(Template({
                   status:"some_code", // add hard code value
                   "data[+3]":{ // generate an array of length 3
                      id:1,
                      avatar:Fake("image.avatar"), // generate fake value from @faker-js https://github.com/faker-js/faker
                      firstName:values("name 1","name 2"), // generate fake value from hard value list
                      lastName:Fake("name.lastName"),
                      fullName:values("firstname lastname",FakeExpr("{{name.firstName}} {{name.lastName}}")) // combine hardcode value with @faker-js
                   }
                }))
        )

this will generate the following response

{
    "status": "some_code",
    "data": [
        {
            "id": 1,
            "avatar": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/870.jpg",
            "firstName": "name 1",
            "lastName": "Predovic",
            "fullName": "firstname lastname"
        },
        {
            "id": 1,
            "avatar": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/891.jpg",
            "firstName": "name 2",
            "lastName": "Rath",
            "fullName": "Maurine Rath"
        },
        {
            "id": 1,
            "avatar": "https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/357.jpg",
            "firstName": "name 1",
            "lastName": "Graham",
            "fullName": "Edison Keebler"
        }
    ]
}

You can also use generate array with template

server.addEndPoint("books","GET")
  .proxy()
  // generate mock data
  .response(
    OverrideResponse(TemplateArray({
      id:values(1,2),
      name:values("name1","name2")
    },2))
  )

this will generate

[
    {
        "id": 1,
        "name": "name1"
    },
    {
        "id": 2,
        "name": "name2"
    }
]

You can also use template to add new fields to existing API's response

// use updateEndPoint to update existing API
server.updateEndPoint("posts","GET")
        .proxy()
        // generate mock data
        .response(
                RewriteResponse(
                        Add({
                           "[]":{
                              newField:values(1,2,3),
                              "nestArray[+3]":{
                                 name:Fake("name.firstName")
                              }
                           }
                        })
                )
        )

this will update

[
    {
        "id": 1,
        "title": "json-server1",
        "author": "typicode"
    },
    ...
]

to

[
    {
        "id": 1,
        "title": "json-server1",
        "author": "typicode",
        "newField": 1,
        "nestArray": [
            {
                "name": "Maurine"
            },
            {
                "name": "Mervin"
            },
            {
                "name": "Edison"
            }
        ]
    },
    ...
]

Connect to multiple proxy servers


const server = new ProxyServer({
   upstreamUrl:"http://localhost:3000",
   port:8080,
   upstreams:{
      // add new upstream servers
      "server2":{
         upstreamUrl:"http://localhost:3001" // you can run json-server db2.json --port 3001 to start a new server for this sample
      }
   }
})

server.proxy("posts")
        .renameTo("new-posts")

//
server.proxy("comments").from("server2") // specify the name of upstream server
        .renameTo("server2-comments") // you can try http://localhost:8080/server2-comments

TODO: related projects and differences