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

@36node/mock-server

v0.1.20

Published

A mock server based on json-server

Downloads

725

Readme

@36node/mock-server

version downloads

mock-server 基于 json-server, 为了更好的提供数据 mock 服务.

Install

$ yarn install @36node/mock-server

Use

1. 在 Nodejs 中使用

#!/usr/bin/env node

const mockServer = require("@36node/mock-server");

const app = mockServer({
  db: {
    pets: [
      { id: 1, name: "kitty", tag: "CAT", grade: 3 },
      { id: 2, name: "pi", tag: "DOG", grade: 4 },
    ],
  },
  rewrites: {
    "/store/pets*": "/pets$1",
  },
  routers: [], // custom middle ware
  aggregations: {
    "/pets": {
      grade: records => _.sumBy(records, "grade") / records.length,
      count: records => records.length,
    },
  },
});

app.listen(3000, () => {
  console.log("JSON Server is running on port 3000");
});

2. 在 webpack develop server 中使用

使用 react-app-rewired 时, 通过 config-overwrites.js 文件 配置 devServer

const stopMock = process.env.MOCK === "false" || process.env.MOCK === "FALSE";
const defaultServerOpts = { delay: 500 };
const {
  serverOpts = defaultServerOpts,
  db: {
    pets: [
      { id: 1, name: "kitty", tag: "CAT", grade: 3 },
      { id: 2, name: "pi", tag: "DOG", grade: 4 },
    ],
  },
  rewrites: {
    "/store/pets*": "/pets$1",
  },
  routers: [], // custom middle ware
  aggregations: {
    "/pets": {
      grade: records => _.sumBy(records, "grade") / records.length,
      count: records => records.length,
    },
  },
} = someMockConfig;

const mockServer = require("@36node/mock-server");

module.exports = {
  ...otherConfig,

  devServer: function(configFunction) {
    return function(proxy, allowedHost) {
      const config = configFunction(proxy, allowedHost);

      if (stopMock) {
        return config;
      }

      /**
       * mock server hoc
       * @param {Express.Application} app
       */
      function configMock(app) {
        // 根据 请求的 header.accept 的类型决定是正常渲染,还是进入mock-server
        const shouldMockReq = req => {
          return (
            req.method !== "GET" ||
            (req.headers.accept &&
              req.headers.accept.indexOf("application/json") !== -1)
          );
        };

        if (serverOpts.delay) {
          app.use((req, res, next) => {
            if (shouldMockReq(req)) {
              return pause(serverOpts.delay)(req, res, next);
            }
            return next();
          });
        }

        mockServer({ app, db, rewrites, routers, shouldMockReq });

        return app;
      }

      const prev = config.before;

      config.before = compose(
        configMock,
        app => {
          prev(app);
          return app;
        }
      );

      return config;
    };
  },
};

Api

mockServer(opts)

params:

  1. opts: Object

    db: // 同 json-server 的 db 配置 https://github.com/typicode/json-server#getting-started

    rewrites (Optional): 同 json-server https://github.com/typicode/json-server#rewriter-example

    routes (Optional): [Express.Middleware] 同 json-server custom-middle https://github.com/typicode/json-server#add-middlewares

    aggregations (Optional): Object 见下文 Aggregation

    app (Optional): Express.Application, 如果没有则自动新建

    shouldMock (Optional): (req, res) => Boolean, 判断 request 是否使用 mock-server 的 中间件

返回:Express.Appliction

Array

使用标准 url query 格式传递数组数据

a=1&a=2

Filter

Use . to access deep properties

GET /posts?title=json-server&author=typicode
GET /posts?id=1&id=2
GET /comments?author.name=typicode

Paginate

Use _offset and optionally _limit to paginate returned data. (an X-Total-Count header is included in the response)

In the Link header you'll get first, prev, next and last links.

GET /posts?_offset=10
GET /posts?_offset=7&_limit=20

note: 10 items are returned by default

Sort

Add _sort and _order (ascending order by default)

# asc
GET /posts?_sort=views

# desc
GET /posts/1/comments?_sort=-votes

note: list posts by views ascending order and comments by votes descending order

For multiple fields, use the following format:

