view-api 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # view-api
2
+
3
+ A lightweight CLI tool to run mock APIs locally from a JSON configuration file.
4
+
5
+ Perfect for frontend development, testing, and prototyping without a real backend.
6
+
7
+ ## ✨ Features
8
+
9
+ - Run mock APIs from a single JSON file
10
+ - Customizable port
11
+ - Randomized success / error responses
12
+ - Zero setup for frontend teams
13
+ - Works fully offline
14
+
15
+ ## πŸ“¦ Installation
16
+
17
+ You don’t need to install it globally.
18
+
19
+ Run directly with `npx`:
20
+
21
+ ```bash
22
+ npx watch-api start ./mock.json --port 4000
23
+ ```
24
+
25
+ ## πŸ“– Mock Config Format
26
+
27
+ You gotta use this json structure in able to use the api
28
+
29
+ ```json
30
+ {
31
+ "version": "1.0",
32
+ "routes": {
33
+ "GET /products": {
34
+ "behavior": {
35
+ "successRate": 70
36
+ },
37
+ "responses": {
38
+ "success": {
39
+ "statusCode": 200,
40
+ "body": {
41
+ "status": "success",
42
+ "data": [{ "id": 1, "name": "Product A" }]
43
+ }
44
+ },
45
+ "errors": [
46
+ {
47
+ "statusCode": 500,
48
+ "body": {
49
+ "status": "failed",
50
+ "message": "Server error"
51
+ }
52
+ }
53
+ ]
54
+ }
55
+ }
56
+ }
57
+ }
58
+ ```
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from "path";
4
+ import { program } from "commander";
5
+ import startServer from "../src/server.js";
6
+
7
+ program
8
+ .name("mock-runner")
9
+ .description("Run mock APIs from a JSON config")
10
+ .version("1.0.0");
11
+
12
+ program
13
+ .command("start <config>")
14
+ .option("-p, --port <port>", "port to run server", "3000")
15
+ .action((config, options) => {
16
+ const configPath = path.resolve(process.cwd(), config);
17
+ startServer({ configPath, port: Number(options.port) || 8734 });
18
+ });
19
+
20
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "view-api",
3
+ "version": "1.0.1",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "server": "nodemon src/server.js",
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "bin": {
11
+ "mock-runner": "./bin/mock-runner.js"
12
+ },
13
+ "keywords": [],
14
+ "author": "",
15
+ "license": "ISC",
16
+ "type": "module",
17
+ "dependencies": {
18
+ "commander": "^14.0.2",
19
+ "cors": "^2.8.5",
20
+ "dotenv": "^17.2.3",
21
+ "express": "^5.2.1",
22
+ "helmet": "^8.1.0",
23
+ "morgan": "^1.10.1",
24
+ "nodemon": "^3.1.11"
25
+ }
26
+ }
package/src/app.js ADDED
@@ -0,0 +1,29 @@
1
+ import express from "express";
2
+ import morgan from "morgan";
3
+ import helmet from "helmet";
4
+ import cors from "cors";
5
+
6
+ // define routes here
7
+ import mockRoutes from "./routes/mock.routes.js";
8
+
9
+ import "dotenv/config";
10
+
11
+ export default function createApp(configPath) {
12
+ const app = express();
13
+
14
+ // ==== MIDDLEWARES ====
15
+ app.use(express.json());
16
+ app.use(express.urlencoded({ extended: true }));
17
+ app.use(morgan("dev"));
18
+ app.use(cors());
19
+ app.use(helmet());
20
+
21
+ app.use((req, _res, next) => {
22
+ req.mockConfigPath = configPath;
23
+ next();
24
+ });
25
+
26
+ app.use(mockRoutes);
27
+
28
+ return app;
29
+ }
@@ -0,0 +1,21 @@
1
+ import { handle } from "../services/mock.service.js";
2
+
3
+ export const handleRequest = async (req, res, next) => {
4
+ try {
5
+ // call service to handle request
6
+ const data = handle(req.mockConfigPath, req.method, req.path);
7
+ console.log("πŸš€ ~ handleRequest ~ data:", data);
8
+
9
+ if (!data) {
10
+ return res.status(404).json({
11
+ status: "failed",
12
+ message: `No mock defined for ${req.method} ${req.path}`,
13
+ });
14
+ }
15
+
16
+ // return response
17
+ return res.status(data.statusCode).json(data.body);
18
+ } catch (err) {
19
+ next(err);
20
+ }
21
+ };
@@ -0,0 +1,51 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "routes": {
4
+ "GET /products": {
5
+ "behavior": {
6
+ "successRate": 50
7
+ },
8
+ "responses": {
9
+ "success": {
10
+ "statusCode": 200,
11
+ "body": {
12
+ "status": "success",
13
+ "message": "Products fetched wkwk",
14
+ "data": [
15
+ {
16
+ "id": 1,
17
+ "name": "Product A",
18
+ "price": 10000,
19
+ "stock": 50
20
+ },
21
+ {
22
+ "id": 2,
23
+ "name": "Product B",
24
+ "price": 15000,
25
+ "stock": 30
26
+ }
27
+ ]
28
+ }
29
+ },
30
+ "errors": [
31
+ {
32
+ "statusCode": 500,
33
+ "body": {
34
+ "status": "failed",
35
+ "message": "Server error",
36
+ "error_code": "SERVER_ERROR"
37
+ }
38
+ },
39
+ {
40
+ "statusCode": 400,
41
+ "body": {
42
+ "status": "failed",
43
+ "message": "Bad request, invalid parameters",
44
+ "error_code": "INVALID_PARAMETERS"
45
+ }
46
+ }
47
+ ]
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,8 @@
1
+ import express from "express";
2
+ import { handleRequest } from "../controllers/mock.controller.js";
3
+
4
+ const router = express.Router();
5
+
6
+ router.use(handleRequest);
7
+
8
+ export default router;
package/src/server.js ADDED
@@ -0,0 +1,10 @@
1
+ import createApp from "./app.js";
2
+
3
+ export default ({ configPath, port }) => {
4
+ const server = createApp(configPath);
5
+
6
+ server.listen(port, () => {
7
+ console.log(` ➜ [API] Server running on: http://localhost:${port}`);
8
+ console.log(` ➜ [API] Using config file: ${configPath}`);
9
+ });
10
+ };
@@ -0,0 +1,15 @@
1
+ import { loadConfig } from "../utils/loadConfig.js";
2
+ import { pickResponse } from "../utils/responsePicker.js";
3
+
4
+ export const handle = (mockConfigPath, method, path) => {
5
+ const config = loadConfig(mockConfigPath);
6
+ const key = `${method} ${path}`;
7
+
8
+ const route = config.routes[key];
9
+
10
+ if (!route) {
11
+ return null;
12
+ }
13
+
14
+ return pickResponse(route);
15
+ };
@@ -0,0 +1,6 @@
1
+ import fs from "fs";
2
+
3
+ export const loadConfig = (configPath) => {
4
+ const raw = fs.readFileSync(configPath, "utf-8");
5
+ return JSON.parse(raw);
6
+ };
@@ -0,0 +1,19 @@
1
+ export const pickResponse = (routeConfig) => {
2
+ const { behavior, responses } = routeConfig;
3
+ const roll = Math.random() * 100;
4
+
5
+ if (roll <= behavior.successRate) {
6
+ return {
7
+ statusCode: responses.success.statusCode,
8
+ body: responses.success.body,
9
+ };
10
+ }
11
+
12
+ const errors = responses.errors;
13
+ const error = errors[Math.floor(Math.random() * errors.length)];
14
+
15
+ return {
16
+ statusCode: error.statusCode,
17
+ body: error.body,
18
+ };
19
+ };