Skip to content

Commit 14b87d2

Browse files
authored
Support pathing (#153)
* can use id to match paths * full path in header * validation * make redis errors clearer * rotate log url structure * support empty path * rotate paths * fix * remove unused parsers * validate * remove 400s * remove validation
1 parent 4ff28c6 commit 14b87d2

File tree

11 files changed

+65
-68
lines changed

11 files changed

+65
-68
lines changed

README.md

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,8 @@ Mockbin is used internally and maintained by [Kong](https://github.com/Kong), wh
2626

2727
## Installation
2828

29-
```shell
30-
git clone https://github.com/Kong/mockbin.git ./mockbin
31-
cd mockbin
32-
cp .env.sample .env
33-
brew install fnm
34-
fnm use
35-
npm install
36-
```
37-
38-
Note: nvm, n or volta can be used instead of fnm.
39-
4029
### Requirements
4130

42-
other than the dependencies listed in [package.json](package.json) The following are required:
43-
4431
- [Redis](http://redis.io/)
4532

4633
```shell
@@ -49,6 +36,18 @@ brew services start redis
4936
```
5037

5138
Redis should be now running on localhost:6379
39+
Mockbin will start without redis but you wont be able to set or get response bins.
40+
41+
```shell
42+
git clone https://github.com/Kong/mockbin.git ./mockbin
43+
cd mockbin
44+
cp .env.sample .env
45+
brew install fnm
46+
fnm use
47+
npm install
48+
```
49+
50+
Note: nvm, n or volta can be used instead of fnm.
5251

5352
### Running with Node
5453

biome.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"rules": {
99
"recommended": true,
1010
"complexity": {
11-
"noForEach": "off"
11+
"noForEach": "off",
12+
"useArrowFunction": "off"
1213
}
1314
}
1415
}

docs/api/bins.md

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,16 @@ Responds with a `Location` header with the newly created **Bin**, e.g. `Location
9393
9494
#### Update Bin
9595
96-
> ##### `PUT /bin/:id`
96+
> ##### `PUT /bin/:id/a/b/c`
9797
98-
Updates a new **Bin** with a mock HTTP response as described by a [HAR Response Object](http://www.softwareishard.com/blog/har-12-spec/#response) body.
98+
Creates or updates a **Bin** with a mock HTTP response as described by a [HAR Response Object](http://www.softwareishard.com/blog/har-12-spec/#response) body. /a/b/c represeent any following paths than will be combined with the id for response matching.
9999
100-
Responds with a `Location` header with the updated **Bin**, e.g. `Location: /bin/3c149e20-bc9c-4c68-8614-048e6023a108` *(the Bin ID is also repeated in the body)*
100+
Responds with a `Location` header with the updated **Bin**, e.g. `Location: /bin/3c149e20-bc9c-4c68-8614-048e6023a108/a/b/c` *(the Bin ID is also repeated in the body)*
101101
102102
###### Request
103103
104104
> ```http
105-
> PUT /bin/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
105+
> PUT /bin/3c149e20-bc9c-4c68-8614-048e6023a108/a/b/c HTTP/1.1
106106
> Host: mockbin.org
107107
> Content-Type: application/json
108108
> Accept: application/json
@@ -162,7 +162,7 @@ Responds with a `Location` header with the updated **Bin**, e.g. `Location: /bin
162162
163163
> ```http
164164
> HTTP/1.1 200 OK
165-
> Location: /bin/3c149e20-bc9c-4c68-8614-048e6023a108
165+
> Location: /bin/3c149e20-bc9c-4c68-8614-048e6023a108/a/b/c
166166
> Content-Type: application/json; charset=utf-8
167167
> Content-Length: 38
168168
>
@@ -173,14 +173,14 @@ Responds with a `Location` header with the updated **Bin**, e.g. `Location: /bin
173173
174174
#### Inspect Bin
175175
176-
> ##### `GET /bin/:id/view`
176+
> ##### `GET /bin/view/:id`
177177
178178
Respondes with the [HAR Response Object](http://www.softwareishard.com/blog/har-12-spec/#response) sent at time of [creation](#create-bin).
179179
180180
###### Request
181181
182182
> ```http
183-
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/view HTTP/1.1
183+
> GET /bin/view/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
184184
> Host: mockbin.org
185185
> Accept: application/json
186186
> ```
@@ -252,16 +252,17 @@ The [HAR Response Object](http://www.softwareishard.com/blog/har-12-spec/#respon
252252
Each call to this endpoint will be [logged](#bin-log) *(max of 100 requests)*.
253253
254254
You can request this endpoint with *any* combination of the following:
255-
- HTTP methods *(e.g. `POST`, `XXPUT`)*
256-
- HTTP headers *(e.g. `X-My-Header-Name: Value`)*
257-
- body content *(max of 100mb)*
258-
- query string *(e.g. `?foo=bar`)*
259-
- path arguments *(e.g. `/bin/3c149e20-bc9c-4c68-8614-048e6023a108/any/extra/path/`)*
255+
256+
- HTTP methods *(e.g. `POST`, `XXPUT`)*
257+
- HTTP headers *(e.g. `X-My-Header-Name: Value`)*
258+
- body content *(max of 100mb)*
259+
- query string *(e.g. `?foo=bar`)*
260+
- path arguments *(e.g. `/bin/3c149e20-bc9c-4c68-8614-048e6023a108/any/extra/path/`)*
260261
261262
###### Request
262263
263264
> ```http
264-
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/view HTTP/1.1
265+
> GET /bin/view/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
265266
> Host: mockbin.org
266267
> Accept: application/json
267268
> ```
@@ -284,14 +285,14 @@ You can request this endpoint with *any* combination of the following:
284285
285286
#### Bin Access Log
286287
287-
> ##### `GET /bin/:id/log`
288+
> ##### `GET /bin/log/:id`
288289
289290
List all requests made to this Bin, using [HAR](http://www.softwareishard.com/blog/har-12-spec/) log format.
290291
291292
###### Request
292293
293294
> ```http
294-
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/log HTTP/1.1
295+
> GET /bin/log/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
295296
> Host: mockbin.org
296297
> Accept: application/json
297298
> ```
@@ -316,14 +317,14 @@ List all requests made to this Bin, using [HAR](http://www.softwareishard.com/bl
316317
317318
#### Delete Bin
318319
319-
> ##### `DELETE /bin/:id/delete`
320+
> ##### `DELETE /bin/delete/:id`
320321
321322
Deletes the bin and all of its logs
322323
323324
###### Request
324325
325326
> ```http
326-
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/view HTTP/1.1
327+
> GET /bin/view/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
327328
> ```
328329
329330
###### Response

lib/routes/bins.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ module.exports = function bins(dsnStr) {
2525
}
2626

2727
this.client.on("error", (err) => {
28-
debug("redis error:", err);
28+
console.log("redis error:", err);
2929
});
3030

3131
const router = express.Router();
@@ -42,15 +42,15 @@ module.exports = function bins(dsnStr) {
4242
const endpoints = [
4343
{ action: "get", path: "/create", route: routes.form.bind(this) },
4444
{ action: "post", path: "/create", route: routes.create.bind(this) },
45-
{ action: "get", path: "/:uuid/view", route: routes.view.bind(this) },
46-
{ action: "get", path: "/:uuid/sample", route: routes.sample.bind(this) },
47-
{ action: "get", path: "/:uuid/log", route: routes.log.bind(this) },
45+
{ action: "get", path: "/view/:uuid*", route: routes.view.bind(this) },
46+
{ action: "get", path: "/sample/:uuid*", route: routes.sample.bind(this) },
47+
{ action: "get", path: "/log/:uuid*", route: routes.log.bind(this) },
4848
{
4949
action: "delete",
50-
path: "/:uuid/delete",
50+
path: "/delete/:uuid*",
5151
route: routes.delete.bind(this),
5252
},
53-
{ action: "put", path: "/:uuid", route: routes.update.bind(this) },
53+
{ action: "put", path: "/:uuid*", route: routes.update.bind(this) },
5454
{ action: "all", path: "/:uuid*", route: routes.run.bind(this) },
5555
];
5656

lib/routes/bins/create.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ module.exports = async function (req, res, next) {
5656

5757
.catch((err) => {
5858
res.body = {
59-
errors: err.errors,
59+
errors: err.message,
6060
};
6161
})
6262

lib/routes/bins/log.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ const pkg = require("../../../package.json");
33

44
module.exports = function (req, res, next) {
55
res.view = "bin/log";
6-
7-
this.client.lrange(`log:${req.params.uuid}`, 0, -1, (err, history) => {
6+
const compoundId = req.params.uuid + req.params[0];
7+
this.client.lrange(`log:${compoundId}`, 0, -1, (err, history) => {
88
if (err) {
99
debug(err);
1010

lib/routes/bins/run.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
const debug = require("debug")("mockbin");
22

33
module.exports = function (req, res, next) {
4+
// compoundId allows us to provide paths in the id to resolve to a specific bin
5+
const compoundId = req.params.uuid + req.params[0];
46
this.client.get(
5-
`bin:${req.params.uuid}`,
7+
`bin:${compoundId}`,
68
function (err, value) {
79
if (err) {
810
debug(err);
@@ -15,10 +17,10 @@ module.exports = function (req, res, next) {
1517

1618
// log interaction & send the appropriate response based on HAR
1719
this.client.rpush(
18-
`log:${req.params.uuid}`,
20+
`log:${compoundId}`,
1921
JSON.stringify(req.har.log.entries[0]),
2022
);
21-
this.client.ltrim(`log:${req.params.uuid}`, 0, 100);
23+
this.client.ltrim(`log:${compoundId}`, 0, 100);
2224

2325
// headers
2426
har.headers.map((header) => {

lib/routes/bins/update.js

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,13 @@
11
const debug = require("debug")("mockbin");
2-
const util = require("util");
32
const validate = require("har-validator");
3+
const path = require("path");
44

55
module.exports = function (req, res, next) {
66
const id = req.params.uuid;
7-
let mock = req.jsonBody;
8-
9-
// check for full HAR
10-
if (req.jsonBody?.response) {
11-
mock = req.jsonBody.response;
12-
}
7+
const path = req.params[0];
8+
const compoundId = id + path;
139

14-
// exception for the web Form
15-
// TODO eliminate this and rely on req.simple.postData.text
16-
if (req.simple.postData.params?.response) {
17-
try {
18-
mock = JSON.parse(req.simple.postData.params.response);
19-
} catch (e) {
20-
debug(e);
21-
}
22-
}
10+
let mock = req.jsonBody;
2311

2412
// overritten by application/x-www-form-urlencoded or multipart/form-data
2513
if (req.simple.postData.text) {
@@ -29,6 +17,13 @@ module.exports = function (req, res, next) {
2917
debug(e);
3018
}
3119
}
20+
if (!mock) {
21+
res.body = {
22+
errors: "Response HAR is required",
23+
};
24+
next();
25+
return;
26+
}
3227

3328
// provide optional values before validation
3429
mock.redirectURL = "";
@@ -45,16 +40,15 @@ module.exports = function (req, res, next) {
4540
.response(mock)
4641
.then(
4742
function () {
48-
this.client.set(`bin:${id}`, JSON.stringify(mock));
43+
this.client.set(`bin:${compoundId}`, JSON.stringify(mock));
4944

5045
res.view = "redirect";
51-
res.status(200).location(util.format("/bin/%s", id)).body = id;
46+
res.status(200).location(`/bin/${compoundId}`).body = id;
5247
}.bind(this),
5348
)
54-
5549
.catch((err) => {
5650
res.body = {
57-
errors: err.errors,
51+
errors: err.message,
5852
};
5953
})
6054

src/views/bin/log.pug

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ mixin method (method)
99
block content
1010
div(data-page="bin/log").container
1111
div.btn-group.pull-right.hidden-xs
12-
a(href= '/bin/' + req.params.uuid + '/view').btn.btn-primary View Details
12+
a(href= '/bin/view/' + req.params.uuid).btn.btn-primary View Details
1313

1414
h3 Bin History: #[code= req.params.uuid]
1515

1616
div.visible-xs
17-
a(href= '/bin/' + req.params.uuid + '/view').btn.btn-block.btn-primary View Details
17+
a(href= '/bin/view' + req.params.uuid).btn.btn-block.btn-primary View Details
1818

1919
hr
2020

src/views/bin/view.pug

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ block content
1414

1515
a(href= '#apiembed').btn.btn-block.btn-primary #[span.badge 1]   Send Some Requests
1616
a(href= '/bin/' + req.params.uuid).btn.btn-block.btn-primary #[span.badge 2]   Visit in Browser
17-
a(href= '/bin/' + req.params.uuid + '/log').btn.btn-block.btn-primary #[span.badge 3]   View History
17+
a(href= '/bin/log/' + req.params.uuid).btn.btn-block.btn-primary #[span.badge 3]   View History
1818

1919
br
2020

0 commit comments

Comments
 (0)