From 4c7571bcfe8b1df45edd4e3d2eea10675dc72f72 Mon Sep 17 00:00:00 2001 From: Artemy Date: Wed, 16 Aug 2023 10:36:04 +0300 Subject: [PATCH 1/5] feat: swagger --- package-lock.json | 42 ++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/app.ts | 13 +++++++++++++ 3 files changed, 56 insertions(+) diff --git a/package-lock.json b/package-lock.json index 63b556d..881f324 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@fastify/static": "^6.10.2", + "@fastify/swagger": "^8.8.0", "@fastify/view": "^8.0.0", "@mozilla/readability": "^0.4.4", "axios": "^1.4.0", @@ -211,6 +212,18 @@ "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/view": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@fastify/view/-/view-8.0.0.tgz", @@ -2091,6 +2104,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 +2333,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 +3319,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..2e08dc9 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "main": "dist/app.js", "dependencies": { "@fastify/static": "^6.10.2", + "@fastify/swagger": "^8.8.0", "@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..e874661 100644 --- a/src/app.ts +++ b/src/app.ts @@ -6,6 +6,7 @@ import path from "path"; import Fastify from "fastify"; import fastifyStatic from "@fastify/static"; import fastifyView from "@fastify/view"; +import fastifySwagger from "@fastify/swagger"; import ejs from "ejs"; import getRoute from "./routes/get"; @@ -36,6 +37,18 @@ class App { }, }); + await fastify.register(fastifySwagger, { + swagger: { + info: { + title: "Dottxt", + version: "1.0.0", + }, + externalDocs: { + url: "https://github.com/dottxt/dottxt", + }, + }, + }); + fastify.register(indexRoute); fastify.register(getRoute); fastify.register(parseRoute); From 9da9ea3adedb5de788c1f6007afc86bebb0c66ec Mon Sep 17 00:00:00 2001 From: Artemy Date: Wed, 16 Aug 2023 10:49:55 +0300 Subject: [PATCH 2/5] feat: swagger-ui In /doc route --- package-lock.json | 13 +++++++++++++ package.json | 1 + src/app.ts | 14 +++----------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 881f324..5bb3bb6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "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", @@ -224,6 +225,18 @@ "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", diff --git a/package.json b/package.json index 2e08dc9..fdebae3 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "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 e874661..0fab5e0 100644 --- a/src/app.ts +++ b/src/app.ts @@ -7,6 +7,7 @@ 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"; @@ -37,17 +38,8 @@ class App { }, }); - await fastify.register(fastifySwagger, { - swagger: { - info: { - title: "Dottxt", - version: "1.0.0", - }, - externalDocs: { - url: "https://github.com/dottxt/dottxt", - }, - }, - }); + await fastify.register(fastifySwagger); + await fastify.register(fastifySwaggerUi, { routePrefix: "/doc" }); fastify.register(indexRoute); fastify.register(getRoute); From 20755f2b8986cc27ddc68f95f3f91722033d36aa Mon Sep 17 00:00:00 2001 From: Artemy Date: Wed, 16 Aug 2023 11:54:22 +0300 Subject: [PATCH 3/5] doc: schema for get --- src/routes/get.ts | 60 +++++++++++++++++++++++-------------------- src/types/requests.ts | 39 +++++++++++++++++++++++++++- 2 files changed, 70 insertions(+), 29 deletions(-) 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/types/requests.ts b/src/types/requests.ts index a8e31b1..1639525 100644 --- a/src/types/requests.ts +++ b/src/types/requests.ts @@ -1,4 +1,4 @@ -import { FastifyRequest } from "fastify"; +import { FastifyRequest, FastifySchema } from "fastify"; export type GetRequest = FastifyRequest<{ Querystring: { @@ -8,6 +8,43 @@ export type GetRequest = FastifyRequest<{ }; }>; +export interface IGetQuery { + url: string; + format?: string; + engine?: string; +} + +export interface IGetSchema { + Querystring: IGetQuery; +} + +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: ["readability", "google", ""], + default: "readability", + }, + }, +}; + +export const GetSchema: FastifySchema = { + description: "Get page", + querystring: getQuerySchema, + produces: ["text/html"], +}; + export type EngineRequest = FastifyRequest<{ Querystring: { url: string; From b0bbcd0bba629ef068ebdf2be5d2604b20e9595c Mon Sep 17 00:00:00 2001 From: Artemy Date: Wed, 16 Aug 2023 12:07:12 +0300 Subject: [PATCH 4/5] doc: all available pages schema --- src/handlers/handler.interface.ts | 18 ++++++++++++ src/routes/index.ts | 3 +- src/routes/parse.ts | 30 ++++++++++--------- src/routes/raw-html.ts | 28 ++++++++++-------- src/types/requests.ts | 48 +++++++++++++++++++++++++++++-- templates/index.ejs | 6 ++-- 6 files changed, 101 insertions(+), 32 deletions(-) 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/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 1639525..157754d 100644 --- a/src/types/requests.ts +++ b/src/types/requests.ts @@ -1,4 +1,6 @@ import { FastifyRequest, FastifySchema } from "fastify"; +import { handlerSchema } from "../handlers/handler.interface"; +import { engineList } from "../handlers/main"; export type GetRequest = FastifyRequest<{ Querystring: { @@ -14,10 +16,23 @@ export interface IGetQuery { 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"], @@ -33,8 +48,22 @@ export const getQuerySchema = { }, engine: { type: "string", - enum: ["readability", "google", ""], - default: "readability", + enum: [...engineList, ""], + }, + }, +}; + +export const parseQuerySchema = { + type: "object", + required: ["url"], + properties: { + url: { + type: "string", + description: "URL", + }, + engine: { + type: "string", + enum: [...engineList, ""], }, }, }; @@ -42,6 +71,21 @@ export const getQuerySchema = { 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"], }; 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)=> { %> - + <% }) %> From af2c964e4dc6a0ccb13c5a024d2935c9c6ad94c8 Mon Sep 17 00:00:00 2001 From: Artemy Date: Wed, 16 Aug 2023 12:15:51 +0300 Subject: [PATCH 5/5] doc: add title, version, description to swagger --- src/app.ts | 12 +++++++++++- src/publicConfig.ts | 5 +++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/publicConfig.ts diff --git a/src/app.ts b/src/app.ts index 0fab5e0..2d9ea54 100644 --- a/src/app.ts +++ b/src/app.ts @@ -15,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; @@ -38,7 +40,15 @@ class App { }, }); - await fastify.register(fastifySwagger); + await fastify.register(fastifySwagger, { + swagger: { + info: { + title: "TXTDot API", + description: publicConfig.description, + version: publicConfig.version, + }, + }, + }); await fastify.register(fastifySwaggerUi, { routePrefix: "/doc" }); fastify.register(indexRoute); 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", +};