Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support pathing #153

Merged
merged 12 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 12 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,8 @@ Mockbin is used internally and maintained by [Kong](https://github.com/Kong), wh

## Installation

```shell
git clone https://github.com/Kong/mockbin.git ./mockbin
cd mockbin
cp .env.sample .env
brew install fnm
fnm use
npm install
```

Note: nvm, n or volta can be used instead of fnm.

### Requirements

other than the dependencies listed in [package.json](package.json) The following are required:

- [Redis](http://redis.io/)

```shell
Expand All @@ -49,6 +36,18 @@ brew services start redis
```

Redis should be now running on localhost:6379
Mockbin will start without redis but you wont be able to set or get response bins.

```shell
git clone https://github.com/Kong/mockbin.git ./mockbin
cd mockbin
cp .env.sample .env
brew install fnm
fnm use
npm install
```

Note: nvm, n or volta can be used instead of fnm.

### Running with Node

Expand Down
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"rules": {
"recommended": true,
"complexity": {
"noForEach": "off"
"noForEach": "off",
"useArrowFunction": "off"
}
}
}
Expand Down
35 changes: 18 additions & 17 deletions docs/api/bins.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,16 +93,16 @@ Responds with a `Location` header with the newly created **Bin**, e.g. `Location

#### Update Bin

> ##### `PUT /bin/:id`
> ##### `PUT /bin/:id/a/b/c`

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.
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.

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)*
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)*

###### Request

> ```http
> PUT /bin/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
> PUT /bin/3c149e20-bc9c-4c68-8614-048e6023a108/a/b/c HTTP/1.1
> Host: mockbin.org
> Content-Type: application/json
> Accept: application/json
Expand Down Expand Up @@ -162,7 +162,7 @@ Responds with a `Location` header with the updated **Bin**, e.g. `Location: /bin

> ```http
> HTTP/1.1 200 OK
> Location: /bin/3c149e20-bc9c-4c68-8614-048e6023a108
> Location: /bin/3c149e20-bc9c-4c68-8614-048e6023a108/a/b/c
> Content-Type: application/json; charset=utf-8
> Content-Length: 38
>
Expand All @@ -173,14 +173,14 @@ Responds with a `Location` header with the updated **Bin**, e.g. `Location: /bin

#### Inspect Bin

> ##### `GET /bin/:id/view`
> ##### `GET /bin/view/:id`

Respondes with the [HAR Response Object](http://www.softwareishard.com/blog/har-12-spec/#response) sent at time of [creation](#create-bin).

###### Request

> ```http
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/view HTTP/1.1
> GET /bin/view/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
> Host: mockbin.org
> Accept: application/json
> ```
Expand Down Expand Up @@ -252,16 +252,17 @@ The [HAR Response Object](http://www.softwareishard.com/blog/har-12-spec/#respon
Each call to this endpoint will be [logged](#bin-log) *(max of 100 requests)*.

You can request this endpoint with *any* combination of the following:
- HTTP methods *(e.g. `POST`, `XXPUT`)*
- HTTP headers *(e.g. `X-My-Header-Name: Value`)*
- body content *(max of 100mb)*
- query string *(e.g. `?foo=bar`)*
- path arguments *(e.g. `/bin/3c149e20-bc9c-4c68-8614-048e6023a108/any/extra/path/`)*

- HTTP methods *(e.g. `POST`, `XXPUT`)*
- HTTP headers *(e.g. `X-My-Header-Name: Value`)*
- body content *(max of 100mb)*
- query string *(e.g. `?foo=bar`)*
- path arguments *(e.g. `/bin/3c149e20-bc9c-4c68-8614-048e6023a108/any/extra/path/`)*

###### Request

> ```http
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/view HTTP/1.1
> GET /bin/view/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
> Host: mockbin.org
> Accept: application/json
> ```
Expand All @@ -284,14 +285,14 @@ You can request this endpoint with *any* combination of the following:

#### Bin Access Log

> ##### `GET /bin/:id/log`
> ##### `GET /bin/log/:id`

List all requests made to this Bin, using [HAR](http://www.softwareishard.com/blog/har-12-spec/) log format.

###### Request

> ```http
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/log HTTP/1.1
> GET /bin/log/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
> Host: mockbin.org
> Accept: application/json
> ```
Expand All @@ -316,14 +317,14 @@ List all requests made to this Bin, using [HAR](http://www.softwareishard.com/bl

#### Delete Bin

> ##### `DELETE /bin/:id/delete`
> ##### `DELETE /bin/delete/:id`

Deletes the bin and all of its logs

###### Request

> ```http
> GET /bin/3c149e20-bc9c-4c68-8614-048e6023a108/view HTTP/1.1
> GET /bin/view/3c149e20-bc9c-4c68-8614-048e6023a108 HTTP/1.1
> ```

###### Response
Expand Down
12 changes: 6 additions & 6 deletions lib/routes/bins.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ module.exports = function bins(dsnStr) {
}

this.client.on("error", (err) => {
debug("redis error:", err);
console.log("redis error:", err);
});

const router = express.Router();
Expand All @@ -42,15 +42,15 @@ module.exports = function bins(dsnStr) {
const endpoints = [
{ action: "get", path: "/create", route: routes.form.bind(this) },
{ action: "post", path: "/create", route: routes.create.bind(this) },
{ action: "get", path: "/:uuid/view", route: routes.view.bind(this) },
{ action: "get", path: "/:uuid/sample", route: routes.sample.bind(this) },
{ action: "get", path: "/:uuid/log", route: routes.log.bind(this) },
{ action: "get", path: "/view/:uuid*", route: routes.view.bind(this) },
{ action: "get", path: "/sample/:uuid*", route: routes.sample.bind(this) },
{ action: "get", path: "/log/:uuid*", route: routes.log.bind(this) },
{
action: "delete",
path: "/:uuid/delete",
path: "/delete/:uuid*",
route: routes.delete.bind(this),
},
{ action: "put", path: "/:uuid", route: routes.update.bind(this) },
{ action: "put", path: "/:uuid*", route: routes.update.bind(this) },
{ action: "all", path: "/:uuid*", route: routes.run.bind(this) },
];

Expand Down
2 changes: 1 addition & 1 deletion lib/routes/bins/create.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ module.exports = async function (req, res, next) {

.catch((err) => {
res.body = {
errors: err.errors,
errors: err.message,
};
})

Expand Down
4 changes: 2 additions & 2 deletions lib/routes/bins/log.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ const pkg = require("../../../package.json");

module.exports = function (req, res, next) {
res.view = "bin/log";

this.client.lrange(`log:${req.params.uuid}`, 0, -1, (err, history) => {
const compoundId = req.params.uuid + req.params[0];
this.client.lrange(`log:${compoundId}`, 0, -1, (err, history) => {
if (err) {
debug(err);

Expand Down
8 changes: 5 additions & 3 deletions lib/routes/bins/run.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
const debug = require("debug")("mockbin");

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

// log interaction & send the appropriate response based on HAR
this.client.rpush(
`log:${req.params.uuid}`,
`log:${compoundId}`,
JSON.stringify(req.har.log.entries[0]),
);
this.client.ltrim(`log:${req.params.uuid}`, 0, 100);
this.client.ltrim(`log:${compoundId}`, 0, 100);

// headers
har.headers.map((header) => {
Expand Down
34 changes: 14 additions & 20 deletions lib/routes/bins/update.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,13 @@
const debug = require("debug")("mockbin");
const util = require("util");
const validate = require("har-validator");
const path = require("path");

module.exports = function (req, res, next) {
const id = req.params.uuid;
let mock = req.jsonBody;

// check for full HAR
if (req.jsonBody?.response) {
mock = req.jsonBody.response;
}
const path = req.params[0];
const compoundId = id + path;

// exception for the web Form
// TODO eliminate this and rely on req.simple.postData.text
if (req.simple.postData.params?.response) {
try {
mock = JSON.parse(req.simple.postData.params.response);
} catch (e) {
debug(e);
}
}
let mock = req.jsonBody;

// overritten by application/x-www-form-urlencoded or multipart/form-data
if (req.simple.postData.text) {
Expand All @@ -29,6 +17,13 @@ module.exports = function (req, res, next) {
debug(e);
}
}
if (!mock) {
res.body = {
errors: "Response HAR is required",
};
next();
return;
}

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

res.view = "redirect";
res.status(200).location(util.format("/bin/%s", id)).body = id;
res.status(200).location(`/bin/${compoundId}`).body = id;
}.bind(this),
)

.catch((err) => {
res.body = {
errors: err.errors,
errors: err.message,
};
})

Expand Down
4 changes: 2 additions & 2 deletions src/views/bin/log.pug
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ mixin method (method)
block content
div(data-page="bin/log").container
div.btn-group.pull-right.hidden-xs
a(href= '/bin/' + req.params.uuid + '/view').btn.btn-primary View Details
a(href= '/bin/view/' + req.params.uuid).btn.btn-primary View Details

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

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

hr

Expand Down
2 changes: 1 addition & 1 deletion src/views/bin/view.pug
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ block content

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

br

Expand Down
4 changes: 2 additions & 2 deletions src/views/redirect.pug
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
doctype html
html
head
meta(http-equiv='refresh', content=`0; url=${res.getHeaders().location}/view`)
meta(http-equiv='refresh', content=`0; url=${res.getHeaders().location.replace('/bin','/bin/view')}`)

body
p Redirecting to #[a(href=res.getHeaders().location)= res.getHeaders().location + '/view']
p Redirecting to #[a(href=res.getHeaders().location)= res.getHeaders().location.replace('/bin','/bin/view')]
Loading