From 63862b19c04305230017e55434b9a760ff32a9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20LUDWIG?= Date: Tue, 13 Aug 2024 11:58:38 +0100 Subject: [PATCH] feat(api): implement GET /wikipedia/pages/[id] --- TODO.md | 3 +- .../routes/{tests => __tests__}/get.test.ts | 0 .../health/{tests => __tests__}/get.test.ts | 0 apps/api/src/app/routes/index.ts | 3 +- apps/api/src/app/routes/wikipedia/index.ts | 1 - .../pages/[id]/__tests__/get.test.ts | 52 +++++++++++++++++++ .../app/routes/wikipedia/pages/[id]/get.ts | 24 +++++++++ .../pages/{tests => __tests__}/get.test.ts | 0 apps/api/src/config/database.ts | 2 +- .../src/database/factories/page_factory.ts | 3 ++ 10 files changed, 84 insertions(+), 4 deletions(-) rename apps/api/src/app/routes/{tests => __tests__}/get.test.ts (100%) rename apps/api/src/app/routes/health/{tests => __tests__}/get.test.ts (100%) delete mode 100644 apps/api/src/app/routes/wikipedia/index.ts create mode 100644 apps/api/src/app/routes/wikipedia/pages/[id]/__tests__/get.test.ts create mode 100644 apps/api/src/app/routes/wikipedia/pages/[id]/get.ts rename apps/api/src/app/routes/wikipedia/pages/{tests => __tests__}/get.test.ts (100%) diff --git a/TODO.md b/TODO.md index 1e829cb..ac7912d 100644 --- a/TODO.md +++ b/TODO.md @@ -32,7 +32,8 @@ - [x] Init AdonisJS project - [x] Create Lucid models and migrations for Wikipedia Database Dump: `pages` and `internal_links` tables - [x] Implement `GET /wikipedia/pages?title=Node.js` to search a page by title (not necessarily with the title sanitized, search with input by user to check if page exists) - - [ ] Implement `GET /wikipedia/pages/internal-links/paths?from=Node.js&to=Linux` to get all the possible paths between 2 pages with titles sanitized + - [x] Implement `GET /wikipedia/pages/[id]` to get a page and all its internal links with the pageId + - [ ] Implement `GET /wikipedia/internal-links/paths?fromPageId=id&toPageId=id` to get all the possible paths between 2 pages - [x] Setup tests with database + add coverage - [x] Setup Health checks - [x] Setup Rate limiting diff --git a/apps/api/src/app/routes/tests/get.test.ts b/apps/api/src/app/routes/__tests__/get.test.ts similarity index 100% rename from apps/api/src/app/routes/tests/get.test.ts rename to apps/api/src/app/routes/__tests__/get.test.ts diff --git a/apps/api/src/app/routes/health/tests/get.test.ts b/apps/api/src/app/routes/health/__tests__/get.test.ts similarity index 100% rename from apps/api/src/app/routes/health/tests/get.test.ts rename to apps/api/src/app/routes/health/__tests__/get.test.ts diff --git a/apps/api/src/app/routes/index.ts b/apps/api/src/app/routes/index.ts index e19546a..71564fe 100644 --- a/apps/api/src/app/routes/index.ts +++ b/apps/api/src/app/routes/index.ts @@ -1,3 +1,4 @@ import "#app/routes/get.js" import "#app/routes/health/get.js" -import "#app/routes/wikipedia/index.js" +import "#app/routes/wikipedia/pages/[id]/get.js" +import "#app/routes/wikipedia/pages/get.js" diff --git a/apps/api/src/app/routes/wikipedia/index.ts b/apps/api/src/app/routes/wikipedia/index.ts deleted file mode 100644 index 138acf6..0000000 --- a/apps/api/src/app/routes/wikipedia/index.ts +++ /dev/null @@ -1 +0,0 @@ -import "#app/routes/wikipedia/pages/get.js" diff --git a/apps/api/src/app/routes/wikipedia/pages/[id]/__tests__/get.test.ts b/apps/api/src/app/routes/wikipedia/pages/[id]/__tests__/get.test.ts new file mode 100644 index 0000000..e0f6fa8 --- /dev/null +++ b/apps/api/src/app/routes/wikipedia/pages/[id]/__tests__/get.test.ts @@ -0,0 +1,52 @@ +import { PageFactory } from "#database/factories/page_factory.js" +import testUtils from "@adonisjs/core/services/test_utils" +import db from "@adonisjs/lucid/services/db" +import { test } from "@japa/runner" + +test.group("GET /wikipedia/pages/[id]", (group) => { + group.each.setup(async () => { + return await testUtils.db().truncate() + }) + + test("should succeeds and get the page with the given id, and get all its internal links", async ({ + client, + }) => { + // Arrange - Given + const page = await PageFactory.create() + const pages = await PageFactory.createMany(10) + const internalLinksPages = pages.slice(0, 5) + await Promise.all( + internalLinksPages.map(async (internalLinkPage) => { + await db.table("internal_links").insert({ + from_page_id: page.id, + to_page_id: internalLinkPage.id, + }) + }), + ) + + // Act - When + const response = await client.get(`/wikipedia/pages/${page.id}`) + + // Assert - Then + response.assertStatus(200) + response.assertBody({ + ...page.toJSON(), + internalLinks: internalLinksPages.map((page) => { + return page.toJSON() + }), + }) + }) + + test("should fails with a 404 status code when the page with the given id does not exist", async ({ + client, + }) => { + // Arrange - Given + const page = await PageFactory.create() + + // Act - When + const response = await client.get(`/wikipedia/pages/${page.id + 1}`) + + // Assert - Then + response.assertStatus(404) + }) +}) diff --git a/apps/api/src/app/routes/wikipedia/pages/[id]/get.ts b/apps/api/src/app/routes/wikipedia/pages/[id]/get.ts new file mode 100644 index 0000000..eb83628 --- /dev/null +++ b/apps/api/src/app/routes/wikipedia/pages/[id]/get.ts @@ -0,0 +1,24 @@ +import Page from "#app/models/page.js" +import { throttle } from "#start/limiter.js" +import type { HttpContext } from "@adonisjs/core/http" +import router from "@adonisjs/core/services/router" +import vine from "@vinejs/vine" + +const requestValidator = vine.compile( + vine.object({ + params: vine.object({ + id: vine.number().withoutDecimals().positive(), + }), + }), +) + +class Controller { + public async handle(context: HttpContext): Promise { + const payload = await context.request.validateUsing(requestValidator) + const page = await Page.findOrFail(payload.params.id) + await page.load("internalLinks") + return page + } +} + +router.get("/wikipedia/pages/:id", [Controller]).use(throttle) diff --git a/apps/api/src/app/routes/wikipedia/pages/tests/get.test.ts b/apps/api/src/app/routes/wikipedia/pages/__tests__/get.test.ts similarity index 100% rename from apps/api/src/app/routes/wikipedia/pages/tests/get.test.ts rename to apps/api/src/app/routes/wikipedia/pages/__tests__/get.test.ts diff --git a/apps/api/src/config/database.ts b/apps/api/src/config/database.ts index dc41e8a..4e8bcd4 100644 --- a/apps/api/src/config/database.ts +++ b/apps/api/src/config/database.ts @@ -7,7 +7,7 @@ const databaseConfig = defineConfig({ connection: app.inTest ? "sqlite" : "postgres", connections: { postgres: { - debug: !app.inProduction, + debug: app.inDev, client: "pg", connection: { host: env.get("DATABASE_HOST"), diff --git a/apps/api/src/database/factories/page_factory.ts b/apps/api/src/database/factories/page_factory.ts index 6a4c5c7..598a709 100644 --- a/apps/api/src/database/factories/page_factory.ts +++ b/apps/api/src/database/factories/page_factory.ts @@ -8,4 +8,7 @@ export const PageFactory = factory title: sanitizePageTitle(faker.commerce.productName()), } }) + .relation("internalLinks", () => { + return [] + }) .build()