diff --git a/package-lock.json b/package-lock.json index 63b556d..5bb3bb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "license": "MIT", "dependencies": { "@fastify/static": "^6.10.2", + "@fastify/swagger": "^8.8.0", + "@fastify/swagger-ui": "^1.9.3", "@fastify/view": "^8.0.0", "@mozilla/readability": "^0.4.4", "axios": "^1.4.0", @@ -211,6 +213,30 @@ "node": ">=10" } }, + "node_modules/@fastify/swagger": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/@fastify/swagger/-/swagger-8.8.0.tgz", + "integrity": "sha512-tYI2lbItb4yg9FhQj+leK6DdIBICLbXkSR2vZjo117ygHyYQLxw2v0ere/d2PtDmYAx7SOJzxvg3w6y0Sxc3iw==", + "dependencies": { + "fastify-plugin": "^4.0.0", + "json-schema-resolver": "^2.0.0", + "openapi-types": "^12.0.0", + "rfdc": "^1.3.0", + "yaml": "^2.2.2" + } + }, + "node_modules/@fastify/swagger-ui": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/@fastify/swagger-ui/-/swagger-ui-1.9.3.tgz", + "integrity": "sha512-YYqce4CydjDIEry6Zo4JLjVPe5rjS8iGnk3fHiIQnth9sFSLeyG0U1DCH+IyYmLddNDg1uWJOuErlVqnu/jI3w==", + "dependencies": { + "@fastify/static": "^6.0.0", + "fastify-plugin": "^4.0.0", + "openapi-types": "^12.0.2", + "rfdc": "^1.3.0", + "yaml": "^2.2.2" + } + }, "node_modules/@fastify/view": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@fastify/view/-/view-8.0.0.tgz", @@ -2091,6 +2117,22 @@ } } }, + "node_modules/json-schema-resolver": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/json-schema-resolver/-/json-schema-resolver-2.0.0.tgz", + "integrity": "sha512-pJ4XLQP4Q9HTxl6RVDLJ8Cyh1uitSs0CzDBAz1uoJ4sRD/Bk7cFSXL1FUXDW3zJ7YnfliJx6eu8Jn283bpZ4Yg==", + "dependencies": { + "debug": "^4.1.1", + "rfdc": "^1.1.4", + "uri-js": "^4.2.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/Eomm/json-schema-resolver?sponsor=1" + } + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "dev": true, @@ -2304,6 +2346,11 @@ "wrappy": "1" } }, + "node_modules/openapi-types": { + "version": "12.1.3", + "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-12.1.3.tgz", + "integrity": "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw==" + }, "node_modules/optionator": { "version": "0.9.3", "dev": true, @@ -3285,6 +3332,14 @@ "version": "4.0.0", "license": "ISC" }, + "node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "engines": { + "node": ">= 14" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "license": "MIT", diff --git a/package.json b/package.json index 8a4739c..fdebae3 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,8 @@ "main": "dist/app.js", "dependencies": { "@fastify/static": "^6.10.2", + "@fastify/swagger": "^8.8.0", + "@fastify/swagger-ui": "^1.9.3", "@fastify/view": "^8.0.0", "@mozilla/readability": "^0.4.4", "axios": "^1.4.0", diff --git a/src/app.ts b/src/app.ts index 7fad46b..2d9ea54 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,6 +6,8 @@ import path from "path"; import Fastify from "fastify"; import fastifyStatic from "@fastify/static"; import fastifyView from "@fastify/view"; +import fastifySwagger from "@fastify/swagger"; +import fastifySwaggerUi from "@fastify/swagger-ui"; import ejs from "ejs"; import getRoute from "./routes/get"; @@ -13,6 +15,8 @@ import parseRoute from "./routes/parse"; import indexRoute from "./routes/index"; import rawHtml from "./routes/raw-html"; +import publicConfig from "./publicConfig"; + class App { config: IConfigService; @@ -36,6 +40,17 @@ class App { }, }); + await fastify.register(fastifySwagger, { + swagger: { + info: { + title: "TXTDot API", + description: publicConfig.description, + version: publicConfig.version, + }, + }, + }); + await fastify.register(fastifySwaggerUi, { routePrefix: "/doc" }); + fastify.register(indexRoute); fastify.register(getRoute); fastify.register(parseRoute); diff --git a/src/handlers/handler.interface.ts b/src/handlers/handler.interface.ts index 26c2053..14e69d3 100644 --- a/src/handlers/handler.interface.ts +++ b/src/handlers/handler.interface.ts @@ -4,3 +4,21 @@ export interface IHandlerOutput { title: string; lang: string; } + +export const handlerSchema = { + type: "object", + properties: { + content: { + type: "string", + }, + textContent: { + type: "string", + }, + title: { + type: "string", + }, + lang: { + type: "string", + }, + }, +}; diff --git a/src/publicConfig.ts b/src/publicConfig.ts new file mode 100644 index 0000000..57a09c7 --- /dev/null +++ b/src/publicConfig.ts @@ -0,0 +1,5 @@ +export default { + version: "1.0.0", + description: + "HTTP proxy that parses only text, links and pictures from pages reducing internet traffic, removing ads and heavy scripts", +}; diff --git a/src/routes/get.ts b/src/routes/get.ts index 227908f..413b1f9 100644 --- a/src/routes/get.ts +++ b/src/routes/get.ts @@ -1,38 +1,42 @@ import { FastifyInstance } from "fastify"; -import { GetRequest } from "../types/requests"; +import { GetSchema, IGetSchema } from "../types/requests"; import handlePage from "../handlers/main"; import { generateRequestUrl } from "../utils"; export default async function getRoute(fastify: FastifyInstance) { - fastify.get("/get", async (request: GetRequest, reply) => { - const remoteUrl = request.query.url; - const engine = request.query.engine; + fastify.get( + "/get", + { schema: GetSchema }, + async (request, reply) => { + const remoteUrl = request.query.url; + const engine = request.query.engine; - let format: string; + let format: string; - if (request.query.format === "text") { - reply.type("text/plain; charset=utf-8"); - format = "text"; - } else { - reply.type("text/html; charset=utf-8"); - format = "html"; + if (request.query.format === "text") { + reply.type("text/plain; charset=utf-8"); + format = "text"; + } else { + reply.type("text/html; charset=utf-8"); + format = "html"; + } + + const parsed = await handlePage( + remoteUrl, + generateRequestUrl( + request.protocol, + request.hostname, + request.originalUrl + ), + engine + ); + + if (format === "text") { + return parsed.textContent; + } else { + return reply.view("/templates/get.ejs", { parsed: parsed }); + } } - - const parsed = await handlePage( - remoteUrl, - generateRequestUrl( - request.protocol, - request.hostname, - request.originalUrl - ), - engine - ); - - if (format === "text") { - return parsed.textContent; - } else { - return reply.view("/templates/get.ejs", { parsed: parsed }); - } - }); + ); } diff --git a/src/routes/index.ts b/src/routes/index.ts index 200463a..ea3ff2d 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,8 +1,9 @@ import { FastifyInstance } from "fastify"; import { engineList } from "../handlers/main"; +import { indexSchema } from "../types/requests"; export default async function indexRoute(fastify: FastifyInstance) { - fastify.get("/", async (_, reply) => { + fastify.get("/", { schema: indexSchema }, async (_, reply) => { return reply.view("/templates/index.ejs", { engineList }); }); } diff --git a/src/routes/parse.ts b/src/routes/parse.ts index 87858ec..5523ff3 100644 --- a/src/routes/parse.ts +++ b/src/routes/parse.ts @@ -1,20 +1,22 @@ -import { EngineRequest } from "../types/requests"; +import { EngineRequest, IParseSchema, parseSchema } from "../types/requests"; import { FastifyInstance } from "fastify"; import handlePage from "../handlers/main"; import { generateRequestUrl } from "../utils"; export default async function parseRoute(fastify: FastifyInstance) { - fastify.get("/parse", async (request: EngineRequest) => { - const parsed = await handlePage( - request.query.url, - generateRequestUrl( - request.protocol, - request.hostname, - request.originalUrl - ), - request.query.engine - ); - - return parsed; - }); + fastify.get( + "/parse", + { schema: parseSchema }, + async (request: EngineRequest) => { + return await handlePage( + request.query.url, + generateRequestUrl( + request.protocol, + request.hostname, + request.originalUrl + ), + request.query.engine + ); + } + ); } diff --git a/src/routes/raw-html.ts b/src/routes/raw-html.ts index 4ac60d8..38fad4b 100644 --- a/src/routes/raw-html.ts +++ b/src/routes/raw-html.ts @@ -1,20 +1,24 @@ import { FastifyInstance } from "fastify"; -import { GetRequest } from "../types/requests"; +import { GetRequest, IParseSchema, rawHtmlSchema } from "../types/requests"; import handlePage from "../handlers/main"; import { generateRequestUrl } from "../utils"; export default async function rawHtml(fastify: FastifyInstance) { - fastify.get("/raw-html", async (request: GetRequest) => { - return ( - await handlePage( - request.query.url, - generateRequestUrl( - request.protocol, - request.hostname, - request.originalUrl + fastify.get( + "/raw-html", + { schema: rawHtmlSchema }, + async (request: GetRequest) => { + return ( + await handlePage( + request.query.url, + generateRequestUrl( + request.protocol, + request.hostname, + request.originalUrl + ) ) - ) - ).content; - }); + ).content; + } + ); } diff --git a/src/types/requests.ts b/src/types/requests.ts index a8e31b1..157754d 100644 --- a/src/types/requests.ts +++ b/src/types/requests.ts @@ -1,4 +1,6 @@ -import { FastifyRequest } from "fastify"; +import { FastifyRequest, FastifySchema } from "fastify"; +import { handlerSchema } from "../handlers/handler.interface"; +import { engineList } from "../handlers/main"; export type GetRequest = FastifyRequest<{ Querystring: { @@ -8,6 +10,85 @@ export type GetRequest = FastifyRequest<{ }; }>; +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"], +}; + +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", + 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; diff --git a/templates/index.ejs b/templates/index.ejs index 42e1bae..d996086 100644 --- a/templates/index.ejs +++ b/templates/index.ejs @@ -30,9 +30,9 @@ <% engineList.forEach((engine)=> { %> - + <% }) %>