Skip to content

Commit b063cd1

Browse files
committed
refactor(api): implement types for api request
1 parent 8247751 commit b063cd1

7 files changed

Lines changed: 148 additions & 10 deletions

File tree

__tests__/unit/api/api.test.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
import { expect, test } from "vitest";
1+
import { describe, expect, it, test } from "vitest";
2+
import { PaginationParams } from "../../../src/api";
3+
import { Order, getValidOrder } from "../../../src/api/order";
24
import { RequestOptions, fetchFromApi } from "../../../src/api/request";
35

46
test("should returns 404 if path contains ignore chars", async () => {
@@ -8,3 +10,60 @@ test("should returns 404 if path contains ignore chars", async () => {
810
const response = await fetchFromApi("https://example.com/hoge.svg", options);
911
expect(response.status).toEqual(404);
1012
});
13+
14+
15+
describe("PaginationParams", () => {
16+
it("should accept valid PaginationParams object", () => {
17+
const params: PaginationParams = {
18+
page: 1,
19+
limit: 10,
20+
order: Order.DESC,
21+
};
22+
23+
expect(params.page).toBe(1);
24+
expect(params.limit).toBe(10);
25+
expect(params.order).toBe(Order.DESC);
26+
});
27+
28+
it("should work with different Order values", () => {
29+
const defaultParams: PaginationParams = {
30+
page: 1,
31+
limit: 20,
32+
order: Order.DEFAULT,
33+
};
34+
35+
const randomParams: PaginationParams = {
36+
page: 2,
37+
limit: 5,
38+
order: Order.RANDOM,
39+
};
40+
41+
expect(defaultParams.order).toBe(Order.DEFAULT);
42+
expect(randomParams.order).toBe(Order.RANDOM);
43+
});
44+
45+
it("should enforce correct types", () => {
46+
const params: PaginationParams = {
47+
page: 1,
48+
limit: 10,
49+
order: Order.DESC,
50+
};
51+
52+
expect(typeof params.page).toBe("number");
53+
expect(typeof params.limit).toBe("number");
54+
expect(typeof params.order).toBe("string");
55+
});
56+
57+
it("should work with getValidOrder function", () => {
58+
const orderParam = "desc";
59+
const validOrder = getValidOrder(orderParam);
60+
61+
const params: PaginationParams = {
62+
page: 1,
63+
limit: 10,
64+
order: validOrder,
65+
};
66+
67+
expect(params.order).toBe(Order.DESC);
68+
});
69+
});

__tests__/unit/api/order.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { describe, expect, it } from "vitest";
2+
import { Order, getValidOrder } from "../../../src/api/order";
3+
4+
describe("Order", () => {
5+
it("should have correct enum values", () => {
6+
expect(Order.DEFAULT).toBe("default");
7+
expect(Order.DESC).toBe("desc");
8+
expect(Order.RANDOM).toBe("random");
9+
});
10+
});
11+
12+
describe("getValidOrder", () => {
13+
it("should return Order.DESC when given 'desc'", () => {
14+
const result = getValidOrder("desc");
15+
expect(result).toBe(Order.DESC);
16+
});
17+
18+
it("should return Order.RANDOM when given 'random'", () => {
19+
const result = getValidOrder("random");
20+
expect(result).toBe(Order.RANDOM);
21+
});
22+
23+
it("should return Order.DEFAULT when given 'default'", () => {
24+
const result = getValidOrder("default");
25+
expect(result).toBe(Order.DEFAULT);
26+
});
27+
28+
it("should return Order.DEFAULT when given undefined", () => {
29+
const result = getValidOrder(undefined);
30+
expect(result).toBe(Order.DEFAULT);
31+
});
32+
33+
it("should return Order.DEFAULT when given invalid string", () => {
34+
const result = getValidOrder("invalid");
35+
expect(result).toBe(Order.DEFAULT);
36+
});
37+
38+
it("should return Order.DEFAULT when given empty string", () => {
39+
const result = getValidOrder("");
40+
expect(result).toBe(Order.DEFAULT);
41+
});
42+
43+
it("should return Order.DEFAULT when given null", () => {
44+
const result = getValidOrder(null as any);
45+
expect(result).toBe(Order.DEFAULT);
46+
});
47+
48+
it("should be case sensitive", () => {
49+
expect(getValidOrder("DESC")).toBe(Order.DEFAULT);
50+
expect(getValidOrder("Desc")).toBe(Order.DEFAULT);
51+
expect(getValidOrder("RANDOM")).toBe(Order.DEFAULT);
52+
});
53+
});

src/api/index.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,27 @@
11
import { api, publicApi } from "../../config";
22
import { requestContextFrom } from "../utils/requestContext";
33
import { buildQueryParams, buildUrl, sluggize } from "../utils/url";
4+
import { Order } from "./order";
45
import { RequestOptions, fetchFromApi, requestHeaderFrom } from "./request";
56

7+
export interface PaginationParams {
8+
page: number;
9+
limit: number;
10+
order: Order;
11+
}
12+
613
export function fetchArticles(
714
headers: Headers,
815
currentPage: number,
916
limit: number,
10-
order: string
17+
order: Order
1118
): Promise<Response> {
1219
const url = buildUrl(api.url, "v1/articles", true);
1320
const ctx = requestContextFrom(headers);
1421
const options: RequestOptions = {
1522
headers: requestHeaderFrom(ctx),
1623
queryParams: buildQueryParams({
17-
pagination: { page: currentPage, limit: limit, order: order }
24+
pagination: { page: currentPage, limit, order } as PaginationParams
1825
})
1926
};
2027
return fetchFromApi(url, options);
@@ -120,7 +127,7 @@ export function fetchTag(
120127
tagName: string,
121128
currentPage: number,
122129
limit: number,
123-
order: string
130+
order: Order
124131
): Promise<Response> {
125132
const url = buildUrl(
126133
api.url,
@@ -131,7 +138,7 @@ export function fetchTag(
131138
const options: RequestOptions = {
132139
headers: requestHeaderFrom(ctx),
133140
queryParams: buildQueryParams({
134-
pagination: { page: currentPage, limit: limit, order: order }
141+
pagination: { page: currentPage, limit, order } as PaginationParams
135142
})
136143
};
137144
return fetchFromApi(url, options);

src/api/order.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export enum Order {
2+
DEFAULT = 'default',
3+
DESC = 'desc',
4+
RANDOM = 'random'
5+
}
6+
7+
export function getValidOrder(orderParam: string | undefined): Order {
8+
switch (orderParam) {
9+
case Order.DESC:
10+
return Order.DESC;
11+
case Order.RANDOM:
12+
return Order.RANDOM;
13+
default:
14+
return Order.DEFAULT;
15+
}
16+
}

src/app/articles/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { headers } from "next/headers";
44
import { fetchArticles } from "../../api";
5+
import { getValidOrder, Order } from "../../api/order";
56
import { Article, ArticleResponseWithCount } from "../../models/models";
67
import { parseOrThrow, runWithHandleErrorIf } from "../handler";
78
import { Renderer } from "./renderer";
@@ -16,8 +17,8 @@ export default async function Page(req: any) {
1617

1718
async function handler(req: any) {
1819
const queryString = await req.searchParams;
19-
const order = queryString.order;
20-
const randomness = order === "random";
20+
const order = getValidOrder(queryString.order);
21+
const randomness = order === Order.RANDOM;
2122
const currentPage = queryString.p ? queryString.p : 1;
2223
const response: Response = await fetchArticles(
2324
await headers(),

src/app/page.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { headers } from "next/headers";
44
import { fetchArticles } from "../api";
5+
import { Order } from "../api/order";
56
import { Article, ArticleResponseWithCount } from "../models/models";
67
import { parseOrThrow, runWithHandleErrorIf } from "./handler";
78
import { Renderer } from "./renderer";
@@ -15,7 +16,7 @@ export default async function Page(req: any) {
1516
}
1617

1718
async function handler(req: any) {
18-
const response: Response = await fetchArticles(await headers(), 1, 5);
19+
const response: Response = await fetchArticles(await headers(), 1, 5, Order.DEFAULT);
1920
const articlesResponseWithCount =
2021
await parseOrThrow<ArticleResponseWithCount>(response);
2122
const articles: Array<Article> = articlesResponseWithCount.articles.map(

src/app/tags/[...slug]/page.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { headers } from "next/headers";
44
import { fetchTag } from "../../../api";
5+
import { getValidOrder, Order } from "../../../api/order";
56
import { Article, ArticleResponseWithCount } from "../../../models/models";
67
import { parseOrThrow, runWithHandleErrorIf } from "../../handler";
78
import { Renderer } from "./renderer";
@@ -19,8 +20,8 @@ async function handler(req: any) {
1920
const tagName = decodeURI(slug[0]);
2021

2122
const queryString = await req.searchParams;
22-
const order = queryString.order;
23-
const randomness = order === "random";
23+
const order = getValidOrder(queryString.order);
24+
const randomness = order === Order.RANDOM;
2425
const currentPage = queryString.p ? queryString.p : 1;
2526
const response: Response = await fetchTag(
2627
await headers(),

0 commit comments

Comments
 (0)