GET /posts/1/comments?_sort=-votes&_sort=likes

_prefixing a path with - will flag that sort is descending order. When a path does not have the - prefix, it is ascending order.

Operators

Add _gt, _lt, _gte or _lte for getting a range

GET /posts?views_gte=10&views_lte=20

Add _ne to exclude a value

GET /posts?id_ne=1

Add _like to filter (RegExp supported)

_like support array

GET /posts?title_like=server

Select

Specifies which document fields to include or exclude

GET /posts?_select=title&_select=body
GET /posts?_select=-comments&_select=-views

or

_select=title,body

prefixing a path with - will flag that path as excluded. When a path does not have the - prefix, it is included A projection must be either inclusive or exclusive. In other words, you must either list the fields to include (which excludes all others), or list the fields to exclude (which implies all other fields are included).

Aggregation

聚合的 query 请求。聚合请求通过 _group 和 _select 参数来控制,通过 opts.aggregations 配置:

比如对于一个 db 配置:

const faker = require("faker");
const _ = require("lodash");
const moment = require("moment");

const now = moment();

const generate = count =>
  _.range(count).map((val, index) => {
    const birthAt = faker.date.between(
      moment()
        .subtract(10, "year")
        .toDate(),
      moment()
        .subtract(1, "year")
        .toDate()
    );

    const age = now.diff(moment(birthAt), "year");

    return {
      id: faker.random.uuid(), // pet id
      name: faker.name.lastName(), // pet name
      tag: faker.random.arrayElement(["CAT", "DOG"]), // pet tag
      owner: faker.name.firstName(), // pet owner
      grade: faker.random.number({ min: 1, max: 5 }), // pet grade
      age, // pet age
      birthAt: birthAt.toISOString(), // pet birth time
    };
  });

const db = {
  pets: generate(100),
};

其中包括了 100 个 pets 的 mock 数据,可使用的路由有:

GET    /pets
GET    /pets/{petId}
POST   /pets
PUT    /pets/{petId}
PATCH  /pets/{petId}
DELETE /pets/{petId}

聚合只在 GET /pets 中有效

简单分组

如果需要统计 pets 中猫和狗的数量, 可以对 tag 分组

配置 aggregations 参数

  aggregations: {
    "/pets": {
      // records 是分组后的数据集合
      count: records => records.length,
      // 默认支持 两种聚合简写 求和 'sum' 和 平均 ‘avg'
      grade: 'avg',
    },
  },

请求:

GET /pets?_group=tag

结果:

[
  {
    "id": "tag=CAT",
    "tag": "CAT",
    "grade": 3.017857142857143,
    "count": 56
  },
  {
    "id": "tag=DOG",
    "tag": "DOG",
    "grade": 3.3863636363636362,
    "count": 44
  }
]

按时间粒度分组

如果需要统计每个月分别生了多少猫和狗, 可以按 tag 和 birthAt.month 分组

对于时间的分组条件,可以采用不同粒度进行分组,query 的格式为 birthAt.month 表示在 birthAt 字段上 按照 月粒度进行分组。

支持的粒度包括:

[
  "year", // 年
  "quarter", // 季度
  "month", // 月
  "week", // 星期
  "isoWeek", // iso 星期
  "day", // 天
  "hour", // 小时
  "min", // 分钟
  "second", // 秒
];

请求:

GET /pets?_group=tag&_group=birthAt.month

结果:

[
  ...,
  {
    "id": "tag=CAT&birthAt=2012-12-31T16%3A00%3A00.000Z",
    "tag": "CAT",
    "birthAt": "2012-12-31T16:00:00.000Z",
    "count": 6
  },
  {
    "id": "tag=DOG&birthAt=2014-12-31T16%3A00%3A00.000Z",
    "tag": "DOG",
    "birthAt": "2014-12-31T16:00:00.000Z",
    "count": 7
  }
]

Tips:

  1. 在返回结果中,birthAt 当前月的起始时间(UTC),如果使用其他粒度,则类似。
  2. 如果同时传入统一字段的多个时间粒度,比如 _group=birthAt.year&_group=birthAt.month, 则较小的时间粒度(month)会生效.