Skip to content

Commit 024f4f8

Browse files
authored
feat: auth API 명세 (#60)
기존 API와 1:1 대응되게 옮겼습니다.
1 parent 9e902d6 commit 024f4f8

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { AuthController } from './auth.controller';
3+
4+
describe('AuthController', () => {
5+
let controller: AuthController;
6+
7+
beforeEach(async () => {
8+
const module: TestingModule = await Test.createTestingModule({
9+
controllers: [AuthController],
10+
}).compile();
11+
12+
controller = module.get<AuthController>(AuthController);
13+
});
14+
15+
it('should be defined', () => {
16+
expect(controller).toBeDefined();
17+
});
18+
});
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
import { createZodDto } from '@anatine/zod-nestjs';
2+
import { Body, Controller, Get, Post } from '@nestjs/common';
3+
import {
4+
ApiFoundResponse,
5+
ApiGoneResponse,
6+
ApiNoContentResponse,
7+
ApiOperation,
8+
ApiTags,
9+
ApiUnauthorizedResponse,
10+
} from '@nestjs/swagger';
11+
import { z } from 'zod';
12+
13+
const locationSchema = z.string().url();
14+
15+
const errorSchema = z.object({
16+
code: z.number(),
17+
message: z.string(),
18+
});
19+
class ErrorResponseDto extends createZodDto(errorSchema) {}
20+
21+
const userSchema = z.object({
22+
id: z.number().describe('로그인한 유저의 PK'),
23+
intra: z.string().describe('인트라 아이디 (인트라아이디가 없다면 email)'),
24+
librarian: z.boolean().describe('사서 여부'),
25+
email: z.string().email(),
26+
});
27+
class UserResponseDto extends createZodDto(userSchema) {}
28+
29+
const loginSchema = z.object({
30+
id: z.string(),
31+
password: z.string(),
32+
});
33+
class LoginDto extends createZodDto(loginSchema) {}
34+
35+
@Controller('auth')
36+
@ApiTags('auth')
37+
export class AuthController {
38+
constructor() {}
39+
40+
@Get('oauth')
41+
@ApiOperation({
42+
summary: '42 Api에 API key값을 추가해서 요청합니다.',
43+
description:
44+
'42 Api에 API key값을 추가해서 요청합니다. redirect 되기에 반환값을 확인할 수 없습니다.',
45+
})
46+
@ApiFoundResponse({
47+
description: '정상적으로 42 Api로 이동합니다.',
48+
headers: {
49+
Location: {
50+
description: '42 Api 주소로 이동합니다.',
51+
schema: { type: 'string', format: 'uri' },
52+
},
53+
},
54+
})
55+
async oauth() {}
56+
57+
@Get('token')
58+
@ApiOperation({
59+
summary: '42 OAuth Api의 반환값을 이용하여 토큰을 발급합니다.',
60+
description:
61+
'42 OAuth Api의 반환값을 이용하여 토큰을 발급합니다. redirect 되기에 반환값을 확인할 수 없습니다.',
62+
})
63+
@ApiFoundResponse({
64+
description: '성공적으로 토큰 발급',
65+
headers: {
66+
Location: {
67+
description:
68+
'브라우저에 유저정보를 저장 하는 frontend /auth 주소로 이동',
69+
schema: { type: 'string', format: 'uri' },
70+
},
71+
},
72+
})
73+
@ApiUnauthorizedResponse({
74+
description:
75+
'42 api와 연동된 ID가 없음, [front에서 알림 후 회원가입창으로 이동]',
76+
type: ErrorResponseDto,
77+
})
78+
async token() {}
79+
80+
@Get('me')
81+
@ApiOperation({
82+
summary: '클라이언트의 로그인된 유저 정보를 받아옵니다.',
83+
description: '클라이언트의 로그인된 유저 정보를 받아옵니다.',
84+
})
85+
@ApiFoundResponse({
86+
description: '로그인 되어 있는 유저의 정보를 반환합니다.',
87+
type: UserResponseDto,
88+
})
89+
@ApiUnauthorizedResponse({
90+
description: '토큰이 없을 경우 에러',
91+
type: ErrorResponseDto,
92+
})
93+
@ApiUnauthorizedResponse({
94+
description: '권한이 맞지 않을때 에러',
95+
type: ErrorResponseDto,
96+
})
97+
@ApiGoneResponse({
98+
description: '해당 토큰의 유저가 DB에 없을 경우의 에러',
99+
type: ErrorResponseDto,
100+
})
101+
async me() {}
102+
103+
@Post('login')
104+
@ApiOperation({
105+
summary: '로그인',
106+
description:
107+
'입력된 회원정보를 Users DB에서 확인하여, Token을 발급해 쿠키에 저장해줍니다.',
108+
})
109+
@ApiNoContentResponse({
110+
description: '성공적으로 토큰 발급',
111+
})
112+
@ApiUnauthorizedResponse({
113+
description: 'ID를 찾을 수 없는 경우',
114+
type: ErrorResponseDto,
115+
})
116+
@ApiUnauthorizedResponse({
117+
description: 'PW가 틀린 경우',
118+
type: ErrorResponseDto,
119+
})
120+
async login(@Body() { id, password }: LoginDto) {}
121+
122+
@Post('logout')
123+
@ApiOperation({
124+
summary: '로그아웃',
125+
description: '발급한 token을 소멸시킵니다.',
126+
})
127+
@ApiNoContentResponse({
128+
description: '정상적으로 token 삭제 완료',
129+
})
130+
async logout() {}
131+
132+
@Get('getIntraAuthentication')
133+
@ApiOperation({
134+
summary: '42 intra에 접근합니다.',
135+
description: 'redirect 되어 들어오기에 반환값을 확인할 수 없습니다.',
136+
})
137+
@ApiFoundResponse({
138+
description: '성공적으로 토큰 발급',
139+
headers: {
140+
Location: {
141+
description:
142+
'브라우저에 유저정보를 저장 하는 frontend /auth 주소로 이동',
143+
schema: { type: 'string', format: 'uri' },
144+
},
145+
},
146+
})
147+
getIntraAuthentication() {}
148+
149+
@Get('intraAuthentication')
150+
@ApiOperation({
151+
summary: '42 intra 인증을 실시합니다.',
152+
description: 'redirect 되어 들어오기에 반환값을 확인할 수 없습니다.',
153+
})
154+
@ApiFoundResponse({
155+
description: '성공적으로 토큰 발급',
156+
headers: {
157+
Location: {
158+
description:
159+
'브라우저에 유저정보를 저장 하는 frontend /auth 주소로 이동',
160+
schema: { type: 'string', format: 'uri' },
161+
},
162+
},
163+
})
164+
@ApiUnauthorizedResponse({
165+
description: 'ID, PW 값이 없는 잘못된 요청',
166+
type: ErrorResponseDto,
167+
})
168+
@ApiUnauthorizedResponse({
169+
description: '토큰이 없을 경우, 이미 인증된 회원의 경우',
170+
type: ErrorResponseDto,
171+
})
172+
@ApiGoneResponse({
173+
description: '해당 토큰의 유저가 DB에 없을 경우의 에러',
174+
type: ErrorResponseDto,
175+
})
176+
intraAuthentication() {}
177+
}

0 commit comments

Comments
 (0)