-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 히스토리 api ts rest 적용 #599
Merged
The head ref may contain hidden characters: "598-\uD788\uC2A4\uD1A0\uB9AC-api-ts-rest-\uC801\uC6A9"
Merged
Changes from 30 commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
6bc0872
feat: histories 라우터에 추가
nyj001012 642c3ae
feat: histories controller 추가
nyj001012 0123076
feat: impl 추가
nyj001012 ae75767
feat: histories 전용 type 파일 추가
nyj001012 a03eb43
feat: histories service 추가
nyj001012 88a9052
feat: 권한 없음 에러 추가
nyj001012 3153397
feat: 권한 없음 에러 오브젝트 추가
nyj001012 99b5742
feat: meta 스키마 추가
nyj001012 e4d6bae
style: eslint comma 추가
nyj001012 b29e417
feat: contract에 histories 추가
nyj001012 4457518
feat: contract에 histories 명세 추가
nyj001012 399233b
feat: contract에 histories에서 사용하는 query string 스키마 추가
nyj001012 7c4ad3c
feat: contract에 공용으로 사용할 권한 없음 에러 스키마 추가
nyj001012 ba76a8d
feat(histories): histories controller 추가
nyj001012 37080d6
feat(histories): histories service 추가
nyj001012 3df6b8d
feat(histories): histories 조회 시의 query string schema 변경
nyj001012 dd774fe
feat(histories): 라우터 분기 자세하게 나눔
nyj001012 92d72de
feat(histories): histories service index.ts 추가
nyj001012 ec427df
fix: 쿼리 파라미터를 json으로 파싱
scarf005 96894cb
feat(histories): 결과 반환 시, literal이 아닌 아이템 리스트 반환
nyj001012 1d956ef
style(histories): import 형식 변경
nyj001012 ebc2df1
feat(histories): histories 조회 결과 200 시, 스키마 추가
nyj001012 2876193
feat(histories): 검색 조건 callsign 추가
nyj001012 a90eb0c
feat(histories): meta 스키마 추가
nyj001012 b81689c
feat(histories): id 타입 변경
nyj001012 8356875
feat(histories): meta 스키마 positiveInt로 변경
nyj001012 4636b8a
feat(histories): 서비스 함수 반환 타입 변경
nyj001012 a91fea2
feat(histories): getMyHistories 반환값 변경
nyj001012 9c5b560
feat(histories): 서비스 함수 반환 타입 변경
nyj001012 c2ed994
chore(histories): 서비스 파일 분리 및 컨트롤러 파일 분리
nyj001012 840747e
Merge branch 'develop' into 598-히스토리-api-ts-rest-적용
scarf005 eec4ade
fix: 스키마에서 date와 string 모두 허용
scarf005 2aa991f
fix: 패턴 매칭에서 타입이 좁혀지지 않던 문제
scarf005 d32ded4
fix: users 경로 숨김
scarf005 12c264b
fix: stocks 타입 오류 수정
scarf005 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { contract } from '@jiphyeonjeon-42/contracts'; | ||
import { P, match } from 'ts-pattern'; | ||
import { | ||
UnauthorizedError, | ||
HandlerFor, | ||
unauthorized, | ||
} from '../../shared'; | ||
import { HistoriesService } from '../service'; | ||
|
||
// mkGetMyHistories | ||
type GetMyDeps = Pick<HistoriesService, 'searchMyHistories'>; | ||
type MkGetMy = (services: GetMyDeps) => HandlerFor<typeof contract.histories.getMyHistories>; | ||
export const mkGetMyHistories: MkGetMy = ({ searchMyHistories }) => | ||
async ({ | ||
query: { | ||
query, page, limit, type, | ||
}, | ||
}) => { | ||
contract.histories.getMyHistories.query.safeParse({ | ||
query, page, limit, type, | ||
}); | ||
const result = await searchMyHistories({ | ||
query, page, limit, type, | ||
}); | ||
|
||
return match(result) | ||
.with(P.instanceOf(UnauthorizedError), () => unauthorized) | ||
.otherwise(() => ({ | ||
status: 200, | ||
body: result, | ||
} as const)); | ||
}; | ||
|
||
// mkGetAllHistories | ||
type GetAllDeps = Pick<HistoriesService, 'searchAllHistories'>; | ||
type MkGetAll = (services: GetAllDeps) => HandlerFor<typeof contract.histories.getAllHistories>; | ||
export const mkGetAllHistories: MkGetAll = ({ searchAllHistories }) => async ({ | ||
query: { query, page, limit, type }, | ||
}) => { | ||
const parsedQuery = contract.histories.getMyHistories.query.parse({ | ||
query, page, limit, type, | ||
}); | ||
const result = await searchAllHistories(parsedQuery); | ||
return match(result) | ||
.with(P.instanceOf(UnauthorizedError), () => unauthorized) | ||
.otherwise(() => ({ | ||
status: 200, | ||
body: result, | ||
} as const)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { mkGetMyHistories, mkGetAllHistories } from './controller'; | ||
import { | ||
HistoriesService, | ||
} from '../service'; | ||
|
||
export const implHistoriesController = (service: HistoriesService) => ({ | ||
getMyHistories: mkGetMyHistories(service), | ||
getAllHistories: mkGetAllHistories(service), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './controller'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { contract } from '@jiphyeonjeon-42/contracts'; | ||
import { initServer } from '@ts-rest/express'; | ||
import jipDataSource from '~/app-data-source'; | ||
import { roleSet } from '~/v1/auth/auth.type'; | ||
import authValidate from '~/v1/auth/auth.validate'; | ||
import { VHistories } from '~/entity/entities/VHistories'; | ||
import { implHistoriesService } from '~/v2/histories/service/impl'; | ||
import { implHistoriesController } from '~/v2/histories/controller/impl'; | ||
|
||
const service = implHistoriesService({ | ||
historiesRepo: jipDataSource.getRepository(VHistories), | ||
}); | ||
|
||
const handler = implHistoriesController(service); | ||
|
||
const s = initServer(); | ||
export const histories = s.router(contract.histories, { | ||
getMyHistories: { | ||
middleware: [authValidate(roleSet.all)], | ||
handler: handler.getMyHistories, | ||
}, | ||
getAllHistories: { | ||
middleware: [authValidate(roleSet.librarian)], | ||
handler: handler.getAllHistories, | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Repository } from 'typeorm'; | ||
import { VHistories } from '~/entity/entities/VHistories'; | ||
|
||
import { | ||
mkSearchHistories, | ||
} from './service'; | ||
|
||
export const implHistoriesService = (repos: { | ||
historiesRepo: Repository<VHistories>; | ||
}) => ({ | ||
searchMyHistories: mkSearchHistories(repos), | ||
searchAllHistories: mkSearchHistories(repos), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { VHistories } from '~/entity/entities/VHistories'; | ||
import { Meta, UnauthorizedError } from '~/v2/shared'; | ||
|
||
type Args = { | ||
query?: string | undefined; | ||
page: number; | ||
limit: number; | ||
type?: 'title' | 'user' | 'callsign' | undefined; | ||
}; | ||
|
||
export type HistoriesService = { | ||
searchMyHistories: ( | ||
args: Args, | ||
) => Promise<UnauthorizedError | { items: VHistories[], meta: Meta }>; | ||
searchAllHistories: ( | ||
args: Args, | ||
) => Promise<UnauthorizedError | { items: VHistories[], meta: Meta }>; | ||
} | ||
|
||
export * from './service'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
/* eslint-disable import/no-extraneous-dependencies */ | ||
import { match } from 'ts-pattern'; | ||
|
||
import { FindOperator, Like, type Repository } from 'typeorm'; | ||
import { VHistories } from '~/entity/entities/VHistories'; | ||
|
||
import { Meta } from '~/v2/shared'; | ||
import type { HistoriesService } from '.'; | ||
|
||
// HistoriesService | ||
|
||
type Repos = { historiesRepo: Repository<VHistories> }; | ||
|
||
type MkSearchHistories = ( | ||
repos: Repos | ||
) => HistoriesService['searchAllHistories']; | ||
|
||
type whereCondition = { | ||
login: FindOperator<string>, | ||
title: FindOperator<string>, | ||
callSign: FindOperator<string>, | ||
} | [ | ||
{ login: FindOperator<string> }, | ||
{ title: FindOperator<string> }, | ||
{ callSign: FindOperator<string> }, | ||
]; | ||
|
||
export const mkSearchHistories: MkSearchHistories = ({ historiesRepo }) => async ({ | ||
query, type, page, limit, | ||
}): Promise<{ items: VHistories[], meta: Meta }> => { | ||
let filterQuery: whereCondition = { | ||
login: Like('%%'), | ||
title: Like('%%'), | ||
callSign: Like('%%'), | ||
}; | ||
if (query !== undefined) { | ||
if (type === 'user') { | ||
filterQuery.login = Like(`%${query}%`); | ||
} else if (type === 'title') { | ||
filterQuery.title = Like(`%${query}%`); | ||
} else if (type === 'callsign') { | ||
filterQuery.callSign = Like(`%${query}%`); | ||
} else { | ||
filterQuery = [ | ||
{ login: Like(`%${query}%`) }, | ||
{ title: Like(`%${query}%`) }, | ||
{ callSign: Like(`%${query}%`) }, | ||
]; | ||
} | ||
} | ||
const [items, count] = await historiesRepo.findAndCount({ | ||
where: filterQuery, | ||
take: limit, | ||
skip: limit * page, | ||
}); | ||
const meta: Meta = { | ||
totalItems: count, | ||
itemCount: items.length, | ||
itemsPerPage: limit, | ||
totalPages: Math.ceil(count / limit), | ||
currentPage: page + 1, | ||
}; | ||
const returnObject = { | ||
items, | ||
meta, | ||
}; | ||
return returnObject; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { z } from 'zod'; | ||
import { positiveInt } from '~/v1/reviews/controller/reviews.type'; | ||
|
||
export type ParsedHistoriesSearchCondition = z.infer<typeof getHistoriesSearchCondition>; | ||
export const getHistoriesSearchCondition = z.object({ | ||
query: z.string().optional(), | ||
type: z.enum(['user', 'title', 'callsign']).optional(), | ||
page: z.number().nonnegative().default(0), | ||
limit: z.number().nonnegative().default(10), | ||
}); | ||
|
||
export type ParsedHistoriesUserInfo = z.infer<typeof getHistoriesUserInfo>; | ||
export const getHistoriesUserInfo = z.object({ | ||
userId: positiveInt, | ||
userRole: positiveInt.max(3), | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,14 @@ | ||
import { AppRoute } from '@ts-rest/core'; | ||
import { AppRouteOptions } from '@ts-rest/express'; | ||
import { z } from 'zod'; | ||
|
||
export type HandlerFor<T extends AppRoute> = AppRouteOptions<T>['handler']; | ||
|
||
export type Meta = z.infer<typeof meta>; | ||
export const meta = z.object({ | ||
totalItems: z.number().nonnegative(), | ||
nyj001012 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
itemCount: z.number().nonnegative(), | ||
itemsPerPage: z.number().nonnegative(), | ||
totalPages: z.number().nonnegative(), | ||
currentPage: z.number().nonnegative(), | ||
}); | ||
nyj001012 marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import { initContract } from '@ts-rest/core'; | ||
import { z } from 'zod'; | ||
import { | ||
historiesGetQuerySchema, historiesGetResponseSchema, | ||
} from './schema'; | ||
import { unauthorizedSchema } from '../shared'; | ||
|
||
export * from './schema'; | ||
|
||
// contract 를 생성할 때, router 함수를 사용하여 api 를 생성 | ||
const c = initContract(); | ||
|
||
export const historiesContract = c.router( | ||
{ | ||
getMyHistories: { | ||
method: 'GET', | ||
path: '/mypage/histories', | ||
description: '마이페이지에서 본인의 대출 기록을 가져온다.', | ||
query: historiesGetQuerySchema, | ||
responses: { | ||
200: historiesGetResponseSchema, | ||
401: unauthorizedSchema, | ||
}, | ||
}, | ||
getAllHistories: { | ||
method: 'GET', | ||
path: '/histories', | ||
description: '사서가 전체 대출 기록을 가져온다.', | ||
query: historiesGetQuerySchema, | ||
responses: { | ||
200: historiesGetResponseSchema, | ||
401: unauthorizedSchema, | ||
}, | ||
}, | ||
|
||
}, | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { metaSchema, positiveInt } from '../shared'; | ||
import { z } from '../zodWithOpenapi'; | ||
|
||
export const historiesGetQuerySchema = z.object({ | ||
query: z.string().optional(), | ||
type: z.enum(['user', 'title', 'callsign']).optional(), | ||
page: z.number().int().nonnegative().default(0), | ||
limit: z.number().int().nonnegative().default(10), | ||
}); | ||
|
||
export const historiesGetResponseSchema = z.object({ | ||
items: z.array( | ||
z.object({ | ||
id: positiveInt, | ||
lendingCondition: z.string(), | ||
login: z.string(), | ||
returningCondition: z.string(), | ||
penaltyDays: z.number().int().nonnegative(), | ||
callSign: z.string(), | ||
title: z.string(), | ||
bookInfoId: positiveInt, | ||
image: z.string(), | ||
createdAt: z.string(), | ||
returnedAt: z.string(), | ||
updatedAt: z.date(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
dueDate: z.string(), | ||
lendingLibrarianNickName: z.string(), | ||
returningLibrarianNickname: z.string(), | ||
}), | ||
), | ||
meta: metaSchema, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
반환값이
UnauthorizedError | { items: [...], meta: { ... } }
타입이기 때문에,UnauthorizedError
를 예상하지 못한 ts-rest에서 오류를 내고 있습니다. 다음을 참고하시면 타입을 좁힐 때 도움이 될 것 같습니다.https://github.com/gvergnaud/ts-pattern#withpattern-handler
https://github.com/gvergnaud/ts-pattern#exhaustive-otherwise-and-run