@jaredwray/mockhttp 0.2.3 → 0.4.0
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 +13 -5
- package/dist/index.d.ts +68 -2
- package/dist/index.js +608 -295
- package/package.json +13 -12
package/README.md
CHANGED
|
@@ -7,9 +7,17 @@
|
|
|
7
7
|
[](https://npmjs.com/package/@jaredwray/mockhttp)
|
|
8
8
|
[](https://hub.docker.com/r/jaredwray/mockhttp)
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
A simple HTTP server that can be used to mock HTTP responses for testing purposes. Inspired by [httpbin](https://httpbin.org/) and built using `nodejs` and `fastify` with the idea of running it via https://mockhttp.org, via docker `jaredwray/mockhttp`, or nodejs `npm install jaredwray/mockhttp`.
|
|
12
11
|
|
|
12
|
+
# Features
|
|
13
|
+
* All the features of [httpbin](https://httpbin.org/)
|
|
14
|
+
* `@fastify/helmet` built in by default
|
|
15
|
+
* Built with `nodejs`, `typescript`, and `fastify`
|
|
16
|
+
* Deploy via `docker` or `nodejs`
|
|
17
|
+
* Global deployment via [mockhttp.org](https://mockhttp.org) (free service)
|
|
18
|
+
* Better API documentation and examples
|
|
19
|
+
* Maintained and updated regularly!
|
|
20
|
+
|
|
13
21
|
# Deploy via Docker
|
|
14
22
|
```bash
|
|
15
23
|
docker run -d -p 3000:3000 jaredwray/mockhttp
|
|
@@ -24,14 +32,14 @@ then run `mockhttp` in your code.
|
|
|
24
32
|
|
|
25
33
|
```javascript
|
|
26
34
|
import { mockhttp } from '@jaredwray/mockhttp';
|
|
27
|
-
mockhttp.start(); // start the server
|
|
28
|
-
const response = await fetch('http://localhost:
|
|
29
|
-
mockhttp.stop(); // stop the server
|
|
35
|
+
await mockhttp.start(); // start the server
|
|
36
|
+
const response = await fetch('http://localhost:3000/get');
|
|
37
|
+
await mockhttp.stop(); // stop the server
|
|
30
38
|
```
|
|
31
39
|
|
|
32
40
|
# About mockhttp.org
|
|
33
41
|
|
|
34
|
-
[mockhttp.org](https://mockhttp.org) is a free service that runs this codebase and allows you to use it for testing purposes. It is a simple way to mock HTTP responses for testing purposes. It is globally available has some limitations on it to prevent abuse but many people will not see it. It is ran via [Cloudflare](https://cloudflare.com) and [Google Cloud Run](https://cloud.google.com/run/) across 7 regions globally.
|
|
42
|
+
[mockhttp.org](https://mockhttp.org) is a free service that runs this codebase and allows you to use it for testing purposes. It is a simple way to mock HTTP responses for testing purposes. It is globally available has some limitations on it to prevent abuse but many people will not see it. It is ran via [Cloudflare](https://cloudflare.com) and [Google Cloud Run](https://cloud.google.com/run/) across 7 regions globally and can do millions of requests per second.
|
|
35
43
|
|
|
36
44
|
# Contributing
|
|
37
45
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,69 @@
|
|
|
1
|
-
|
|
1
|
+
import { Hookified, HookifiedOptions } from 'hookified';
|
|
2
|
+
import { FastifyInstance } from 'fastify';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
type HttpBinOptions = {
|
|
5
|
+
httpMethods?: boolean;
|
|
6
|
+
redirects?: boolean;
|
|
7
|
+
requestInspection?: boolean;
|
|
8
|
+
responseInspection?: boolean;
|
|
9
|
+
statusCodes?: boolean;
|
|
10
|
+
};
|
|
11
|
+
type MockHttpOptions = {
|
|
12
|
+
/**
|
|
13
|
+
* The port to listen on. If not provided, defaults to 3000 and falls back to 3001 if the PORT is in use.
|
|
14
|
+
*/
|
|
15
|
+
port?: number;
|
|
16
|
+
/**
|
|
17
|
+
* The host to listen on. If not provided, defaults to '0.0.0.0'.
|
|
18
|
+
*/
|
|
19
|
+
host?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Whether to use Helmet for security headers. Defaults to true.
|
|
22
|
+
*/
|
|
23
|
+
helmet?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to use Swagger for API documentation. Defaults to true.
|
|
26
|
+
*/
|
|
27
|
+
apiDocs?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Whether to use Swagger UI. Defaults to true.
|
|
30
|
+
*/
|
|
31
|
+
httpBin?: HttpBinOptions;
|
|
32
|
+
/**
|
|
33
|
+
* Hookified options.
|
|
34
|
+
*/
|
|
35
|
+
hookOptions?: HookifiedOptions;
|
|
36
|
+
};
|
|
37
|
+
declare class MockHttp extends Hookified {
|
|
38
|
+
private _port;
|
|
39
|
+
private _host;
|
|
40
|
+
private _helmet;
|
|
41
|
+
private _apiDocs;
|
|
42
|
+
private _httpBin;
|
|
43
|
+
private _server;
|
|
44
|
+
constructor(options?: MockHttpOptions);
|
|
45
|
+
get port(): number;
|
|
46
|
+
set port(port: number);
|
|
47
|
+
get host(): string;
|
|
48
|
+
set host(host: string);
|
|
49
|
+
get helmet(): boolean;
|
|
50
|
+
set helmet(helmet: boolean);
|
|
51
|
+
get apiDocs(): boolean;
|
|
52
|
+
set apiDocs(apiDocs: boolean);
|
|
53
|
+
get httpBin(): HttpBinOptions;
|
|
54
|
+
set httpBin(httpBinary: HttpBinOptions);
|
|
55
|
+
get server(): FastifyInstance;
|
|
56
|
+
set server(server: FastifyInstance);
|
|
57
|
+
start(): Promise<void>;
|
|
58
|
+
close(): Promise<void>;
|
|
59
|
+
registerApiDocs(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
60
|
+
registerHttpMethods(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
61
|
+
registerStatusCodeRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
62
|
+
registerRequestInspectionRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
63
|
+
registerResponseInspectionRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
64
|
+
registerRedirectRoutes(fastifyInstance?: FastifyInstance): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
declare const start: () => Promise<MockHttp>;
|
|
68
|
+
|
|
69
|
+
export { MockHttp as default, MockHttp as mockhttp, start };
|
package/dist/index.js
CHANGED
|
@@ -3,128 +3,14 @@ var __name = (target, value) => __defProp(target, "name", { value, configurable:
|
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
5
|
import process from "node:process";
|
|
6
|
+
|
|
7
|
+
// src/mock-http.ts
|
|
6
8
|
import path from "node:path";
|
|
7
|
-
import Fastify from "fastify";
|
|
8
9
|
import fastifyStatic from "@fastify/static";
|
|
9
|
-
import { fastifySwagger } from "@fastify/swagger";
|
|
10
10
|
import fastifyHelmet from "@fastify/helmet";
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
fastify2.get("/", {
|
|
15
|
-
schema: {
|
|
16
|
-
hide: true
|
|
17
|
-
}
|
|
18
|
-
}, async (_request, reply) => {
|
|
19
|
-
const redocHtml = `
|
|
20
|
-
<!doctype html>
|
|
21
|
-
<html>
|
|
22
|
-
<head>
|
|
23
|
-
<title>{ mockhttp }</title>
|
|
24
|
-
<meta charset="utf-8" />
|
|
25
|
-
<meta
|
|
26
|
-
name="viewport"
|
|
27
|
-
content="width=device-width, initial-scale=1" />
|
|
28
|
-
<style>
|
|
29
|
-
:root {
|
|
30
|
-
--scalar-custom-header-height: 70px;
|
|
31
|
-
}
|
|
32
|
-
.custom-header {
|
|
33
|
-
height: var(--scalar-custom-header-height);
|
|
34
|
-
background-color: var(--scalar-background-1);
|
|
35
|
-
box-shadow: inset 0 -1px 0 var(--scalar-border-color);
|
|
36
|
-
color: var(--scalar-color-1);
|
|
37
|
-
font-size: var(--scalar-font-size-2);
|
|
38
|
-
padding: 0 18px;
|
|
39
|
-
position: sticky;
|
|
40
|
-
justify-content: space-between;
|
|
41
|
-
top: 0;
|
|
42
|
-
z-index: 100;
|
|
43
|
-
}
|
|
44
|
-
.custom-header,
|
|
45
|
-
.custom-header nav {
|
|
46
|
-
display: flex;
|
|
47
|
-
align-items: center;
|
|
48
|
-
gap: 18px;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
.custom-header img {
|
|
52
|
-
height: var(--scalar-custom-header-height);
|
|
53
|
-
object-fit: contain;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
.custom-header a:hover {
|
|
57
|
-
color: var(--scalar-color-2);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
.github-corner {
|
|
61
|
-
fill: var(--scalar-border-color) !important;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
</style>
|
|
65
|
-
</head>
|
|
66
|
-
<body>
|
|
67
|
-
<header class="custom-header scalar-app">
|
|
68
|
-
<a href="/"><img src="/logo.svg" alt="{ mockhttp }" /></a>
|
|
69
|
-
<a href="https://github.com/jaredwray/mockhttp" class="github-corner" aria-label="View source on GitHub">
|
|
70
|
-
<svg width="70" height="70" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
|
|
71
|
-
</header>
|
|
72
|
-
|
|
73
|
-
<script
|
|
74
|
-
id="api-reference"
|
|
75
|
-
data-url="/docs/json"></script>
|
|
76
|
-
|
|
77
|
-
<script src="/scalar/browser/standalone.js"></script>
|
|
78
|
-
</body>
|
|
79
|
-
</html>
|
|
80
|
-
`;
|
|
81
|
-
await reply.type("text/html").send(redocHtml);
|
|
82
|
-
});
|
|
83
|
-
}, "indexRoute");
|
|
84
|
-
|
|
85
|
-
// src/routes/sitemap.ts
|
|
86
|
-
var sitemapRoute = /* @__PURE__ */ __name((fastify2) => {
|
|
87
|
-
fastify2.get("/sitemap.xml", {
|
|
88
|
-
schema: {
|
|
89
|
-
hide: true
|
|
90
|
-
}
|
|
91
|
-
}, async (_request, reply) => {
|
|
92
|
-
try {
|
|
93
|
-
const host = _request.headers.host ?? "mockhttp.org";
|
|
94
|
-
const isSecure = _request.headers["x-forwarded-proto"]?.includes("https");
|
|
95
|
-
const protocol = isSecure ? "https" : "http";
|
|
96
|
-
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
97
|
-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
98
|
-
<url>
|
|
99
|
-
<loc>${protocol}://${host}/</loc>
|
|
100
|
-
<changefreq>monthly</changefreq>
|
|
101
|
-
<priority>1.0</priority>
|
|
102
|
-
</url>
|
|
103
|
-
</urlset>`;
|
|
104
|
-
await reply.type("text/xml").send(xml);
|
|
105
|
-
} catch (error) {
|
|
106
|
-
fastify2.log.error(error);
|
|
107
|
-
await reply.status(500).send({
|
|
108
|
-
error: "Internal Server Error"
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}, "sitemapRoute");
|
|
113
|
-
|
|
114
|
-
// src/fastify-config.ts
|
|
115
|
-
var fastifyConfig = {
|
|
116
|
-
logger: {
|
|
117
|
-
transport: {
|
|
118
|
-
target: "pino-pretty",
|
|
119
|
-
options: {
|
|
120
|
-
colorize: true,
|
|
121
|
-
translateTime: true,
|
|
122
|
-
ignore: "pid,hostname",
|
|
123
|
-
singleLine: true
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
};
|
|
11
|
+
import { fastifySwagger } from "@fastify/swagger";
|
|
12
|
+
import { Hookified } from "hookified";
|
|
13
|
+
import Fastify from "fastify";
|
|
128
14
|
|
|
129
15
|
// src/swagger.ts
|
|
130
16
|
import { fastifySwaggerUi } from "@fastify/swagger-ui";
|
|
@@ -132,7 +18,7 @@ import { fastifySwaggerUi } from "@fastify/swagger-ui";
|
|
|
132
18
|
// package.json
|
|
133
19
|
var package_default = {
|
|
134
20
|
name: "@jaredwray/mockhttp",
|
|
135
|
-
version: "0.
|
|
21
|
+
version: "0.4.0",
|
|
136
22
|
description: "Mock Http - Easy way to mock http with httpbin replacement",
|
|
137
23
|
type: "module",
|
|
138
24
|
main: "dist/index.js",
|
|
@@ -168,23 +54,24 @@ var package_default = {
|
|
|
168
54
|
},
|
|
169
55
|
homepage: "https://github.com/jaredwray/mockhttp#readme",
|
|
170
56
|
devDependencies: {
|
|
171
|
-
"@swc/core": "^1.10.
|
|
57
|
+
"@swc/core": "^1.10.9",
|
|
172
58
|
"@types/html-escaper": "^3.0.2",
|
|
173
|
-
"@vitest/coverage-v8": "^
|
|
59
|
+
"@vitest/coverage-v8": "^3.0.4",
|
|
174
60
|
rimraf: "^6.0.1",
|
|
175
|
-
tsup: "^8.3.
|
|
61
|
+
tsup: "^8.3.6",
|
|
176
62
|
tsx: "^4.19.2",
|
|
177
|
-
typescript: "^5.7.
|
|
178
|
-
vitest: "^
|
|
63
|
+
typescript: "^5.7.3",
|
|
64
|
+
vitest: "^3.0.4",
|
|
179
65
|
xo: "^0.60.0"
|
|
180
66
|
},
|
|
181
67
|
dependencies: {
|
|
182
|
-
"@fastify/helmet": "^13.0.
|
|
183
|
-
"@fastify/static": "^8.0.
|
|
184
|
-
"@fastify/swagger": "^9.4.
|
|
185
|
-
"@fastify/swagger-ui": "^5.2.
|
|
186
|
-
"@scalar/api-reference": "^1.25.
|
|
187
|
-
fastify: "^5.2.
|
|
68
|
+
"@fastify/helmet": "^13.0.1",
|
|
69
|
+
"@fastify/static": "^8.0.4",
|
|
70
|
+
"@fastify/swagger": "^9.4.2",
|
|
71
|
+
"@fastify/swagger-ui": "^5.2.1",
|
|
72
|
+
"@scalar/api-reference": "^1.25.108",
|
|
73
|
+
fastify: "^5.2.1",
|
|
74
|
+
hookified: "^1.7.0",
|
|
188
75
|
"html-escaper": "^3.0.3",
|
|
189
76
|
pino: "^9.6.0",
|
|
190
77
|
"pino-pretty": "^13.0.0"
|
|
@@ -197,11 +84,22 @@ var package_default = {
|
|
|
197
84
|
};
|
|
198
85
|
|
|
199
86
|
// src/swagger.ts
|
|
87
|
+
var description = `
|
|
88
|
+
A simple HTTP server that can be used to mock HTTP responses for testing purposes. Inspired by [httpbin](https://httpbin.org/) and built using \`nodejs\` and \`fastify\` with the idea of running it via https://mockhttp.org, via docker \`jaredwray/mockhttp\`, or nodejs \`npm install jaredwray/mockhttp\`.
|
|
89
|
+
|
|
90
|
+
* [GitHub Repository](https://github.com/jaredwray/mockhttp)
|
|
91
|
+
* [Docker Image](https://hub.docker.com/r/jaredwray/mockhttp)
|
|
92
|
+
* [NPM Package](https://www.npmjs.com/package/jaredwray/mockhttp)
|
|
93
|
+
|
|
94
|
+
# About mockhttp.org
|
|
95
|
+
|
|
96
|
+
[mockhttp.org](https://mockhttp.org) is a free service that runs this codebase and allows you to use it for testing purposes. It is a simple way to mock HTTP responses for testing purposes. It is globally available has some limitations on it to prevent abuse but many people will not see it. It is ran via [Cloudflare](https://cloudflare.com) and [Google Cloud Run](https://cloud.google.com/run/) across 7 regions globally and can do millions of requests per second.
|
|
97
|
+
`;
|
|
200
98
|
var fastifySwaggerConfig = {
|
|
201
99
|
openapi: {
|
|
202
100
|
info: {
|
|
203
101
|
title: "Mock HTTP API",
|
|
204
|
-
description
|
|
102
|
+
description,
|
|
205
103
|
version: package_default.version
|
|
206
104
|
},
|
|
207
105
|
consumes: [
|
|
@@ -212,8 +110,8 @@ var fastifySwaggerConfig = {
|
|
|
212
110
|
]
|
|
213
111
|
}
|
|
214
112
|
};
|
|
215
|
-
var registerSwaggerUi = /* @__PURE__ */ __name(async (
|
|
216
|
-
await
|
|
113
|
+
var registerSwaggerUi = /* @__PURE__ */ __name(async (fastify) => {
|
|
114
|
+
await fastify.register(fastifySwaggerUi, {
|
|
217
115
|
routePrefix: "/docs",
|
|
218
116
|
uiConfig: {
|
|
219
117
|
docExpansion: "none",
|
|
@@ -235,110 +133,122 @@ var registerSwaggerUi = /* @__PURE__ */ __name(async (fastify2) => {
|
|
|
235
133
|
});
|
|
236
134
|
}, "registerSwaggerUi");
|
|
237
135
|
|
|
238
|
-
// src/
|
|
239
|
-
var
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
ip: {
|
|
250
|
-
type: "string",
|
|
251
|
-
description: "The IP address of the client"
|
|
252
|
-
}
|
|
253
|
-
},
|
|
254
|
-
required: [
|
|
255
|
-
"ip"
|
|
256
|
-
]
|
|
136
|
+
// src/fastify-config.ts
|
|
137
|
+
var fastifyConfig = {
|
|
138
|
+
logger: {
|
|
139
|
+
transport: {
|
|
140
|
+
target: "pino-pretty",
|
|
141
|
+
options: {
|
|
142
|
+
colorize: true,
|
|
143
|
+
translateTime: true,
|
|
144
|
+
ignore: "pid,hostname",
|
|
145
|
+
singleLine: true
|
|
146
|
+
}
|
|
257
147
|
}
|
|
258
148
|
}
|
|
259
149
|
};
|
|
260
|
-
var ipRoute = /* @__PURE__ */ __name((fastify2) => {
|
|
261
|
-
fastify2.get("/ip", {
|
|
262
|
-
schema: ipSchema
|
|
263
|
-
}, async (request) => {
|
|
264
|
-
const cloudflareIp = request.headers["cf-connecting-ip"];
|
|
265
|
-
const forwardedIp = request.headers["x-forwarded-for"];
|
|
266
|
-
const remoteIp = request.ip;
|
|
267
|
-
const ip = cloudflareIp ?? (typeof forwardedIp === "string" ? forwardedIp.split(",")[0].trim() : remoteIp);
|
|
268
|
-
return {
|
|
269
|
-
ip
|
|
270
|
-
};
|
|
271
|
-
});
|
|
272
|
-
}, "ipRoute");
|
|
273
150
|
|
|
274
|
-
// src/routes/
|
|
275
|
-
var
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
],
|
|
280
|
-
response: {
|
|
281
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
282
|
-
200: {
|
|
283
|
-
type: "object",
|
|
284
|
-
properties: {
|
|
285
|
-
headers: {
|
|
286
|
-
type: "object",
|
|
287
|
-
additionalProperties: {
|
|
288
|
-
type: "string"
|
|
289
|
-
},
|
|
290
|
-
description: "All headers of the client request"
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
required: [
|
|
294
|
-
"headers"
|
|
295
|
-
]
|
|
151
|
+
// src/routes/index.ts
|
|
152
|
+
var indexRoute = /* @__PURE__ */ __name((fastify) => {
|
|
153
|
+
fastify.get("/", {
|
|
154
|
+
schema: {
|
|
155
|
+
hide: true
|
|
296
156
|
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
157
|
+
}, async (_request, reply) => {
|
|
158
|
+
const redocHtml = `
|
|
159
|
+
<!doctype html>
|
|
160
|
+
<html>
|
|
161
|
+
<head>
|
|
162
|
+
<title>{ mockhttp }</title>
|
|
163
|
+
<meta charset="utf-8" />
|
|
164
|
+
<meta
|
|
165
|
+
name="viewport"
|
|
166
|
+
content="width=device-width, initial-scale=1" />
|
|
167
|
+
<style>
|
|
168
|
+
:root {
|
|
169
|
+
--scalar-custom-header-height: 70px;
|
|
170
|
+
}
|
|
171
|
+
.custom-header {
|
|
172
|
+
height: var(--scalar-custom-header-height);
|
|
173
|
+
background-color: var(--scalar-background-1);
|
|
174
|
+
box-shadow: inset 0 -1px 0 var(--scalar-border-color);
|
|
175
|
+
color: var(--scalar-color-1);
|
|
176
|
+
font-size: var(--scalar-font-size-2);
|
|
177
|
+
padding: 0 18px;
|
|
178
|
+
position: sticky;
|
|
179
|
+
justify-content: space-between;
|
|
180
|
+
top: 0;
|
|
181
|
+
z-index: 100;
|
|
182
|
+
}
|
|
183
|
+
.custom-header,
|
|
184
|
+
.custom-header nav {
|
|
185
|
+
display: flex;
|
|
186
|
+
align-items: center;
|
|
187
|
+
gap: 18px;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.custom-header img {
|
|
191
|
+
height: var(--scalar-custom-header-height);
|
|
192
|
+
object-fit: contain;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.custom-header a:hover {
|
|
196
|
+
color: var(--scalar-color-2);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.github-corner {
|
|
200
|
+
fill: var(--scalar-border-color) !important;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
</style>
|
|
204
|
+
</head>
|
|
205
|
+
<body>
|
|
206
|
+
<header class="custom-header scalar-app">
|
|
207
|
+
<a href="/"><img src="/logo.svg" alt="{ mockhttp }" /></a>
|
|
208
|
+
<a href="https://github.com/jaredwray/mockhttp" class="github-corner" aria-label="View source on GitHub">
|
|
209
|
+
<svg width="70" height="70" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
|
|
210
|
+
</header>
|
|
211
|
+
|
|
212
|
+
<script
|
|
213
|
+
id="api-reference"
|
|
214
|
+
data-url="/docs/json"></script>
|
|
215
|
+
|
|
216
|
+
<script src="/scalar/browser/standalone.js"></script>
|
|
217
|
+
</body>
|
|
218
|
+
</html>
|
|
219
|
+
`;
|
|
220
|
+
await reply.type("text/html").send(redocHtml);
|
|
307
221
|
});
|
|
308
|
-
}, "
|
|
222
|
+
}, "indexRoute");
|
|
309
223
|
|
|
310
|
-
// src/routes/
|
|
311
|
-
var
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
224
|
+
// src/routes/sitemap.ts
|
|
225
|
+
var sitemapRoute = /* @__PURE__ */ __name((fastify) => {
|
|
226
|
+
fastify.get("/sitemap.xml", {
|
|
227
|
+
schema: {
|
|
228
|
+
hide: true
|
|
229
|
+
}
|
|
230
|
+
}, async (_request, reply) => {
|
|
231
|
+
try {
|
|
232
|
+
const host = _request.headers.host ?? "mockhttp.org";
|
|
233
|
+
const isSecure = _request.headers["x-forwarded-proto"]?.includes("https");
|
|
234
|
+
const protocol = isSecure ? "https" : "http";
|
|
235
|
+
const xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
236
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
237
|
+
<url>
|
|
238
|
+
<loc>${protocol}://${host}/</loc>
|
|
239
|
+
<changefreq>monthly</changefreq>
|
|
240
|
+
<priority>1.0</priority>
|
|
241
|
+
</url>
|
|
242
|
+
</urlset>`;
|
|
243
|
+
await reply.type("text/xml").send(xml);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
fastify.log.error(error);
|
|
246
|
+
await reply.status(500).send({
|
|
247
|
+
error: "Internal Server Error"
|
|
248
|
+
});
|
|
329
249
|
}
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
var userAgentRoute = /* @__PURE__ */ __name((fastify2) => {
|
|
333
|
-
fastify2.get("/user-agent", {
|
|
334
|
-
schema: userAgentSchema
|
|
335
|
-
}, async (request) => {
|
|
336
|
-
const userAgent = request.headers["user-agent"];
|
|
337
|
-
return {
|
|
338
|
-
userAgent
|
|
339
|
-
};
|
|
340
250
|
});
|
|
341
|
-
}, "
|
|
251
|
+
}, "sitemapRoute");
|
|
342
252
|
|
|
343
253
|
// src/routes/http-methods/get.ts
|
|
344
254
|
var getSchema = {
|
|
@@ -387,8 +297,8 @@ var getSchema = {
|
|
|
387
297
|
}
|
|
388
298
|
}
|
|
389
299
|
};
|
|
390
|
-
var getRoute = /* @__PURE__ */ __name((
|
|
391
|
-
|
|
300
|
+
var getRoute = /* @__PURE__ */ __name((fastify) => {
|
|
301
|
+
fastify.get("/get", {
|
|
392
302
|
schema: getSchema
|
|
393
303
|
}, async (request, _reply) => ({
|
|
394
304
|
method: "GET",
|
|
@@ -435,8 +345,8 @@ var postSchema = {
|
|
|
435
345
|
}
|
|
436
346
|
}
|
|
437
347
|
};
|
|
438
|
-
var postRoute = /* @__PURE__ */ __name((
|
|
439
|
-
|
|
348
|
+
var postRoute = /* @__PURE__ */ __name((fastify) => {
|
|
349
|
+
fastify.post("/post", {
|
|
440
350
|
schema: postSchema
|
|
441
351
|
}, async (request) => ({
|
|
442
352
|
method: "POST",
|
|
@@ -483,8 +393,8 @@ var deleteSchema = {
|
|
|
483
393
|
}
|
|
484
394
|
}
|
|
485
395
|
};
|
|
486
|
-
var deleteRoute = /* @__PURE__ */ __name((
|
|
487
|
-
|
|
396
|
+
var deleteRoute = /* @__PURE__ */ __name((fastify) => {
|
|
397
|
+
fastify.delete("/delete", {
|
|
488
398
|
schema: deleteSchema
|
|
489
399
|
}, async (request) => ({
|
|
490
400
|
method: "DELETE",
|
|
@@ -531,8 +441,8 @@ var putSchema = {
|
|
|
531
441
|
}
|
|
532
442
|
}
|
|
533
443
|
};
|
|
534
|
-
var putRoute = /* @__PURE__ */ __name((
|
|
535
|
-
|
|
444
|
+
var putRoute = /* @__PURE__ */ __name((fastify) => {
|
|
445
|
+
fastify.put("/put", {
|
|
536
446
|
schema: putSchema
|
|
537
447
|
}, async (request) => ({
|
|
538
448
|
method: "PUT",
|
|
@@ -579,8 +489,8 @@ var patchSchema = {
|
|
|
579
489
|
}
|
|
580
490
|
}
|
|
581
491
|
};
|
|
582
|
-
var patchRoute = /* @__PURE__ */ __name((
|
|
583
|
-
|
|
492
|
+
var patchRoute = /* @__PURE__ */ __name((fastify) => {
|
|
493
|
+
fastify.patch("/patch", {
|
|
584
494
|
schema: patchSchema
|
|
585
495
|
}, async (request) => ({
|
|
586
496
|
method: "PATCH",
|
|
@@ -871,7 +781,7 @@ var statusSchema = {
|
|
|
871
781
|
}
|
|
872
782
|
}
|
|
873
783
|
};
|
|
874
|
-
var statusCodeRoute = /* @__PURE__ */ __name((
|
|
784
|
+
var statusCodeRoute = /* @__PURE__ */ __name((fastify) => {
|
|
875
785
|
const handler = /* @__PURE__ */ __name(async (request, reply) => {
|
|
876
786
|
let { code } = request.params;
|
|
877
787
|
if (!code || !statusCodes.map((status) => status.code).includes(Number(code))) {
|
|
@@ -881,23 +791,128 @@ var statusCodeRoute = /* @__PURE__ */ __name((fastify2) => {
|
|
|
881
791
|
status: `Response with status code ${code}`
|
|
882
792
|
});
|
|
883
793
|
}, "handler");
|
|
884
|
-
|
|
794
|
+
fastify.get("/status/:code?", {
|
|
885
795
|
schema: statusSchema
|
|
886
796
|
}, handler);
|
|
887
|
-
|
|
797
|
+
fastify.post("/status/:code?", {
|
|
888
798
|
schema: statusSchema
|
|
889
799
|
}, handler);
|
|
890
|
-
|
|
800
|
+
fastify.put("/status/:code?", {
|
|
891
801
|
schema: statusSchema
|
|
892
802
|
}, handler);
|
|
893
|
-
|
|
803
|
+
fastify.patch("/status/:code?", {
|
|
894
804
|
schema: statusSchema
|
|
895
805
|
}, handler);
|
|
896
|
-
|
|
806
|
+
fastify.delete("/status/:code?", {
|
|
897
807
|
schema: statusSchema
|
|
898
808
|
}, handler);
|
|
899
809
|
}, "statusCodeRoute");
|
|
900
810
|
|
|
811
|
+
// src/routes/request-inspection/ip.ts
|
|
812
|
+
var ipSchema = {
|
|
813
|
+
description: "Returns the IP address of the client",
|
|
814
|
+
tags: [
|
|
815
|
+
"Request Inspection"
|
|
816
|
+
],
|
|
817
|
+
response: {
|
|
818
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
819
|
+
200: {
|
|
820
|
+
type: "object",
|
|
821
|
+
properties: {
|
|
822
|
+
ip: {
|
|
823
|
+
type: "string",
|
|
824
|
+
description: "The IP address of the client"
|
|
825
|
+
}
|
|
826
|
+
},
|
|
827
|
+
required: [
|
|
828
|
+
"ip"
|
|
829
|
+
]
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
var ipRoute = /* @__PURE__ */ __name((fastify) => {
|
|
834
|
+
fastify.get("/ip", {
|
|
835
|
+
schema: ipSchema
|
|
836
|
+
}, async (request) => {
|
|
837
|
+
const cloudflareIp = request.headers["cf-connecting-ip"];
|
|
838
|
+
const forwardedIp = request.headers["x-forwarded-for"];
|
|
839
|
+
const remoteIp = request.ip;
|
|
840
|
+
const ip = cloudflareIp ?? (typeof forwardedIp === "string" ? forwardedIp.split(",")[0].trim() : remoteIp);
|
|
841
|
+
return {
|
|
842
|
+
ip
|
|
843
|
+
};
|
|
844
|
+
});
|
|
845
|
+
}, "ipRoute");
|
|
846
|
+
|
|
847
|
+
// src/routes/request-inspection/headers.ts
|
|
848
|
+
var headersSchema = {
|
|
849
|
+
description: "Returns all headers of the client request",
|
|
850
|
+
tags: [
|
|
851
|
+
"Request Inspection"
|
|
852
|
+
],
|
|
853
|
+
response: {
|
|
854
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
855
|
+
200: {
|
|
856
|
+
type: "object",
|
|
857
|
+
properties: {
|
|
858
|
+
headers: {
|
|
859
|
+
type: "object",
|
|
860
|
+
additionalProperties: {
|
|
861
|
+
type: "string"
|
|
862
|
+
},
|
|
863
|
+
description: "All headers of the client request"
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
required: [
|
|
867
|
+
"headers"
|
|
868
|
+
]
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
var headersRoute = /* @__PURE__ */ __name((fastify) => {
|
|
873
|
+
fastify.get("/headers", {
|
|
874
|
+
schema: headersSchema
|
|
875
|
+
}, async (request) => {
|
|
876
|
+
const headers = request.headers;
|
|
877
|
+
return {
|
|
878
|
+
headers
|
|
879
|
+
};
|
|
880
|
+
});
|
|
881
|
+
}, "headersRoute");
|
|
882
|
+
|
|
883
|
+
// src/routes/request-inspection/user-agent.ts
|
|
884
|
+
var userAgentSchema = {
|
|
885
|
+
description: "Returns the User-Agent header of the client request",
|
|
886
|
+
tags: [
|
|
887
|
+
"Request Inspection"
|
|
888
|
+
],
|
|
889
|
+
response: {
|
|
890
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
891
|
+
200: {
|
|
892
|
+
type: "object",
|
|
893
|
+
properties: {
|
|
894
|
+
userAgent: {
|
|
895
|
+
type: "string",
|
|
896
|
+
description: "The User-Agent header of the client request"
|
|
897
|
+
}
|
|
898
|
+
},
|
|
899
|
+
required: [
|
|
900
|
+
"userAgent"
|
|
901
|
+
]
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
var userAgentRoute = /* @__PURE__ */ __name((fastify) => {
|
|
906
|
+
fastify.get("/user-agent", {
|
|
907
|
+
schema: userAgentSchema
|
|
908
|
+
}, async (request) => {
|
|
909
|
+
const userAgent = request.headers["user-agent"];
|
|
910
|
+
return {
|
|
911
|
+
userAgent
|
|
912
|
+
};
|
|
913
|
+
});
|
|
914
|
+
}, "userAgentRoute");
|
|
915
|
+
|
|
901
916
|
// src/routes/response-inspection/cache.ts
|
|
902
917
|
var cacheGetSchema = {
|
|
903
918
|
description: "Handles cache validation and retrieval.",
|
|
@@ -942,8 +957,8 @@ var cacheSetSchema = {
|
|
|
942
957
|
}
|
|
943
958
|
}
|
|
944
959
|
};
|
|
945
|
-
var cacheRoutes = /* @__PURE__ */ __name((
|
|
946
|
-
|
|
960
|
+
var cacheRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
961
|
+
fastify.get("/cache", {
|
|
947
962
|
schema: cacheGetSchema
|
|
948
963
|
}, async (request, reply) => {
|
|
949
964
|
const ifModifiedSince = request.headers["if-modified-since"];
|
|
@@ -954,7 +969,7 @@ var cacheRoutes = /* @__PURE__ */ __name((fastify2) => {
|
|
|
954
969
|
}
|
|
955
970
|
await reply.send("Cache content or resource response here.");
|
|
956
971
|
});
|
|
957
|
-
|
|
972
|
+
fastify.get("/cache/:value", {
|
|
958
973
|
schema: cacheSetSchema
|
|
959
974
|
}, async (request, reply) => {
|
|
960
975
|
const { value } = request.params;
|
|
@@ -998,8 +1013,8 @@ var etagSchema = {
|
|
|
998
1013
|
}
|
|
999
1014
|
}
|
|
1000
1015
|
};
|
|
1001
|
-
var etagRoutes = /* @__PURE__ */ __name((
|
|
1002
|
-
|
|
1016
|
+
var etagRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
1017
|
+
fastify.get("/etag/:etag", {
|
|
1003
1018
|
schema: etagSchema
|
|
1004
1019
|
}, async (request, reply) => {
|
|
1005
1020
|
const { etag } = request.params;
|
|
@@ -1038,8 +1053,8 @@ var responseHeadersSchema = {
|
|
|
1038
1053
|
}
|
|
1039
1054
|
}
|
|
1040
1055
|
};
|
|
1041
|
-
var responseHeadersRoutes = /* @__PURE__ */ __name((
|
|
1042
|
-
|
|
1056
|
+
var responseHeadersRoutes = /* @__PURE__ */ __name((fastify) => {
|
|
1057
|
+
fastify.get("/response-headers", {
|
|
1043
1058
|
schema: responseHeadersSchema
|
|
1044
1059
|
}, async (request, reply) => {
|
|
1045
1060
|
const queryParameters = request.query;
|
|
@@ -1052,7 +1067,7 @@ var responseHeadersRoutes = /* @__PURE__ */ __name((fastify2) => {
|
|
|
1052
1067
|
]));
|
|
1053
1068
|
await reply.send(cleanedResponse);
|
|
1054
1069
|
});
|
|
1055
|
-
|
|
1070
|
+
fastify.post("/response-headers", {
|
|
1056
1071
|
schema: responseHeadersSchema
|
|
1057
1072
|
}, async (request, reply) => {
|
|
1058
1073
|
const queryParameters = request.query ?? {};
|
|
@@ -1074,53 +1089,351 @@ var responseHeadersRoutes = /* @__PURE__ */ __name((fastify2) => {
|
|
|
1074
1089
|
});
|
|
1075
1090
|
}, "responseHeadersRoutes");
|
|
1076
1091
|
|
|
1077
|
-
// src/
|
|
1078
|
-
var
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1092
|
+
// src/routes/redirects/absolute-redirect.ts
|
|
1093
|
+
var absoluteRedirectSchema = {
|
|
1094
|
+
tags: [
|
|
1095
|
+
"Redirects"
|
|
1096
|
+
],
|
|
1097
|
+
description: "Redirects the request to the target URL using an absolute URL",
|
|
1098
|
+
params: {
|
|
1099
|
+
type: "object",
|
|
1100
|
+
properties: {
|
|
1101
|
+
value: {
|
|
1102
|
+
type: "integer",
|
|
1103
|
+
minimum: 1
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
required: [
|
|
1107
|
+
"value"
|
|
1108
|
+
]
|
|
1109
|
+
},
|
|
1110
|
+
headers: {
|
|
1111
|
+
type: "object",
|
|
1112
|
+
properties: {
|
|
1113
|
+
host: {
|
|
1114
|
+
type: "string"
|
|
1115
|
+
}
|
|
1116
|
+
},
|
|
1117
|
+
required: [
|
|
1118
|
+
"host"
|
|
1119
|
+
]
|
|
1120
|
+
},
|
|
1121
|
+
response: {
|
|
1122
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1123
|
+
302: {
|
|
1124
|
+
type: "string"
|
|
1109
1125
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1126
|
+
}
|
|
1127
|
+
};
|
|
1128
|
+
var absoluteRedirectRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1129
|
+
fastify.get("/absolute-redirect/:value", {
|
|
1130
|
+
schema: absoluteRedirectSchema
|
|
1131
|
+
}, async (request, reply) => {
|
|
1132
|
+
const value = request.params.value;
|
|
1133
|
+
const { host } = request.headers;
|
|
1134
|
+
const protocol = request.protocol;
|
|
1135
|
+
let url = `${protocol}://${host}/get`;
|
|
1136
|
+
let html = `
|
|
1137
|
+
<title>Redirecting...</title>
|
|
1138
|
+
<h1>Redirecting...</h1>
|
|
1139
|
+
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1140
|
+
`;
|
|
1141
|
+
if (value > 1) {
|
|
1142
|
+
url = `${protocol}://${host}/absolute-redirect/${value - 1}`;
|
|
1143
|
+
html = `
|
|
1144
|
+
<title>Redirecting...</title>
|
|
1145
|
+
<h1>Redirecting...</h1>
|
|
1146
|
+
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1147
|
+
`;
|
|
1113
1148
|
}
|
|
1114
|
-
await
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1149
|
+
await reply.header("Location", url).status(302).type("text/html").send(html);
|
|
1150
|
+
});
|
|
1151
|
+
}, "absoluteRedirectRoute");
|
|
1152
|
+
|
|
1153
|
+
// src/routes/redirects/relative-redirect.ts
|
|
1154
|
+
var relativeRedirectSchema = {
|
|
1155
|
+
tags: [
|
|
1156
|
+
"Redirects"
|
|
1157
|
+
],
|
|
1158
|
+
description: "Redirects the request to the target URL using an relative URL",
|
|
1159
|
+
params: {
|
|
1160
|
+
type: "object",
|
|
1161
|
+
properties: {
|
|
1162
|
+
value: {
|
|
1163
|
+
type: "integer",
|
|
1164
|
+
minimum: 1
|
|
1165
|
+
}
|
|
1166
|
+
},
|
|
1167
|
+
required: [
|
|
1168
|
+
"value"
|
|
1169
|
+
]
|
|
1170
|
+
},
|
|
1171
|
+
headers: {
|
|
1172
|
+
type: "object",
|
|
1173
|
+
properties: {
|
|
1174
|
+
host: {
|
|
1175
|
+
type: "string"
|
|
1176
|
+
}
|
|
1177
|
+
},
|
|
1178
|
+
required: [
|
|
1179
|
+
"host"
|
|
1180
|
+
]
|
|
1181
|
+
},
|
|
1182
|
+
response: {
|
|
1183
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1184
|
+
302: {
|
|
1185
|
+
type: "string"
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
var relativeRedirectRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1190
|
+
fastify.get("/relative-redirect/:value", {
|
|
1191
|
+
schema: relativeRedirectSchema
|
|
1192
|
+
}, async (request, reply) => {
|
|
1193
|
+
const value = request.params.value;
|
|
1194
|
+
let url = "/get";
|
|
1195
|
+
let html = `
|
|
1196
|
+
<title>Redirecting...</title>
|
|
1197
|
+
<h1>Redirecting...</h1>
|
|
1198
|
+
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1199
|
+
`;
|
|
1200
|
+
if (value > 1) {
|
|
1201
|
+
url = `/relative-redirect/${value - 1}`;
|
|
1202
|
+
html = `
|
|
1203
|
+
<title>Redirecting...</title>
|
|
1204
|
+
<h1>Redirecting...</h1>
|
|
1205
|
+
<p>You should be redirected automatically to target URL: <a href="${url}">${url}</a>. If not click the link.</p>
|
|
1206
|
+
`;
|
|
1207
|
+
}
|
|
1208
|
+
await reply.header("Location", url).status(302).type("text/html").send(html);
|
|
1209
|
+
});
|
|
1210
|
+
}, "relativeRedirectRoute");
|
|
1211
|
+
|
|
1212
|
+
// src/routes/redirects/redirect-to.ts
|
|
1213
|
+
var redirectToSchema = {
|
|
1214
|
+
tags: [
|
|
1215
|
+
"Redirects"
|
|
1216
|
+
],
|
|
1217
|
+
description: "Redirects the request to the target URL",
|
|
1218
|
+
querystring: {
|
|
1219
|
+
type: "object",
|
|
1220
|
+
properties: {
|
|
1221
|
+
url: {
|
|
1222
|
+
type: "string",
|
|
1223
|
+
format: "uri",
|
|
1224
|
+
description: "The URL to redirect to"
|
|
1225
|
+
},
|
|
1226
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
1227
|
+
status_code: {
|
|
1228
|
+
type: "string",
|
|
1229
|
+
pattern: "^[1-5][0-9][0-9]$",
|
|
1230
|
+
description: "The HTTP status code to use for redirection"
|
|
1231
|
+
}
|
|
1232
|
+
},
|
|
1233
|
+
required: [
|
|
1234
|
+
"url"
|
|
1235
|
+
],
|
|
1236
|
+
additionalProperties: false
|
|
1237
|
+
}
|
|
1238
|
+
};
|
|
1239
|
+
var redirectToRoute = /* @__PURE__ */ __name((fastify) => {
|
|
1240
|
+
const handler = /* @__PURE__ */ __name(async (request, reply) => {
|
|
1241
|
+
const { url, status_code } = request.query;
|
|
1242
|
+
const statusCode = status_code ? Number(status_code) : 302;
|
|
1243
|
+
await reply.redirect(url, statusCode);
|
|
1244
|
+
}, "handler");
|
|
1245
|
+
fastify.get("/redirect-to", {
|
|
1246
|
+
schema: redirectToSchema
|
|
1247
|
+
}, handler);
|
|
1248
|
+
fastify.post("/redirect-to", {
|
|
1249
|
+
schema: redirectToSchema
|
|
1250
|
+
}, handler);
|
|
1251
|
+
fastify.put("/redirect-to", {
|
|
1252
|
+
schema: redirectToSchema
|
|
1253
|
+
}, handler);
|
|
1254
|
+
fastify.patch("/redirect-to", {
|
|
1255
|
+
schema: redirectToSchema
|
|
1256
|
+
}, handler);
|
|
1257
|
+
fastify.delete("/redirect-to", {
|
|
1258
|
+
schema: redirectToSchema
|
|
1259
|
+
}, handler);
|
|
1260
|
+
}, "redirectToRoute");
|
|
1261
|
+
|
|
1262
|
+
// src/mock-http.ts
|
|
1263
|
+
var MockHttp = class extends Hookified {
|
|
1264
|
+
static {
|
|
1265
|
+
__name(this, "MockHttp");
|
|
1266
|
+
}
|
|
1267
|
+
_port = 3e3;
|
|
1268
|
+
_host = "0.0.0.0";
|
|
1269
|
+
_helmet = true;
|
|
1270
|
+
_apiDocs = true;
|
|
1271
|
+
_httpBin = {
|
|
1272
|
+
httpMethods: true,
|
|
1273
|
+
redirects: true,
|
|
1274
|
+
requestInspection: true,
|
|
1275
|
+
responseInspection: true,
|
|
1276
|
+
statusCodes: true
|
|
1277
|
+
};
|
|
1278
|
+
// eslint-disable-next-line new-cap
|
|
1279
|
+
_server = Fastify();
|
|
1280
|
+
constructor(options) {
|
|
1281
|
+
super(options?.hookOptions);
|
|
1282
|
+
if (options?.port) {
|
|
1283
|
+
this._port = options.port;
|
|
1284
|
+
}
|
|
1285
|
+
if (options?.host) {
|
|
1286
|
+
this._host = options.host;
|
|
1287
|
+
}
|
|
1288
|
+
if (options?.helmet !== void 0) {
|
|
1289
|
+
this._helmet = options.helmet;
|
|
1290
|
+
}
|
|
1291
|
+
if (options?.apiDocs !== void 0) {
|
|
1292
|
+
this._apiDocs = options.apiDocs;
|
|
1293
|
+
}
|
|
1294
|
+
if (options?.httpBin !== void 0) {
|
|
1295
|
+
this._httpBin = options.httpBin;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
get port() {
|
|
1299
|
+
return this._port;
|
|
1300
|
+
}
|
|
1301
|
+
set port(port) {
|
|
1302
|
+
this._port = port;
|
|
1303
|
+
}
|
|
1304
|
+
get host() {
|
|
1305
|
+
return this._host;
|
|
1306
|
+
}
|
|
1307
|
+
set host(host) {
|
|
1308
|
+
this._host = host;
|
|
1309
|
+
}
|
|
1310
|
+
get helmet() {
|
|
1311
|
+
return this._helmet;
|
|
1312
|
+
}
|
|
1313
|
+
set helmet(helmet) {
|
|
1314
|
+
this._helmet = helmet;
|
|
1315
|
+
}
|
|
1316
|
+
get apiDocs() {
|
|
1317
|
+
return this._apiDocs;
|
|
1318
|
+
}
|
|
1319
|
+
// eslint-disable-next-line unicorn/prevent-abbreviations
|
|
1320
|
+
set apiDocs(apiDocs) {
|
|
1321
|
+
this._apiDocs = apiDocs;
|
|
1322
|
+
}
|
|
1323
|
+
get httpBin() {
|
|
1324
|
+
return this._httpBin;
|
|
1325
|
+
}
|
|
1326
|
+
set httpBin(httpBinary) {
|
|
1327
|
+
this._httpBin = httpBinary;
|
|
1328
|
+
}
|
|
1329
|
+
get server() {
|
|
1330
|
+
return this._server;
|
|
1331
|
+
}
|
|
1332
|
+
set server(server) {
|
|
1333
|
+
this._server = server;
|
|
1334
|
+
}
|
|
1335
|
+
async start() {
|
|
1336
|
+
try {
|
|
1337
|
+
const { port, host } = this;
|
|
1338
|
+
if (this._server) {
|
|
1339
|
+
await this._server.close();
|
|
1340
|
+
}
|
|
1341
|
+
this._server = Fastify(fastifyConfig);
|
|
1342
|
+
await this._server.register(fastifyStatic, {
|
|
1343
|
+
root: path.resolve("./node_modules/@scalar/api-reference/dist"),
|
|
1344
|
+
prefix: "/scalar"
|
|
1345
|
+
});
|
|
1346
|
+
await this.server.register(fastifyStatic, {
|
|
1347
|
+
root: path.resolve("./public"),
|
|
1348
|
+
decorateReply: false
|
|
1349
|
+
});
|
|
1350
|
+
await this._server.register(sitemapRoute);
|
|
1351
|
+
if (this._helmet) {
|
|
1352
|
+
await this._server.register(fastifyHelmet);
|
|
1353
|
+
}
|
|
1354
|
+
if (this._apiDocs) {
|
|
1355
|
+
await this.registerApiDocs();
|
|
1356
|
+
}
|
|
1357
|
+
const { httpMethods, redirects, requestInspection, responseInspection, statusCodes: statusCodes2 } = this._httpBin;
|
|
1358
|
+
if (httpMethods) {
|
|
1359
|
+
await this.registerHttpMethods();
|
|
1360
|
+
}
|
|
1361
|
+
if (statusCodes2) {
|
|
1362
|
+
await this.registerStatusCodeRoutes();
|
|
1363
|
+
}
|
|
1364
|
+
if (requestInspection) {
|
|
1365
|
+
await this.registerRequestInspectionRoutes();
|
|
1366
|
+
}
|
|
1367
|
+
if (responseInspection) {
|
|
1368
|
+
await this.registerResponseInspectionRoutes();
|
|
1369
|
+
}
|
|
1370
|
+
if (redirects) {
|
|
1371
|
+
await this.registerRedirectRoutes();
|
|
1372
|
+
}
|
|
1373
|
+
await this._server.listen({
|
|
1374
|
+
port,
|
|
1375
|
+
host
|
|
1376
|
+
});
|
|
1377
|
+
} catch (error) {
|
|
1378
|
+
this._server.log.error(error);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
async close() {
|
|
1382
|
+
await this._server.close();
|
|
1383
|
+
}
|
|
1384
|
+
async registerApiDocs(fastifyInstance) {
|
|
1385
|
+
const fastify = fastifyInstance ?? this._server;
|
|
1386
|
+
await fastify.register(fastifySwagger, fastifySwaggerConfig);
|
|
1387
|
+
await registerSwaggerUi(fastify);
|
|
1388
|
+
await fastify.register(indexRoute);
|
|
1389
|
+
}
|
|
1390
|
+
async registerHttpMethods(fastifyInstance) {
|
|
1391
|
+
const fastify = fastifyInstance ?? this._server;
|
|
1392
|
+
await fastify.register(getRoute);
|
|
1393
|
+
await fastify.register(postRoute);
|
|
1394
|
+
await fastify.register(deleteRoute);
|
|
1395
|
+
await fastify.register(putRoute);
|
|
1396
|
+
await fastify.register(patchRoute);
|
|
1397
|
+
}
|
|
1398
|
+
async registerStatusCodeRoutes(fastifyInstance) {
|
|
1399
|
+
const fastify = fastifyInstance ?? this._server;
|
|
1400
|
+
await fastify.register(statusCodeRoute);
|
|
1401
|
+
}
|
|
1402
|
+
async registerRequestInspectionRoutes(fastifyInstance) {
|
|
1403
|
+
const fastify = fastifyInstance ?? this._server;
|
|
1404
|
+
await fastify.register(ipRoute);
|
|
1405
|
+
await fastify.register(headersRoute);
|
|
1406
|
+
await fastify.register(userAgentRoute);
|
|
1407
|
+
}
|
|
1408
|
+
async registerResponseInspectionRoutes(fastifyInstance) {
|
|
1409
|
+
const fastify = fastifyInstance ?? this._server;
|
|
1410
|
+
await fastify.register(cacheRoutes);
|
|
1411
|
+
await fastify.register(etagRoutes);
|
|
1412
|
+
await fastify.register(responseHeadersRoutes);
|
|
1413
|
+
}
|
|
1414
|
+
async registerRedirectRoutes(fastifyInstance) {
|
|
1415
|
+
const fastify = fastifyInstance ?? this._server;
|
|
1416
|
+
await fastify.register(absoluteRedirectRoute);
|
|
1417
|
+
await fastify.register(relativeRedirectRoute);
|
|
1418
|
+
await fastify.register(redirectToRoute);
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
// src/index.ts
|
|
1423
|
+
var start = /* @__PURE__ */ __name(async () => {
|
|
1424
|
+
const mockHttp = new MockHttp();
|
|
1425
|
+
if (process.env.PORT) {
|
|
1426
|
+
mockHttp.port = Number.parseInt(process.env.PORT, 10);
|
|
1427
|
+
}
|
|
1428
|
+
if (process.env.HOST) {
|
|
1429
|
+
mockHttp.host = process.env.HOST;
|
|
1121
1430
|
}
|
|
1431
|
+
await mockHttp.start();
|
|
1432
|
+
return mockHttp;
|
|
1122
1433
|
}, "start");
|
|
1123
1434
|
await start();
|
|
1124
1435
|
export {
|
|
1436
|
+
MockHttp as default,
|
|
1437
|
+
MockHttp as mockhttp,
|
|
1125
1438
|
start
|
|
1126
1439
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jaredwray/mockhttp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Mock Http - Easy way to mock http with httpbin replacement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -36,23 +36,24 @@
|
|
|
36
36
|
},
|
|
37
37
|
"homepage": "https://github.com/jaredwray/mockhttp#readme",
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@swc/core": "^1.10.
|
|
39
|
+
"@swc/core": "^1.10.9",
|
|
40
40
|
"@types/html-escaper": "^3.0.2",
|
|
41
|
-
"@vitest/coverage-v8": "^
|
|
41
|
+
"@vitest/coverage-v8": "^3.0.4",
|
|
42
42
|
"rimraf": "^6.0.1",
|
|
43
|
-
"tsup": "^8.3.
|
|
43
|
+
"tsup": "^8.3.6",
|
|
44
44
|
"tsx": "^4.19.2",
|
|
45
|
-
"typescript": "^5.7.
|
|
46
|
-
"vitest": "^
|
|
45
|
+
"typescript": "^5.7.3",
|
|
46
|
+
"vitest": "^3.0.4",
|
|
47
47
|
"xo": "^0.60.0"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@fastify/helmet": "^13.0.
|
|
51
|
-
"@fastify/static": "^8.0.
|
|
52
|
-
"@fastify/swagger": "^9.4.
|
|
53
|
-
"@fastify/swagger-ui": "^5.2.
|
|
54
|
-
"@scalar/api-reference": "^1.25.
|
|
55
|
-
"fastify": "^5.2.
|
|
50
|
+
"@fastify/helmet": "^13.0.1",
|
|
51
|
+
"@fastify/static": "^8.0.4",
|
|
52
|
+
"@fastify/swagger": "^9.4.2",
|
|
53
|
+
"@fastify/swagger-ui": "^5.2.1",
|
|
54
|
+
"@scalar/api-reference": "^1.25.108",
|
|
55
|
+
"fastify": "^5.2.1",
|
|
56
|
+
"hookified": "^1.7.0",
|
|
56
57
|
"html-escaper": "^3.0.3",
|
|
57
58
|
"pino": "^9.6.0",
|
|
58
59
|
"pino-pretty": "^13.0.0"
|