Skip to content

Commit

Permalink
feat: TypedAxios 모듈 생성 (#674)
Browse files Browse the repository at this point in the history
* feat: Endpoint 객체 생성

* feat: 에러 발생 추가

* feat: makers 엔드포인트 적용

* feat: 검색 엔드포인트에 적용

* refactor: 폴더 추가

* feat: 코드리뷰 반영
  • Loading branch information
Tekiter authored Apr 28, 2023
1 parent 519248c commit c8fef26
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 7 deletions.
31 changes: 31 additions & 0 deletions api/endpoint/makers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { z } from 'zod';

import { createEndpoint } from '@/api/typedAxios';

export const getMakersProfile = createEndpoint({
request: {
method: 'GET',
url: `makers/profile`,
},
serverResponseScheme: z.array(
z.object({
id: z.number(),
name: z.string(),
profileImage: z.string().nullable(),
activities: z.array(
z.object({
id: z.number(),
generation: z.number(),
}),
),
careers: z.array(
z.object({
id: z.number(),
companyName: z.string(),
title: z.string(),
isCurrent: z.boolean(),
}),
),
}),
),
});
22 changes: 22 additions & 0 deletions api/endpoint/members/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { z } from 'zod';

import { createEndpoint } from '@/api/typedAxios';

export const getMembersSearchByName = createEndpoint({
request: (name: string) => ({
method: 'GET',
url: `api/v1/members/search?name=${encodeURIComponent(name)}`,
}),
serverResponseScheme: z.array(
z.object({
id: z.number(),
name: z.string(),
generation: z.number(),
hasProfile: z.boolean(),
profileImage: z
.string()
.nullable()
.transform((str) => str ?? ''),
}),
),
});
4 changes: 2 additions & 2 deletions api/endpoint_LEGACY/hooks/members.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useMutation, useQuery, UseQueryOptions } from '@tanstack/react-query';
import { AxiosError } from 'axios';

import { getMembersSearchByName } from '@/api/endpoint/members';
import {
getMemberOfMe,
getMemberProfileById,
getMemberProfileOfMe,
getMembersSearchByName,
postMemberCoffeeChat,
} from '@/api/endpoint_LEGACY/members';
import { PostMemberCoffeeChatVariables, ProfileDetail } from '@/api/endpoint_LEGACY/members/type';
Expand Down Expand Up @@ -74,7 +74,7 @@ export const useGetMembersSearchByName = (name: string) => {
return useQuery(
['getMembersSearchByName', name],
async () => {
const data = await getMembersSearchByName(name);
const data = await getMembersSearchByName.request(name);
return data;
},
{
Expand Down
46 changes: 46 additions & 0 deletions api/typedAxios.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { AxiosRequestConfig } from 'axios';
import { z } from 'zod';

import { axiosInstance } from '@/api';

interface Endpoint<ServerResponse, Params extends unknown[]> {
request(...params: Params): Promise<ServerResponse>;
}

export function createEndpoint<
Validator extends z.ZodType,
Param extends unknown[] = [],
Transformed = z.infer<Validator>,
>(config: {
request: AxiosRequestConfig | ((...params: Param) => AxiosRequestConfig);
serverResponseScheme: Validator;
transformer?: (original: z.infer<Validator>) => Transformed;
}): Endpoint<Transformed, Param> {
return {
async request(...params) {
const getConfig = () => {
if (typeof config.request === 'function') {
return config.request(...params);
}
return config.request;
};

const axiosConfig = getConfig();

const { data } = await axiosInstance.request<unknown>(axiosConfig);

const res = config.serverResponseScheme.safeParse(data);

if (!res.success) {
const zodError = String(res.error).slice(0, 1000) + '\n...';
const message = `서버 타입 검증에 실패했습니다. (${axiosConfig.method} ${axiosConfig.url})\n${zodError}`;
console.error(zodError);
throw new Error(message);
}

return res.data;
},
};
}

export type GetResponseType<T> = T extends Endpoint<infer R, never> ? R : never;
4 changes: 2 additions & 2 deletions components/projects/upload/hooks/useGetMembersByNameQuery.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useQuery } from '@tanstack/react-query';

import { getMembersSearchByName } from '@/api/endpoint_LEGACY/members';
import { getMembersSearchByName } from '@/api/endpoint/members';
interface GetMembersByNameQueryVariables {
name: string;
}
Expand All @@ -12,7 +12,7 @@ const useGetMembersByNameQuery = (variables: GetMembersByNameQueryVariables) =>
if (!name) {
return;
}
const data = await getMembersSearchByName(name);
const data = await getMembersSearchByName.request(name);
return data;
},
{
Expand Down
5 changes: 2 additions & 3 deletions pages/makers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { GetStaticProps } from 'next';
import { FC } from 'react';
import { RemoveScroll } from 'react-remove-scroll';

import { getMakersProfile } from '@/api/endpoint_LEGACY/makers';
import { getMakersProfile } from '@/api/endpoint/makers';
import Footer from '@/components/common/Footer';
import SwitchableHeader from '@/components/common/Header/SwitchableHeader';
import AboutMakers from '@/components/makers/AboutMakers';
Expand Down Expand Up @@ -32,11 +32,10 @@ const MakersPage: FC<MakersPageProps> = ({ memberMetadataList }) => {
};

export const getStaticProps: GetStaticProps<MakersPageProps> = async () => {
const memberList = await getMakersProfile();
const memberList = await getMakersProfile.request();

const memberMetadataList = memberList.map((member) => {
const sortedCareers = member.careers.filter((career) => career.isCurrent);
sortedCareers.sort((a, b) => new Date(a.startDate).getTime() - new Date(b.startDate).getTime());
const currentCompany = sortedCareers.length > 0 ? sortedCareers.at(-1)?.companyName ?? null : null;
const generations = member.activities.map((value) => value.generation).sort((a, b) => a - b);

Expand Down

0 comments on commit c8fef26

Please sign in to comment.