Error handler for API, separated schemas
This commit is contained in:
parent
e106509c45
commit
66ce1caab0
34
src/errors/api.ts
Normal file
34
src/errors/api.ts
Normal file
@ -0,0 +1,34 @@
|
||||
export interface IApiError {
|
||||
code: number;
|
||||
name: string;
|
||||
message: string;
|
||||
}
|
||||
|
||||
export const errorSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
code: {
|
||||
type: "number",
|
||||
description: "HTTP error code",
|
||||
},
|
||||
name: {
|
||||
type: "string",
|
||||
description: "Exception class name",
|
||||
},
|
||||
message: {
|
||||
type: "string",
|
||||
description: "Exception message",
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const errorResponseSchema = {
|
||||
type: "object",
|
||||
properties: {
|
||||
data: {
|
||||
type: "object",
|
||||
nullable: true,
|
||||
},
|
||||
error: errorSchema,
|
||||
},
|
||||
};
|
@ -4,14 +4,42 @@ import { getFastifyError } from "./validation";
|
||||
|
||||
export default function errorHandler(
|
||||
error: Error,
|
||||
_: FastifyRequest,
|
||||
req: FastifyRequest,
|
||||
reply: FastifyReply
|
||||
) {
|
||||
// TODO: check if req.url starts with "/api/" and return JSON
|
||||
|
||||
if (req.originalUrl.startsWith("/api/")) {
|
||||
return apiErrorHandler(error, reply);
|
||||
}
|
||||
return htmlErrorHandler(error, reply);
|
||||
}
|
||||
|
||||
function apiErrorHandler(error: Error, reply: FastifyReply) {
|
||||
function generateResponse(code: number) {
|
||||
return reply.code(code).send({
|
||||
data: null,
|
||||
error: {
|
||||
code: code,
|
||||
name: error.name,
|
||||
message: error.message,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
if (error instanceof NotHtmlMimetypeError) {
|
||||
return generateResponse(501);
|
||||
}
|
||||
|
||||
if (getFastifyError(error)?.statusCode === 400) {
|
||||
return generateResponse(400);
|
||||
}
|
||||
|
||||
if (error instanceof TxtDotError) {
|
||||
return generateResponse(error.code);
|
||||
}
|
||||
|
||||
return generateResponse(500);
|
||||
}
|
||||
|
||||
function htmlErrorHandler(error: Error, reply: FastifyReply) {
|
||||
if (error instanceof NotHtmlMimetypeError) {
|
||||
return reply.redirect(301, error.url);
|
||||
|
@ -1,27 +1,30 @@
|
||||
export class TxtDotError extends Error {
|
||||
export abstract class TxtDotError extends Error {
|
||||
code: number;
|
||||
name: string;
|
||||
description: string;
|
||||
|
||||
constructor(code: number, description: string) {
|
||||
constructor(code: number, name: string, description: string) {
|
||||
super(description);
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
|
||||
export class EngineParseError extends TxtDotError {
|
||||
constructor(message: string) {
|
||||
super(500, `Parse error: ${message}`);
|
||||
super(422, "EngineParseError", `Parse error: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class LocalResourceError extends TxtDotError {
|
||||
constructor() {
|
||||
super(403, "Proxying local resources is forbidden.");
|
||||
super(403, "LocalResourceError", "Proxying local resources is forbidden.");
|
||||
}
|
||||
}
|
||||
|
||||
export class NotHtmlMimetypeError extends Error {
|
||||
name: string = "NotHtmlMimetypeError";
|
||||
url: string;
|
||||
|
||||
constructor(url: string) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
|
||||
import { GetSchema, IGetSchema } from "../types/requests";
|
||||
import { GetSchema, IGetSchema } from "../types/requests/browser";
|
||||
import handlePage from "../handlers/main";
|
||||
import { generateRequestUrl } from "../utils/generate";
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
import { engineList } from "../handlers/main";
|
||||
import { indexSchema } from "../types/requests";
|
||||
import { indexSchema } from "../types/requests/browser";
|
||||
|
||||
export default async function indexRoute(fastify: FastifyInstance) {
|
||||
fastify.get("/", { schema: indexSchema }, async (_, reply) => {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import { EngineRequest, IParseSchema, parseSchema } from "../types/requests";
|
||||
import { FastifyInstance } from "fastify";
|
||||
|
||||
import { EngineRequest, IParseSchema, parseSchema } from "../types/requests/api";
|
||||
|
||||
import handlePage from "../handlers/main";
|
||||
import { generateRequestUrl } from "../utils/generate";
|
||||
|
||||
@ -8,7 +10,8 @@ export default async function parseRoute(fastify: FastifyInstance) {
|
||||
"/api/parse",
|
||||
{ schema: parseSchema },
|
||||
async (request: EngineRequest) => {
|
||||
return await handlePage(
|
||||
return {
|
||||
data: await handlePage(
|
||||
request.query.url,
|
||||
generateRequestUrl(
|
||||
request.protocol,
|
||||
@ -16,7 +19,9 @@ export default async function parseRoute(fastify: FastifyInstance) {
|
||||
request.originalUrl
|
||||
),
|
||||
request.query.engine
|
||||
);
|
||||
),
|
||||
error: null,
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
import { FastifyInstance } from "fastify";
|
||||
|
||||
import { GetRequest, IParseSchema, rawHtmlSchema } from "../types/requests";
|
||||
import { IParseSchema, rawHtmlSchema } from "../types/requests/api";
|
||||
import { GetRequest } from "../types/requests/browser";
|
||||
|
||||
import handlePage from "../handlers/main";
|
||||
import { generateRequestUrl } from "../utils/generate";
|
||||
|
||||
|
@ -1,95 +0,0 @@
|
||||
import { FastifyRequest, FastifySchema } from "fastify";
|
||||
import { handlerSchema } from "../handlers/handler.interface";
|
||||
import { engineList } from "../handlers/main";
|
||||
|
||||
export type GetRequest = FastifyRequest<{
|
||||
Querystring: IGetQuery;
|
||||
}>;
|
||||
|
||||
export interface IGetQuery {
|
||||
url: string;
|
||||
format?: string;
|
||||
engine?: string;
|
||||
}
|
||||
|
||||
export interface IParseQuery {
|
||||
url: string;
|
||||
engine?: string;
|
||||
}
|
||||
|
||||
export interface IGetSchema {
|
||||
Querystring: IGetQuery;
|
||||
}
|
||||
|
||||
export interface IParseSchema {
|
||||
Querystring: IParseQuery;
|
||||
}
|
||||
|
||||
export const indexSchema = {
|
||||
produces: ["text/html"],
|
||||
hide: true
|
||||
};
|
||||
|
||||
export const getQuerySchema = {
|
||||
type: "object",
|
||||
required: ["url"],
|
||||
properties: {
|
||||
url: {
|
||||
type: "string",
|
||||
description: "URL",
|
||||
},
|
||||
format: {
|
||||
type: "string",
|
||||
enum: ["text", "html", ""],
|
||||
default: "html",
|
||||
},
|
||||
engine: {
|
||||
type: "string",
|
||||
enum: [...engineList, ""],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const parseQuerySchema = {
|
||||
type: "object",
|
||||
required: ["url"],
|
||||
properties: {
|
||||
url: {
|
||||
type: "string",
|
||||
description: "URL",
|
||||
},
|
||||
engine: {
|
||||
type: "string",
|
||||
enum: [...engineList, ""],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const GetSchema: FastifySchema = {
|
||||
description: "Get page",
|
||||
hide: true,
|
||||
querystring: getQuerySchema,
|
||||
produces: ["text/html", "text/plain"],
|
||||
};
|
||||
|
||||
export const parseSchema: FastifySchema = {
|
||||
description: "Parse page",
|
||||
querystring: parseQuerySchema,
|
||||
response: {
|
||||
"2xx": handlerSchema,
|
||||
},
|
||||
produces: ["text/json"],
|
||||
};
|
||||
|
||||
export const rawHtmlSchema: FastifySchema = {
|
||||
description: "Get raw HTML",
|
||||
querystring: parseQuerySchema,
|
||||
produces: ["text/html"],
|
||||
};
|
||||
|
||||
export type EngineRequest = FastifyRequest<{
|
||||
Querystring: {
|
||||
url: string;
|
||||
engine?: string;
|
||||
};
|
||||
}>;
|
66
src/types/requests/api.ts
Normal file
66
src/types/requests/api.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import { FastifySchema, FastifyRequest } from "fastify";
|
||||
import { IApiError, errorResponseSchema } from "../../errors/api";
|
||||
import { handlerSchema } from "../../handlers/handler.interface";
|
||||
import { engineList } from "../../handlers/main";
|
||||
|
||||
export interface IApiResponse<T> {
|
||||
data?: T;
|
||||
error?: IApiError;
|
||||
}
|
||||
|
||||
export interface IParseQuery {
|
||||
url: string;
|
||||
engine?: string;
|
||||
}
|
||||
|
||||
export interface IParseSchema {
|
||||
Querystring: IParseQuery;
|
||||
}
|
||||
|
||||
export const parseQuerySchema = {
|
||||
type: "object",
|
||||
required: ["url"],
|
||||
properties: {
|
||||
url: {
|
||||
type: "string",
|
||||
description: "URL",
|
||||
},
|
||||
engine: {
|
||||
type: "string",
|
||||
enum: [...engineList, ""],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const parseSchema: FastifySchema = {
|
||||
description: "Parse the page and get all data from the engine",
|
||||
querystring: parseQuerySchema,
|
||||
response: {
|
||||
"2xx": {
|
||||
type: "object",
|
||||
properties: {
|
||||
data: handlerSchema,
|
||||
error: {
|
||||
type: "object",
|
||||
nullable: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
"4xx": errorResponseSchema,
|
||||
"5xx": errorResponseSchema,
|
||||
},
|
||||
produces: ["text/json"],
|
||||
};
|
||||
|
||||
export const rawHtmlSchema: FastifySchema = {
|
||||
description: "Parse the page and get raw HTML from the engine",
|
||||
querystring: parseQuerySchema,
|
||||
produces: ["text/html"],
|
||||
};
|
||||
|
||||
export type EngineRequest = FastifyRequest<{
|
||||
Querystring: {
|
||||
url: string;
|
||||
engine?: string;
|
||||
};
|
||||
}>;
|
48
src/types/requests/browser.ts
Normal file
48
src/types/requests/browser.ts
Normal file
@ -0,0 +1,48 @@
|
||||
import { FastifyRequest, FastifySchema } from "fastify";
|
||||
import { engineList } from "../../handlers/main";
|
||||
|
||||
export type GetRequest = FastifyRequest<{
|
||||
Querystring: IGetQuery;
|
||||
}>;
|
||||
|
||||
export interface IGetQuery {
|
||||
url: string;
|
||||
format?: string;
|
||||
engine?: string;
|
||||
}
|
||||
|
||||
export interface IGetSchema {
|
||||
Querystring: IGetQuery;
|
||||
}
|
||||
|
||||
export const indexSchema = {
|
||||
produces: ["text/html"],
|
||||
hide: true
|
||||
};
|
||||
|
||||
export const getQuerySchema = {
|
||||
type: "object",
|
||||
required: ["url"],
|
||||
properties: {
|
||||
url: {
|
||||
type: "string",
|
||||
description: "URL",
|
||||
},
|
||||
format: {
|
||||
type: "string",
|
||||
enum: ["text", "html", ""],
|
||||
default: "html",
|
||||
},
|
||||
engine: {
|
||||
type: "string",
|
||||
enum: [...engineList, ""],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const GetSchema: FastifySchema = {
|
||||
description: "Get page",
|
||||
hide: true,
|
||||
querystring: getQuerySchema,
|
||||
produces: ["text/html", "text/plain"],
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user