monorepo/server/post/api.ts

300 lines
9.9 KiB
TypeScript

import db from '@/lib/db/client';
import { ACCESS_TOKEN_COOKIE_NAME } from '@/lib/token';
import { createRoute, z } from '@hono/zod-openapi';
import { deleteCookie } from 'hono/cookie';
import { isNil } from 'lodash';
import {
createBodyRequest,
createErrorResponse,
createErrorResult,
createHonoApp,
createResponse,
paginateTransform,
} from '../common/utils';
import {
getPostItemRequestSchema,
postItemResponseSchema,
postPaginateResponseSchema,
} from './schema';
import { createPostItem, isSlugUnique } from './service';
const postTags = ['文章操作'];
const app = createHonoApp();
export const postApi = app
.openapi(
createRoute({
tags: postTags,
method: 'get',
path: '/slug/:slug',
request: {
params: z.object({
slug: z.string(),
}),
},
responses: {
...createResponse('请求成功', z.object({ slug: z.string() }).or(z.null()), 200),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const { slug } = c.req.valid('param');
const result = await db.post.findUnique({
where: { slug },
select: { slug: true },
});
return c.json(result, 200);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
)
.openapi(
createRoute({
tags: postTags,
method: 'get',
path: '/',
request: {
query: z.object({
page: z.coerce.number().optional(),
limit: z.coerce.number().optional(),
orderby: z.enum(['asc', 'desc']).optional(),
}),
},
responses: {
...createResponse('请求成功', postPaginateResponseSchema, 200),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const { page, limit, orderby } = c.req.valid('query');
const data = await db.post.paginate(
{
where: { slug: { not: { equals: null } } },
orderBy: [{ updatedAt: orderby || 'desc' }],
},
{
page: page || 1,
limit: limit || 10,
},
);
deleteCookie(c, ACCESS_TOKEN_COOKIE_NAME);
const result = paginateTransform(data);
return c.json(result, 200);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
)
.openapi(
createRoute({
tags: postTags,
method: 'get',
path: '/page-numbers',
request: {
query: z.object({
limit: z.coerce.number().optional(),
}),
},
responses: {
...createResponse('请求成功', z.object({ pageNumbers: z.array(z.number()) }), 200),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const { limit } = c.req.valid('query');
const count = await db.post.count();
const pageNumbers = Math.ceil(count / (limit || 10));
return c.json({ pageNumbers }, 200);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
)
.openapi(
createRoute({
tags: postTags,
method: 'get',
path: '/:item',
request: {
params: z.object({
item: z.string(),
}),
},
responses: {
...createResponse('请求成功', postItemResponseSchema, 200),
...createErrorResponse('查询不存在', 404),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const { item } = c.req.valid('param');
const result = await db.post.findFirst({
where: {
OR: [
{
id: item,
},
{
slug: item,
},
],
},
});
if (isNil(result)) {
return c.json(createErrorResult('查询不存在'), 404);
}
return c.json(result, 200);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
)
.openapi(
createRoute({
tags: postTags,
method: 'get',
path: '/id/:id',
request: {
params: z.object({
id: z.string(),
}),
},
responses: {
...createResponse('请求成功', postItemResponseSchema, 200),
...createErrorResponse('参数错误', 404),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const { id } = c.req.valid('param');
const result = await db.post.findUnique({
where: { id },
});
if (!result) {
return c.json(createErrorResult('文章不存在'), 404);
}
return c.json(result, 200);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
)
.openapi(
createRoute({
tags: postTags,
method: 'delete',
path: '/:id',
request: {
params: z.object({
id: z.string(),
}),
},
responses: {
...createResponse(
'刪除成功',
z
.object({
msg: z.string(),
id: z.string(),
})
.or(z.null()),
200,
),
...createErrorResponse('参数错误', 404),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const { id } = c.req.valid('param');
const result = await db.post.delete({
where: { id },
});
console.log(result);
if (isNil(result)) {
return c.json(createErrorResult('文章不存在'), 404);
}
return c.json({ msg: '删除成功', id: result.id }, 200);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
)
.openapi(
createRoute({
tags: postTags,
method: 'post',
path: '/',
request: {
...createBodyRequest(getPostItemRequestSchema(undefined)),
},
responses: {
...createResponse('请求成功', postItemResponseSchema, 200),
...createErrorResponse('参数错误', 400),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const schema = getPostItemRequestSchema(isSlugUnique());
const res = await c.req.json();
const validated = schema.safeParse(res);
if (!validated.success) {
return c.json(
createErrorResult('请求数据验证失败', validated.error.errors),
400,
);
}
const result = await createPostItem(validated.data);
return c.json(result, 201);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
)
.openapi(
createRoute({
tags: postTags,
method: 'patch',
path: '/:id',
request: {
params: z.object({ id: z.string() }),
...createBodyRequest(getPostItemRequestSchema(undefined)),
},
responses: {
...createResponse('请求成功', postItemResponseSchema, 200),
...createErrorResponse('提交失敗', 400),
500: { description: '服务器内部错误' },
},
}),
async (c) => {
try {
const { id } = c.req.valid('param');
const schema = getPostItemRequestSchema(isSlugUnique(id));
const validated = schema.safeParse(await c.req.json());
if (!validated.success) {
return c.json(
createErrorResult('请求数据验证失败', validated.error.errors),
400,
);
}
const result = await db.post.update({
where: { id },
data: validated.data,
});
return c.json(result, 200);
} catch (error) {
return c.json(createErrorResult('服务器内部错误', error), 500);
}
},
);