-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.ts
More file actions
79 lines (66 loc) · 2.24 KB
/
Copy pathsearch.ts
File metadata and controls
79 lines (66 loc) · 2.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import { Hono } from "hono";
import type { HonoContext } from "../../types/env";
import { authMiddleware } from "../lib/auth";
import { validator, getValidated } from "../lib/validator";
import { rakutenSearchSchema, isbnSearchSchema } from "./schemas";
import type { RakutenSearchInput } from "./schemas/auth";
import { errorResponse, successResponse } from "../lib/response";
import { isValidISBN } from "../lib/validation";
import * as rakutenService from "../services/rakuten";
import { searchRateLimiter } from "../lib/rate-limit";
import { rankTechBooks } from "../domain/tech-book-search";
const app = new Hono<HonoContext>();
// 認証ミドルウェア適用
app.use("*", authMiddleware);
// 検索APIにRate Limiting適用(外部API呼び出しのため厳しめにする)
app.use("*", searchRateLimiter);
/**
* 楽天ブックス検索
* GET /api/search/books
*/
app.get("/books", validator("query", rakutenSearchSchema), async (c) => {
// バリデーション済みのデータを取得
const { query, limit, page, debug } = getValidated<RakutenSearchInput>(c, "query");
// queryがundefinedの場合はエラーを返す
if (!query) {
return errorResponse(c, "検索クエリが指定されていません", "VALIDATION_ERROR", 400);
}
const { results, hits, pageCount } = await rakutenService.searchBooks(
query,
c.env.RAKUTEN_APP_ID,
c.env.RAKUTEN_ACCESS_KEY,
c.env.RAKUTEN_REQUEST_ORIGIN,
limit ?? 20,
page ?? 1,
);
const sortedResults = rankTechBooks(results, query, {
includeReasons: debug === "1" || debug === "true",
});
return successResponse(c, {
results: sortedResults,
hits,
pageCount,
currentPage: page ?? 1,
});
});
/**
* ISBN検索
* GET /api/search/isbn/:isbn
*/
app.get("/isbn/:isbn", validator("param", isbnSearchSchema), async (c) => {
const isbn = c.req.param("isbn");
if (!isValidISBN(isbn)) {
return errorResponse(c, "Validation failed", "VALIDATION_ERROR", 400, "Invalid ISBN");
}
const result = await rakutenService.searchByISBN(
isbn,
c.env.RAKUTEN_APP_ID,
c.env.RAKUTEN_ACCESS_KEY,
c.env.RAKUTEN_REQUEST_ORIGIN,
);
if (!result) {
return successResponse(c, null);
}
return successResponse(c, result);
});
export default app;