@0layimika/api-response-kit 0.1.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 +114 -0
- package/dist/adapters/express.d.mts +6 -0
- package/dist/adapters/express.d.ts +6 -0
- package/dist/adapters/express.js +55 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/express.mjs +8 -0
- package/dist/adapters/express.mjs.map +1 -0
- package/dist/adapters/fastify.d.mts +6 -0
- package/dist/adapters/fastify.d.ts +6 -0
- package/dist/adapters/fastify.js +53 -0
- package/dist/adapters/fastify.js.map +1 -0
- package/dist/adapters/fastify.mjs +8 -0
- package/dist/adapters/fastify.mjs.map +1 -0
- package/dist/chunk-5HL56LEG.mjs +20 -0
- package/dist/chunk-5HL56LEG.mjs.map +1 -0
- package/dist/chunk-OD5AKNUG.mjs +18 -0
- package/dist/chunk-OD5AKNUG.mjs.map +1 -0
- package/dist/chunk-VJJRPHMZ.mjs +17 -0
- package/dist/chunk-VJJRPHMZ.mjs.map +1 -0
- package/dist/index.d.mts +26 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +67 -0
- package/dist/index.mjs.map +1 -0
- package/dist/response-DV8HnqXP.d.mts +17 -0
- package/dist/response-DV8HnqXP.d.ts +17 -0
- package/package.json +40 -0
- package/src/adapters/express.ts +14 -0
- package/src/adapters/fastify.ts +14 -0
- package/src/core/error.ts +41 -0
- package/src/core/response.ts +17 -0
- package/src/core/status-map.ts +11 -0
- package/src/core/success.ts +21 -0
- package/src/index.ts +8 -0
- package/src/types/index.ts +0 -0
- package/tsconfig.json +14 -0
- package/tsup.config.ts +12 -0
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# api-response-kit
|
|
2
|
+
|
|
3
|
+
> A small, TypeScript-first toolkit for **consistent API success and error responses**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Why This Exists
|
|
8
|
+
|
|
9
|
+
Most APIs suffer from the same problems:
|
|
10
|
+
|
|
11
|
+
- Inconsistent response shapes across endpoints
|
|
12
|
+
- Ad-hoc error handling (`throw new Error`, random JSON)
|
|
13
|
+
- Frontend has to guess response structures
|
|
14
|
+
- Documentation drifts away from reality
|
|
15
|
+
- Boilerplate `res.status().json()` everywhere
|
|
16
|
+
|
|
17
|
+
**api-response-kit** fixes this by enforcing a **predictable response contract** for **both success and error responses** while keeping your code clean and framework-agnostic.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Core Idea
|
|
22
|
+
|
|
23
|
+
Instead of:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
res.status(200).json(user)
|
|
27
|
+
res.status(400).json({ error: "Invalid input" })
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
You write:
|
|
31
|
+
```ts
|
|
32
|
+
return Ok(user)
|
|
33
|
+
return BadRequest("Invalid input")
|
|
34
|
+
```
|
|
35
|
+
## Response Contract
|
|
36
|
+
### Success Response
|
|
37
|
+
```ts
|
|
38
|
+
type ApiSuccess<T> = {
|
|
39
|
+
success: true
|
|
40
|
+
data: T
|
|
41
|
+
message?: string
|
|
42
|
+
meta?: Record<string, unknown>
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
### Error Response
|
|
46
|
+
```ts
|
|
47
|
+
type ApiError = {
|
|
48
|
+
success: false
|
|
49
|
+
error: {
|
|
50
|
+
code: string
|
|
51
|
+
message: string
|
|
52
|
+
details?: unknown
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
## Installation
|
|
57
|
+
```bash
|
|
58
|
+
npm install api-response-kit
|
|
59
|
+
|
|
60
|
+
yarn add api-response-kit
|
|
61
|
+
|
|
62
|
+
pnpm add api-response-kit
|
|
63
|
+
```
|
|
64
|
+
## Basic Usage
|
|
65
|
+
### Success Helpers
|
|
66
|
+
```ts
|
|
67
|
+
import { Ok, Created, NoContent } from "api-response-kit"
|
|
68
|
+
|
|
69
|
+
return Ok(user)
|
|
70
|
+
return Created(newUser)
|
|
71
|
+
return NoContent()
|
|
72
|
+
```
|
|
73
|
+
### Error Helpers
|
|
74
|
+
```ts
|
|
75
|
+
import { BadRequest, NotFound, Unauthorized } from "api-response-kit"
|
|
76
|
+
|
|
77
|
+
if (!user) return NotFound("User not found")
|
|
78
|
+
if (!email) return BadRequest("Email is required")
|
|
79
|
+
if (!token) return Unauthorized()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Controller Example
|
|
83
|
+
```ts
|
|
84
|
+
export function getUser(id: string) {
|
|
85
|
+
const user = findUser(id)
|
|
86
|
+
|
|
87
|
+
if (!user) {
|
|
88
|
+
return NotFound("User")
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return Ok(user)
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Express Adapter Example
|
|
96
|
+
```ts
|
|
97
|
+
import { sendResponse } from "api-response-kit/express"
|
|
98
|
+
|
|
99
|
+
app.get("/users/:id", (req, res) => {
|
|
100
|
+
const response = getUser(req.params.id)
|
|
101
|
+
sendResponse(res, response)
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
## Custom Errors
|
|
105
|
+
```ts
|
|
106
|
+
import { CustomError } from "api-response-kit"
|
|
107
|
+
|
|
108
|
+
return CustomError({
|
|
109
|
+
code: "PAYMENT_FAILED",
|
|
110
|
+
status: 402,
|
|
111
|
+
message: "Payment authorization failed"
|
|
112
|
+
})
|
|
113
|
+
```
|
|
114
|
+
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/adapters/express.ts
|
|
21
|
+
var express_exports = {};
|
|
22
|
+
__export(express_exports, {
|
|
23
|
+
sendResponse: () => sendResponse
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(express_exports);
|
|
26
|
+
|
|
27
|
+
// src/core/status-map.ts
|
|
28
|
+
var statusMap = {
|
|
29
|
+
Ok: 200,
|
|
30
|
+
Created: 201,
|
|
31
|
+
NoContent: 204,
|
|
32
|
+
BadRequest: 400,
|
|
33
|
+
Unauthorized: 401,
|
|
34
|
+
Forbidden: 403,
|
|
35
|
+
NotFound: 404,
|
|
36
|
+
Conflict: 409,
|
|
37
|
+
InternalError: 500
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/adapters/express.ts
|
|
41
|
+
function sendResponse(res, response) {
|
|
42
|
+
let status = 200;
|
|
43
|
+
if (response.success) {
|
|
44
|
+
status = 200;
|
|
45
|
+
} else {
|
|
46
|
+
const errorCode = response.error.code;
|
|
47
|
+
status = statusMap[errorCode] || 500;
|
|
48
|
+
}
|
|
49
|
+
res.status(status).json(response);
|
|
50
|
+
}
|
|
51
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
52
|
+
0 && (module.exports = {
|
|
53
|
+
sendResponse
|
|
54
|
+
});
|
|
55
|
+
//# sourceMappingURL=express.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/express.ts","../../src/core/status-map.ts"],"sourcesContent":["import {Response as ExResponse} from \"express\"\nimport {ApiResponse} from \"../core/response\";\nimport {statusMap} from \"../core/status-map\";\n\nexport function sendResponse(res: ExResponse, response: ApiResponse<unknown>): void {\n let status = 200\n if (response.success) {\n status = 200\n } else {\n const errorCode = response.error.code\n status = statusMap[errorCode] || 500\n }\n res.status(status).json(response)\n}","export const statusMap: Record<string, number> = {\n Ok: 200,\n Created: 201,\n NoContent: 204,\n BadRequest: 400,\n Unauthorized: 401,\n Forbidden: 403,\n NotFound: 404,\n Conflict: 409,\n InternalError: 500,\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,YAAoC;AAAA,EAC7C,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,UAAU;AAAA,EACV,UAAU;AAAA,EACV,eAAe;AACnB;;;ADNO,SAAS,aAAa,KAAiB,UAAsC;AAChF,MAAI,SAAS;AACb,MAAI,SAAS,SAAS;AAClB,aAAS;AAAA,EACb,OAAO;AACH,UAAM,YAAY,SAAS,MAAM;AACjC,aAAS,UAAU,SAAS,KAAK;AAAA,EACrC;AACA,MAAI,OAAO,MAAM,EAAE,KAAK,QAAQ;AACpC;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/adapters/fastify.ts
|
|
21
|
+
var fastify_exports = {};
|
|
22
|
+
__export(fastify_exports, {
|
|
23
|
+
sendResponse: () => sendResponse
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(fastify_exports);
|
|
26
|
+
|
|
27
|
+
// src/core/status-map.ts
|
|
28
|
+
var statusMap = {
|
|
29
|
+
Ok: 200,
|
|
30
|
+
Created: 201,
|
|
31
|
+
NoContent: 204,
|
|
32
|
+
BadRequest: 400,
|
|
33
|
+
Unauthorized: 401,
|
|
34
|
+
Forbidden: 403,
|
|
35
|
+
NotFound: 404,
|
|
36
|
+
Conflict: 409,
|
|
37
|
+
InternalError: 500
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// src/adapters/fastify.ts
|
|
41
|
+
function sendResponse(reply, response) {
|
|
42
|
+
let status = 200;
|
|
43
|
+
if (!response.success) {
|
|
44
|
+
const errorCode = response.error.code;
|
|
45
|
+
status = statusMap[errorCode] || 500;
|
|
46
|
+
}
|
|
47
|
+
reply.status(status).send(response);
|
|
48
|
+
}
|
|
49
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
50
|
+
0 && (module.exports = {
|
|
51
|
+
sendResponse
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=fastify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/fastify.ts","../../src/core/status-map.ts"],"sourcesContent":["import {FastifyReply} from \"fastify\"\nimport { ApiResponse } from \"../core/response\"\nimport { statusMap } from \"../core/status-map\"\n\nexport function sendResponse(reply: FastifyReply, response: ApiResponse<unknown>): void {\n let status = 200\n\n if (!response.success) {\n const errorCode = response.error.code\n status = statusMap[errorCode] || 500\n }\n\n reply.status(status).send(response)\n}\n","export const statusMap: Record<string, number> = {\n Ok: 200,\n Created: 201,\n NoContent: 204,\n BadRequest: 400,\n Unauthorized: 401,\n Forbidden: 403,\n NotFound: 404,\n Conflict: 409,\n InternalError: 500,\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAO,IAAM,YAAoC;AAAA,EAC7C,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,UAAU;AAAA,EACV,UAAU;AAAA,EACV,eAAe;AACnB;;;ADNO,SAAS,aAAa,OAAqB,UAAsC;AACpF,MAAI,SAAS;AAEb,MAAI,CAAC,SAAS,SAAS;AACnB,UAAM,YAAY,SAAS,MAAM;AACjC,aAAS,UAAU,SAAS,KAAK;AAAA,EACrC;AAEA,QAAM,OAAO,MAAM,EAAE,KAAK,QAAQ;AACtC;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {
|
|
2
|
+
statusMap
|
|
3
|
+
} from "./chunk-VJJRPHMZ.mjs";
|
|
4
|
+
|
|
5
|
+
// src/adapters/express.ts
|
|
6
|
+
function sendResponse(res, response) {
|
|
7
|
+
let status = 200;
|
|
8
|
+
if (response.success) {
|
|
9
|
+
status = 200;
|
|
10
|
+
} else {
|
|
11
|
+
const errorCode = response.error.code;
|
|
12
|
+
status = statusMap[errorCode] || 500;
|
|
13
|
+
}
|
|
14
|
+
res.status(status).json(response);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
sendResponse
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=chunk-5HL56LEG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/express.ts"],"sourcesContent":["import {Response as ExResponse} from \"express\"\nimport {ApiResponse} from \"../core/response\";\nimport {statusMap} from \"../core/status-map\";\n\nexport function sendResponse(res: ExResponse, response: ApiResponse<unknown>): void {\n let status = 200\n if (response.success) {\n status = 200\n } else {\n const errorCode = response.error.code\n status = statusMap[errorCode] || 500\n }\n res.status(status).json(response)\n}"],"mappings":";;;;;AAIO,SAAS,aAAa,KAAiB,UAAsC;AAChF,MAAI,SAAS;AACb,MAAI,SAAS,SAAS;AAClB,aAAS;AAAA,EACb,OAAO;AACH,UAAM,YAAY,SAAS,MAAM;AACjC,aAAS,UAAU,SAAS,KAAK;AAAA,EACrC;AACA,MAAI,OAAO,MAAM,EAAE,KAAK,QAAQ;AACpC;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import {
|
|
2
|
+
statusMap
|
|
3
|
+
} from "./chunk-VJJRPHMZ.mjs";
|
|
4
|
+
|
|
5
|
+
// src/adapters/fastify.ts
|
|
6
|
+
function sendResponse(reply, response) {
|
|
7
|
+
let status = 200;
|
|
8
|
+
if (!response.success) {
|
|
9
|
+
const errorCode = response.error.code;
|
|
10
|
+
status = statusMap[errorCode] || 500;
|
|
11
|
+
}
|
|
12
|
+
reply.status(status).send(response);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export {
|
|
16
|
+
sendResponse
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=chunk-OD5AKNUG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/fastify.ts"],"sourcesContent":["import {FastifyReply} from \"fastify\"\nimport { ApiResponse } from \"../core/response\"\nimport { statusMap } from \"../core/status-map\"\n\nexport function sendResponse(reply: FastifyReply, response: ApiResponse<unknown>): void {\n let status = 200\n\n if (!response.success) {\n const errorCode = response.error.code\n status = statusMap[errorCode] || 500\n }\n\n reply.status(status).send(response)\n}\n"],"mappings":";;;;;AAIO,SAAS,aAAa,OAAqB,UAAsC;AACpF,MAAI,SAAS;AAEb,MAAI,CAAC,SAAS,SAAS;AACnB,UAAM,YAAY,SAAS,MAAM;AACjC,aAAS,UAAU,SAAS,KAAK;AAAA,EACrC;AAEA,QAAM,OAAO,MAAM,EAAE,KAAK,QAAQ;AACtC;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/core/status-map.ts
|
|
2
|
+
var statusMap = {
|
|
3
|
+
Ok: 200,
|
|
4
|
+
Created: 201,
|
|
5
|
+
NoContent: 204,
|
|
6
|
+
BadRequest: 400,
|
|
7
|
+
Unauthorized: 401,
|
|
8
|
+
Forbidden: 403,
|
|
9
|
+
NotFound: 404,
|
|
10
|
+
Conflict: 409,
|
|
11
|
+
InternalError: 500
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export {
|
|
15
|
+
statusMap
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=chunk-VJJRPHMZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/status-map.ts"],"sourcesContent":["export const statusMap: Record<string, number> = {\n Ok: 200,\n Created: 201,\n NoContent: 204,\n BadRequest: 400,\n Unauthorized: 401,\n Forbidden: 403,\n NotFound: 404,\n Conflict: 409,\n InternalError: 500,\n}"],"mappings":";AAAO,IAAM,YAAoC;AAAA,EAC7C,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,UAAU;AAAA,EACV,UAAU;AAAA,EACV,eAAe;AACnB;","names":[]}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { A as ApiSuccess, a as ApiError } from './response-DV8HnqXP.mjs';
|
|
2
|
+
export { b as ApiResponse } from './response-DV8HnqXP.mjs';
|
|
3
|
+
export { sendResponse as ExpressResponse } from './adapters/express.mjs';
|
|
4
|
+
export { sendResponse as FastifyResponse } from './adapters/fastify.mjs';
|
|
5
|
+
import 'express';
|
|
6
|
+
import 'fastify';
|
|
7
|
+
|
|
8
|
+
declare function Ok<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>;
|
|
9
|
+
declare function Created<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>;
|
|
10
|
+
declare function NoContent(message?: string): ApiSuccess<null>;
|
|
11
|
+
declare function CustomSuccess<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>;
|
|
12
|
+
|
|
13
|
+
declare function BadRequest(message: string, details?: unknown): ApiError;
|
|
14
|
+
declare function Unauthorized(message?: string): ApiError;
|
|
15
|
+
declare function Forbidden(message?: string): ApiError;
|
|
16
|
+
declare function NotFound(resource?: string): ApiError;
|
|
17
|
+
declare function Conflict(message: string): ApiError;
|
|
18
|
+
declare function InternalError(message?: string, details?: unknown): ApiError;
|
|
19
|
+
interface CustomErrorParams {
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
details?: unknown;
|
|
23
|
+
}
|
|
24
|
+
declare function CustomError({ code, message, details }: CustomErrorParams): ApiError;
|
|
25
|
+
|
|
26
|
+
export { ApiError, ApiSuccess, BadRequest, Conflict, Created, CustomError, CustomSuccess, Forbidden, InternalError, NoContent, NotFound, Ok, Unauthorized };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { A as ApiSuccess, a as ApiError } from './response-DV8HnqXP.js';
|
|
2
|
+
export { b as ApiResponse } from './response-DV8HnqXP.js';
|
|
3
|
+
export { sendResponse as ExpressResponse } from './adapters/express.js';
|
|
4
|
+
export { sendResponse as FastifyResponse } from './adapters/fastify.js';
|
|
5
|
+
import 'express';
|
|
6
|
+
import 'fastify';
|
|
7
|
+
|
|
8
|
+
declare function Ok<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>;
|
|
9
|
+
declare function Created<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>;
|
|
10
|
+
declare function NoContent(message?: string): ApiSuccess<null>;
|
|
11
|
+
declare function CustomSuccess<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>;
|
|
12
|
+
|
|
13
|
+
declare function BadRequest(message: string, details?: unknown): ApiError;
|
|
14
|
+
declare function Unauthorized(message?: string): ApiError;
|
|
15
|
+
declare function Forbidden(message?: string): ApiError;
|
|
16
|
+
declare function NotFound(resource?: string): ApiError;
|
|
17
|
+
declare function Conflict(message: string): ApiError;
|
|
18
|
+
declare function InternalError(message?: string, details?: unknown): ApiError;
|
|
19
|
+
interface CustomErrorParams {
|
|
20
|
+
code: string;
|
|
21
|
+
message: string;
|
|
22
|
+
details?: unknown;
|
|
23
|
+
}
|
|
24
|
+
declare function CustomError({ code, message, details }: CustomErrorParams): ApiError;
|
|
25
|
+
|
|
26
|
+
export { ApiError, ApiSuccess, BadRequest, Conflict, Created, CustomError, CustomSuccess, Forbidden, InternalError, NoContent, NotFound, Ok, Unauthorized };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
BadRequest: () => BadRequest,
|
|
24
|
+
Conflict: () => Conflict,
|
|
25
|
+
Created: () => Created,
|
|
26
|
+
CustomError: () => CustomError,
|
|
27
|
+
CustomSuccess: () => CustomSuccess,
|
|
28
|
+
ExpressResponse: () => sendResponse,
|
|
29
|
+
FastifyResponse: () => sendResponse2,
|
|
30
|
+
Forbidden: () => Forbidden,
|
|
31
|
+
InternalError: () => InternalError,
|
|
32
|
+
NoContent: () => NoContent,
|
|
33
|
+
NotFound: () => NotFound,
|
|
34
|
+
Ok: () => Ok,
|
|
35
|
+
Unauthorized: () => Unauthorized
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(index_exports);
|
|
38
|
+
|
|
39
|
+
// src/core/success.ts
|
|
40
|
+
function Ok(data, message, meta) {
|
|
41
|
+
return { success: true, data, message, meta };
|
|
42
|
+
}
|
|
43
|
+
function Created(data, message, meta) {
|
|
44
|
+
return { success: true, data, message, meta };
|
|
45
|
+
}
|
|
46
|
+
function NoContent(message) {
|
|
47
|
+
return { success: true, data: null, message };
|
|
48
|
+
}
|
|
49
|
+
function CustomSuccess(data, message, meta) {
|
|
50
|
+
return { success: true, data, message, meta };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// src/core/error.ts
|
|
54
|
+
function BadRequest(message, details) {
|
|
55
|
+
return { success: false, error: { code: "BAD_REQUEST", message, details } };
|
|
56
|
+
}
|
|
57
|
+
function Unauthorized(message = "Unauthorized") {
|
|
58
|
+
return { success: false, error: { code: "UNAUTHORIZED", message } };
|
|
59
|
+
}
|
|
60
|
+
function Forbidden(message = "Forbidden") {
|
|
61
|
+
return { success: false, error: { code: "FORBIDDEN", message } };
|
|
62
|
+
}
|
|
63
|
+
function NotFound(resource = "Resource") {
|
|
64
|
+
return { success: false, error: { code: "NOT_FOUND", message: `${resource} not found` } };
|
|
65
|
+
}
|
|
66
|
+
function Conflict(message) {
|
|
67
|
+
return { success: false, error: { code: "CONFLICT", message } };
|
|
68
|
+
}
|
|
69
|
+
function InternalError(message = "Internal server error", details) {
|
|
70
|
+
return { success: false, error: { code: "INTERNAL_ERROR", message, details } };
|
|
71
|
+
}
|
|
72
|
+
function CustomError({ code, message, details }) {
|
|
73
|
+
return {
|
|
74
|
+
success: false,
|
|
75
|
+
error: {
|
|
76
|
+
code,
|
|
77
|
+
message,
|
|
78
|
+
details
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// src/core/status-map.ts
|
|
84
|
+
var statusMap = {
|
|
85
|
+
Ok: 200,
|
|
86
|
+
Created: 201,
|
|
87
|
+
NoContent: 204,
|
|
88
|
+
BadRequest: 400,
|
|
89
|
+
Unauthorized: 401,
|
|
90
|
+
Forbidden: 403,
|
|
91
|
+
NotFound: 404,
|
|
92
|
+
Conflict: 409,
|
|
93
|
+
InternalError: 500
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/adapters/express.ts
|
|
97
|
+
function sendResponse(res, response) {
|
|
98
|
+
let status = 200;
|
|
99
|
+
if (response.success) {
|
|
100
|
+
status = 200;
|
|
101
|
+
} else {
|
|
102
|
+
const errorCode = response.error.code;
|
|
103
|
+
status = statusMap[errorCode] || 500;
|
|
104
|
+
}
|
|
105
|
+
res.status(status).json(response);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// src/adapters/fastify.ts
|
|
109
|
+
function sendResponse2(reply, response) {
|
|
110
|
+
let status = 200;
|
|
111
|
+
if (!response.success) {
|
|
112
|
+
const errorCode = response.error.code;
|
|
113
|
+
status = statusMap[errorCode] || 500;
|
|
114
|
+
}
|
|
115
|
+
reply.status(status).send(response);
|
|
116
|
+
}
|
|
117
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
118
|
+
0 && (module.exports = {
|
|
119
|
+
BadRequest,
|
|
120
|
+
Conflict,
|
|
121
|
+
Created,
|
|
122
|
+
CustomError,
|
|
123
|
+
CustomSuccess,
|
|
124
|
+
ExpressResponse,
|
|
125
|
+
FastifyResponse,
|
|
126
|
+
Forbidden,
|
|
127
|
+
InternalError,
|
|
128
|
+
NoContent,
|
|
129
|
+
NotFound,
|
|
130
|
+
Ok,
|
|
131
|
+
Unauthorized
|
|
132
|
+
});
|
|
133
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/success.ts","../src/core/error.ts","../src/core/status-map.ts","../src/adapters/express.ts","../src/adapters/fastify.ts"],"sourcesContent":["export type { ApiSuccess, ApiError, ApiResponse } from \"./core/response\"\n\nexport { Ok, Created, NoContent, CustomSuccess } from \"./core/success\"\n\nexport { BadRequest, Unauthorized, Forbidden, NotFound, Conflict, InternalError, CustomError } from \"./core/error\"\n\nexport {sendResponse as ExpressResponse} from \"./adapters/express\"\nexport {sendResponse as FastifyResponse} from \"./adapters/fastify\"","import {ApiSuccess} from \"./response\";\n\nexport function Ok<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>{\n return {success:true, data, message, meta}\n}\n\nexport function Created<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T> {\n return { success: true, data, message, meta }\n}\n\nexport function NoContent(message?: string): ApiSuccess<null> {\n return { success: true, data: null, message }\n}\n\nexport function CustomSuccess<T>(\n data: T,\n message?: string,\n meta?: Record<string, unknown>\n): ApiSuccess<T> {\n return { success: true, data, message, meta }\n}","import { ApiError } from \"./response\"\n\nexport function BadRequest(message: string, details?: unknown): ApiError {\n return { success: false, error: { code: \"BAD_REQUEST\", message, details } }\n}\n\nexport function Unauthorized(message = \"Unauthorized\"): ApiError {\n return { success: false, error: { code: \"UNAUTHORIZED\", message } }\n}\n\nexport function Forbidden(message = \"Forbidden\"): ApiError {\n return { success: false, error: { code: \"FORBIDDEN\", message } }\n}\n\nexport function NotFound(resource = \"Resource\"): ApiError {\n return { success: false, error: { code: \"NOT_FOUND\", message: `${resource} not found` } }\n}\n\nexport function Conflict(message: string): ApiError {\n return { success: false, error: { code: \"CONFLICT\", message } }\n}\n\nexport function InternalError(message = \"Internal server error\", details?: unknown): ApiError {\n return { success: false, error: { code: \"INTERNAL_ERROR\", message, details } }\n}\n\ninterface CustomErrorParams {\n code: string\n message: string\n details?: unknown\n}\nexport function CustomError({ code, message, details }: CustomErrorParams): ApiError {\n return {\n success: false,\n error: {\n code,\n message,\n details,\n },\n }\n}\n","export const statusMap: Record<string, number> = {\n Ok: 200,\n Created: 201,\n NoContent: 204,\n BadRequest: 400,\n Unauthorized: 401,\n Forbidden: 403,\n NotFound: 404,\n Conflict: 409,\n InternalError: 500,\n}","import {Response as ExResponse} from \"express\"\nimport {ApiResponse} from \"../core/response\";\nimport {statusMap} from \"../core/status-map\";\n\nexport function sendResponse(res: ExResponse, response: ApiResponse<unknown>): void {\n let status = 200\n if (response.success) {\n status = 200\n } else {\n const errorCode = response.error.code\n status = statusMap[errorCode] || 500\n }\n res.status(status).json(response)\n}","import {FastifyReply} from \"fastify\"\nimport { ApiResponse } from \"../core/response\"\nimport { statusMap } from \"../core/status-map\"\n\nexport function sendResponse(reply: FastifyReply, response: ApiResponse<unknown>): void {\n let status = 200\n\n if (!response.success) {\n const errorCode = response.error.code\n status = statusMap[errorCode] || 500\n }\n\n reply.status(status).send(response)\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAAA;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,SAAS,GAAM,MAAS,SAAkB,MAA8C;AAC3F,SAAO,EAAC,SAAQ,MAAM,MAAM,SAAS,KAAI;AAC7C;AAEO,SAAS,QAAW,MAAS,SAAkB,MAA+C;AACjG,SAAO,EAAE,SAAS,MAAM,MAAM,SAAS,KAAK;AAChD;AAEO,SAAS,UAAU,SAAoC;AAC1D,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM,QAAQ;AAChD;AAEO,SAAS,cACZ,MACA,SACA,MACa;AACb,SAAO,EAAE,SAAS,MAAM,MAAM,SAAS,KAAK;AAChD;;;AClBO,SAAS,WAAW,SAAiB,SAA6B;AACrE,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,eAAe,SAAS,QAAQ,EAAE;AAC9E;AAEO,SAAS,aAAa,UAAU,gBAA0B;AAC7D,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,gBAAgB,QAAQ,EAAE;AACtE;AAEO,SAAS,UAAU,UAAU,aAAuB;AACvD,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,aAAa,QAAQ,EAAE;AACnE;AAEO,SAAS,SAAS,WAAW,YAAsB;AACtD,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,aAAa,SAAS,GAAG,QAAQ,aAAa,EAAE;AAC5F;AAEO,SAAS,SAAS,SAA2B;AAChD,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,YAAY,QAAQ,EAAE;AAClE;AAEO,SAAS,cAAc,UAAU,yBAAyB,SAA6B;AAC1F,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,kBAAkB,SAAS,QAAQ,EAAE;AACjF;AAOO,SAAS,YAAY,EAAE,MAAM,SAAS,QAAQ,GAAgC;AACjF,SAAO;AAAA,IACH,SAAS;AAAA,IACT,OAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AACJ;;;ACxCO,IAAM,YAAoC;AAAA,EAC7C,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,UAAU;AAAA,EACV,UAAU;AAAA,EACV,eAAe;AACnB;;;ACNO,SAAS,aAAa,KAAiB,UAAsC;AAChF,MAAI,SAAS;AACb,MAAI,SAAS,SAAS;AAClB,aAAS;AAAA,EACb,OAAO;AACH,UAAM,YAAY,SAAS,MAAM;AACjC,aAAS,UAAU,SAAS,KAAK;AAAA,EACrC;AACA,MAAI,OAAO,MAAM,EAAE,KAAK,QAAQ;AACpC;;;ACTO,SAASC,cAAa,OAAqB,UAAsC;AACpF,MAAI,SAAS;AAEb,MAAI,CAAC,SAAS,SAAS;AACnB,UAAM,YAAY,SAAS,MAAM;AACjC,aAAS,UAAU,SAAS,KAAK;AAAA,EACrC;AAEA,QAAM,OAAO,MAAM,EAAE,KAAK,QAAQ;AACtC;","names":["sendResponse","sendResponse"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sendResponse
|
|
3
|
+
} from "./chunk-5HL56LEG.mjs";
|
|
4
|
+
import {
|
|
5
|
+
sendResponse as sendResponse2
|
|
6
|
+
} from "./chunk-OD5AKNUG.mjs";
|
|
7
|
+
import "./chunk-VJJRPHMZ.mjs";
|
|
8
|
+
|
|
9
|
+
// src/core/success.ts
|
|
10
|
+
function Ok(data, message, meta) {
|
|
11
|
+
return { success: true, data, message, meta };
|
|
12
|
+
}
|
|
13
|
+
function Created(data, message, meta) {
|
|
14
|
+
return { success: true, data, message, meta };
|
|
15
|
+
}
|
|
16
|
+
function NoContent(message) {
|
|
17
|
+
return { success: true, data: null, message };
|
|
18
|
+
}
|
|
19
|
+
function CustomSuccess(data, message, meta) {
|
|
20
|
+
return { success: true, data, message, meta };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/core/error.ts
|
|
24
|
+
function BadRequest(message, details) {
|
|
25
|
+
return { success: false, error: { code: "BAD_REQUEST", message, details } };
|
|
26
|
+
}
|
|
27
|
+
function Unauthorized(message = "Unauthorized") {
|
|
28
|
+
return { success: false, error: { code: "UNAUTHORIZED", message } };
|
|
29
|
+
}
|
|
30
|
+
function Forbidden(message = "Forbidden") {
|
|
31
|
+
return { success: false, error: { code: "FORBIDDEN", message } };
|
|
32
|
+
}
|
|
33
|
+
function NotFound(resource = "Resource") {
|
|
34
|
+
return { success: false, error: { code: "NOT_FOUND", message: `${resource} not found` } };
|
|
35
|
+
}
|
|
36
|
+
function Conflict(message) {
|
|
37
|
+
return { success: false, error: { code: "CONFLICT", message } };
|
|
38
|
+
}
|
|
39
|
+
function InternalError(message = "Internal server error", details) {
|
|
40
|
+
return { success: false, error: { code: "INTERNAL_ERROR", message, details } };
|
|
41
|
+
}
|
|
42
|
+
function CustomError({ code, message, details }) {
|
|
43
|
+
return {
|
|
44
|
+
success: false,
|
|
45
|
+
error: {
|
|
46
|
+
code,
|
|
47
|
+
message,
|
|
48
|
+
details
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export {
|
|
53
|
+
BadRequest,
|
|
54
|
+
Conflict,
|
|
55
|
+
Created,
|
|
56
|
+
CustomError,
|
|
57
|
+
CustomSuccess,
|
|
58
|
+
sendResponse as ExpressResponse,
|
|
59
|
+
sendResponse2 as FastifyResponse,
|
|
60
|
+
Forbidden,
|
|
61
|
+
InternalError,
|
|
62
|
+
NoContent,
|
|
63
|
+
NotFound,
|
|
64
|
+
Ok,
|
|
65
|
+
Unauthorized
|
|
66
|
+
};
|
|
67
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/success.ts","../src/core/error.ts"],"sourcesContent":["import {ApiSuccess} from \"./response\";\n\nexport function Ok<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>{\n return {success:true, data, message, meta}\n}\n\nexport function Created<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T> {\n return { success: true, data, message, meta }\n}\n\nexport function NoContent(message?: string): ApiSuccess<null> {\n return { success: true, data: null, message }\n}\n\nexport function CustomSuccess<T>(\n data: T,\n message?: string,\n meta?: Record<string, unknown>\n): ApiSuccess<T> {\n return { success: true, data, message, meta }\n}","import { ApiError } from \"./response\"\n\nexport function BadRequest(message: string, details?: unknown): ApiError {\n return { success: false, error: { code: \"BAD_REQUEST\", message, details } }\n}\n\nexport function Unauthorized(message = \"Unauthorized\"): ApiError {\n return { success: false, error: { code: \"UNAUTHORIZED\", message } }\n}\n\nexport function Forbidden(message = \"Forbidden\"): ApiError {\n return { success: false, error: { code: \"FORBIDDEN\", message } }\n}\n\nexport function NotFound(resource = \"Resource\"): ApiError {\n return { success: false, error: { code: \"NOT_FOUND\", message: `${resource} not found` } }\n}\n\nexport function Conflict(message: string): ApiError {\n return { success: false, error: { code: \"CONFLICT\", message } }\n}\n\nexport function InternalError(message = \"Internal server error\", details?: unknown): ApiError {\n return { success: false, error: { code: \"INTERNAL_ERROR\", message, details } }\n}\n\ninterface CustomErrorParams {\n code: string\n message: string\n details?: unknown\n}\nexport function CustomError({ code, message, details }: CustomErrorParams): ApiError {\n return {\n success: false,\n error: {\n code,\n message,\n details,\n },\n }\n}\n"],"mappings":";;;;;;;;;AAEO,SAAS,GAAM,MAAS,SAAkB,MAA8C;AAC3F,SAAO,EAAC,SAAQ,MAAM,MAAM,SAAS,KAAI;AAC7C;AAEO,SAAS,QAAW,MAAS,SAAkB,MAA+C;AACjG,SAAO,EAAE,SAAS,MAAM,MAAM,SAAS,KAAK;AAChD;AAEO,SAAS,UAAU,SAAoC;AAC1D,SAAO,EAAE,SAAS,MAAM,MAAM,MAAM,QAAQ;AAChD;AAEO,SAAS,cACZ,MACA,SACA,MACa;AACb,SAAO,EAAE,SAAS,MAAM,MAAM,SAAS,KAAK;AAChD;;;AClBO,SAAS,WAAW,SAAiB,SAA6B;AACrE,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,eAAe,SAAS,QAAQ,EAAE;AAC9E;AAEO,SAAS,aAAa,UAAU,gBAA0B;AAC7D,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,gBAAgB,QAAQ,EAAE;AACtE;AAEO,SAAS,UAAU,UAAU,aAAuB;AACvD,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,aAAa,QAAQ,EAAE;AACnE;AAEO,SAAS,SAAS,WAAW,YAAsB;AACtD,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,aAAa,SAAS,GAAG,QAAQ,aAAa,EAAE;AAC5F;AAEO,SAAS,SAAS,SAA2B;AAChD,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,YAAY,QAAQ,EAAE;AAClE;AAEO,SAAS,cAAc,UAAU,yBAAyB,SAA6B;AAC1F,SAAO,EAAE,SAAS,OAAO,OAAO,EAAE,MAAM,kBAAkB,SAAS,QAAQ,EAAE;AACjF;AAOO,SAAS,YAAY,EAAE,MAAM,SAAS,QAAQ,GAAgC;AACjF,SAAO;AAAA,IACH,SAAS;AAAA,IACT,OAAO;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,IACJ;AAAA,EACJ;AACJ;","names":[]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type ApiSuccess<T> = {
|
|
2
|
+
success: true;
|
|
3
|
+
data: T;
|
|
4
|
+
message?: string;
|
|
5
|
+
meta?: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
type ApiError = {
|
|
8
|
+
success: false;
|
|
9
|
+
error: {
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: unknown;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
type ApiResponse<T> = ApiSuccess<T> | ApiError;
|
|
16
|
+
|
|
17
|
+
export type { ApiSuccess as A, ApiError as a, ApiResponse as b };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
type ApiSuccess<T> = {
|
|
2
|
+
success: true;
|
|
3
|
+
data: T;
|
|
4
|
+
message?: string;
|
|
5
|
+
meta?: Record<string, unknown>;
|
|
6
|
+
};
|
|
7
|
+
type ApiError = {
|
|
8
|
+
success: false;
|
|
9
|
+
error: {
|
|
10
|
+
code: string;
|
|
11
|
+
message: string;
|
|
12
|
+
details?: unknown;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
type ApiResponse<T> = ApiSuccess<T> | ApiError;
|
|
16
|
+
|
|
17
|
+
export type { ApiSuccess as A, ApiError as a, ApiResponse as b };
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@0layimika/api-response-kit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A typed toolkit for consistent API success and error responses",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"type": "commonjs",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs"
|
|
13
|
+
},
|
|
14
|
+
"./express": {
|
|
15
|
+
"import": "./dist/adapters/express.js",
|
|
16
|
+
"require": "./dist/adapters/express.cjs"
|
|
17
|
+
},
|
|
18
|
+
"./fastify": {
|
|
19
|
+
"import": "./dist/adapters/fastify.js",
|
|
20
|
+
"require": "./dist/adapters/fastify.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup",
|
|
25
|
+
"dev": "tsup --watch",
|
|
26
|
+
"typecheck": "tsc --noEmit"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"express": "^5.2.1",
|
|
30
|
+
"fastify": "^5.6.2",
|
|
31
|
+
"tsup": "^8.5.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/express": "^5.0.6",
|
|
35
|
+
"@types/node": "^25.0.3",
|
|
36
|
+
"ts-node": "^10.9.2",
|
|
37
|
+
"typescript": "^5.9.3"
|
|
38
|
+
},
|
|
39
|
+
"private": false
|
|
40
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {Response as ExResponse} from "express"
|
|
2
|
+
import {ApiResponse} from "../core/response";
|
|
3
|
+
import {statusMap} from "../core/status-map";
|
|
4
|
+
|
|
5
|
+
export function sendResponse(res: ExResponse, response: ApiResponse<unknown>): void {
|
|
6
|
+
let status = 200
|
|
7
|
+
if (response.success) {
|
|
8
|
+
status = 200
|
|
9
|
+
} else {
|
|
10
|
+
const errorCode = response.error.code
|
|
11
|
+
status = statusMap[errorCode] || 500
|
|
12
|
+
}
|
|
13
|
+
res.status(status).json(response)
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {FastifyReply} from "fastify"
|
|
2
|
+
import { ApiResponse } from "../core/response"
|
|
3
|
+
import { statusMap } from "../core/status-map"
|
|
4
|
+
|
|
5
|
+
export function sendResponse(reply: FastifyReply, response: ApiResponse<unknown>): void {
|
|
6
|
+
let status = 200
|
|
7
|
+
|
|
8
|
+
if (!response.success) {
|
|
9
|
+
const errorCode = response.error.code
|
|
10
|
+
status = statusMap[errorCode] || 500
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
reply.status(status).send(response)
|
|
14
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ApiError } from "./response"
|
|
2
|
+
|
|
3
|
+
export function BadRequest(message: string, details?: unknown): ApiError {
|
|
4
|
+
return { success: false, error: { code: "BAD_REQUEST", message, details } }
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function Unauthorized(message = "Unauthorized"): ApiError {
|
|
8
|
+
return { success: false, error: { code: "UNAUTHORIZED", message } }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function Forbidden(message = "Forbidden"): ApiError {
|
|
12
|
+
return { success: false, error: { code: "FORBIDDEN", message } }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function NotFound(resource = "Resource"): ApiError {
|
|
16
|
+
return { success: false, error: { code: "NOT_FOUND", message: `${resource} not found` } }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function Conflict(message: string): ApiError {
|
|
20
|
+
return { success: false, error: { code: "CONFLICT", message } }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function InternalError(message = "Internal server error", details?: unknown): ApiError {
|
|
24
|
+
return { success: false, error: { code: "INTERNAL_ERROR", message, details } }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface CustomErrorParams {
|
|
28
|
+
code: string
|
|
29
|
+
message: string
|
|
30
|
+
details?: unknown
|
|
31
|
+
}
|
|
32
|
+
export function CustomError({ code, message, details }: CustomErrorParams): ApiError {
|
|
33
|
+
return {
|
|
34
|
+
success: false,
|
|
35
|
+
error: {
|
|
36
|
+
code,
|
|
37
|
+
message,
|
|
38
|
+
details,
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type ApiSuccess<T> = {
|
|
2
|
+
success:true,
|
|
3
|
+
data:T,
|
|
4
|
+
message?:string,
|
|
5
|
+
meta?: Record<string, unknown>
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ApiError = {
|
|
9
|
+
success:false,
|
|
10
|
+
error:{
|
|
11
|
+
code:string,
|
|
12
|
+
message:string,
|
|
13
|
+
details?:unknown
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type ApiResponse<T> = ApiSuccess<T> | ApiError
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {ApiSuccess} from "./response";
|
|
2
|
+
|
|
3
|
+
export function Ok<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T>{
|
|
4
|
+
return {success:true, data, message, meta}
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function Created<T>(data: T, message?: string, meta?: Record<string, unknown>): ApiSuccess<T> {
|
|
8
|
+
return { success: true, data, message, meta }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function NoContent(message?: string): ApiSuccess<null> {
|
|
12
|
+
return { success: true, data: null, message }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function CustomSuccess<T>(
|
|
16
|
+
data: T,
|
|
17
|
+
message?: string,
|
|
18
|
+
meta?: Record<string, unknown>
|
|
19
|
+
): ApiSuccess<T> {
|
|
20
|
+
return { success: true, data, message, meta }
|
|
21
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type { ApiSuccess, ApiError, ApiResponse } from "./core/response"
|
|
2
|
+
|
|
3
|
+
export { Ok, Created, NoContent, CustomSuccess } from "./core/success"
|
|
4
|
+
|
|
5
|
+
export { BadRequest, Unauthorized, Forbidden, NotFound, Conflict, InternalError, CustomError } from "./core/error"
|
|
6
|
+
|
|
7
|
+
export {sendResponse as ExpressResponse} from "./adapters/express"
|
|
8
|
+
export {sendResponse as FastifyResponse} from "./adapters/fastify"
|
|
File without changes
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "Bundler",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"outDir": "dist",
|
|
9
|
+
"rootDir": "src",
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src"]
|
|
14
|
+
}
|
package/tsup.config.ts
ADDED