From 69ea5a00eeb502b552ed8cd5540f09ed7b46c871 Mon Sep 17 00:00:00 2001 From: dswbx Date: Thu, 16 Jan 2025 17:18:30 +0100 Subject: [PATCH] DataApi: automatically switch to POST if the URL is too long --- app/__test__/api/DataApi.spec.ts | 16 ++++++++++++++++ app/__test__/api/ModuleApi.spec.ts | 4 ++++ app/src/data/api/DataApi.ts | 18 +++++++++++++----- 3 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 app/__test__/api/DataApi.spec.ts diff --git a/app/__test__/api/DataApi.spec.ts b/app/__test__/api/DataApi.spec.ts new file mode 100644 index 0000000..4fee5d9 --- /dev/null +++ b/app/__test__/api/DataApi.spec.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from "bun:test"; +import { DataApi } from "../../src/data/api/DataApi"; + +describe("DataApi", () => { + it("should switch to post for long url reads", async () => { + const api = new DataApi(); + + const get = api.readMany("a".repeat(100), { select: ["id", "name"] }); + expect(get.request.method).toBe("GET"); + expect(new URL(get.request.url).pathname).toBe(`/api/data/${"a".repeat(100)}`); + + const post = api.readMany("a".repeat(1000), { select: ["id", "name"] }); + expect(post.request.method).toBe("POST"); + expect(new URL(post.request.url).pathname).toBe(`/api/data/${"a".repeat(1000)}/query`); + }); +}); diff --git a/app/__test__/api/ModuleApi.spec.ts b/app/__test__/api/ModuleApi.spec.ts index caa42d0..5fb6976 100644 --- a/app/__test__/api/ModuleApi.spec.ts +++ b/app/__test__/api/ModuleApi.spec.ts @@ -28,6 +28,8 @@ describe("ModuleApi", () => { it("fetches endpoint", async () => { const app = new Hono().get("/endpoint", (c) => c.json({ foo: "bar" })); const api = new Api({ host }); + + // @ts-expect-error it's protected api.fetcher = app.request as typeof fetch; const res = await api.get("/endpoint"); @@ -40,6 +42,8 @@ describe("ModuleApi", () => { it("has accessible request", async () => { const app = new Hono().get("/endpoint", (c) => c.json({ foo: "bar" })); const api = new Api({ host }); + + // @ts-expect-error it's protected api.fetcher = app.request as typeof fetch; const promise = api.get("/endpoint"); diff --git a/app/src/data/api/DataApi.ts b/app/src/data/api/DataApi.ts index f2fe4e7..64eb9af 100644 --- a/app/src/data/api/DataApi.ts +++ b/app/src/data/api/DataApi.ts @@ -3,13 +3,15 @@ import type { EntityData, RepoQuery, RepoQueryIn, RepositoryResponse } from "dat import { type BaseModuleApiOptions, ModuleApi, type PrimaryFieldType } from "modules"; export type DataApiOptions = BaseModuleApiOptions & { - defaultQuery?: Partial; + queryLengthLimit: number; + defaultQuery: Partial; }; export class DataApi extends ModuleApi { protected override getDefaultOptions(): Partial { return { basepath: "/api/data", + queryLengthLimit: 1000, defaultQuery: { limit: 10 } @@ -28,10 +30,16 @@ export class DataApi extends ModuleApi { entity: E, query: RepoQueryIn = {} ) { - return this.get, "meta" | "data">>( - [entity as any], - query ?? this.options.defaultQuery - ); + type T = Pick, "meta" | "data">; + + const input = query ?? this.options.defaultQuery; + const exceeds = JSON.stringify([entity, input]).length > this.options.queryLengthLimit; + + if (exceeds) { + return this.post([entity as any, "query"], input); + } + + return this.get([entity as any], input); } readManyByReference<