Merged PR 6: タスク 1362: API実装(I/F)
## 概要 [Task: 1362](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_sprints/taskboard/OMDSDictation%20%E3%83%81%E3%83%BC%E3%83%A0/OMDSDictation/%E3%82%B9%E3%83%97%E3%83%AA%E3%83%B3%E3%83%88%202_2?workitem=1362) - 以下のIFを実装 - AzureADのidトークンを受け取り、アクセストークン・リフレッシュトークンを返却するAPI - リフレッシュトークンを受け取り、アクセストークンを返却するAPI - エラー時のレスポンスを作成 ## レビューポイント - 各APIのリクエスト・レスポンスの型 ## UIの変更 - なし ## 動作確認状況 - SwaggerUIでAPIを確認 ## 補足
This commit is contained in:
parent
3b4b3c59e7
commit
c82d0363ac
2
dictation_client/codegen.sh
Normal file
2
dictation_client/codegen.sh
Normal file
@ -0,0 +1,2 @@
|
||||
npx openapi-generator-cli version-manager set latest
|
||||
npx openapi-generator-cli generate -g typescript-axios -i /app/dictation_server/src/api/odms/openapi.json -o /app/dictation_client/src/api/
|
||||
@ -2,6 +2,6 @@
|
||||
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
|
||||
"spaces": 2,
|
||||
"generator-cli": {
|
||||
"version": "6.2.1"
|
||||
"version": "6.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
import React from "react";
|
||||
|
||||
const SamplePage: React.FC = () => {
|
||||
return (<div>hello whorld!<br />Dictation App Service Site</div>)
|
||||
};
|
||||
const SamplePage: React.FC = () => (
|
||||
<div>
|
||||
hello whorld!
|
||||
<br />
|
||||
Dictation App Service Site
|
||||
</div>
|
||||
);
|
||||
|
||||
export default SamplePage;
|
||||
|
||||
@ -21,6 +21,12 @@ async function bootstrap(): Promise<void> {
|
||||
const options = new DocumentBuilder()
|
||||
.setTitle('ODMSOpenAPI')
|
||||
.setVersion('1.0.0')
|
||||
.addBearerAuth({
|
||||
type: 'http',
|
||||
scheme: 'bearer',
|
||||
bearerFormat: 'JWT',
|
||||
in: 'header',
|
||||
})
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
await fs.writeFile(
|
||||
|
||||
@ -12,10 +12,109 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/token": {
|
||||
"post": {
|
||||
"operationId": "token",
|
||||
"summary": "",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TokenRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功時のレスポンス",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TokenResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "認証エラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "想定外のサーバーエラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"auth"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/auth/accessToken": {
|
||||
"post": {
|
||||
"operationId": "accessToken",
|
||||
"summary": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功時のレスポンス",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AccessTokenResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "認証エラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "想定外のサーバーエラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ErrorResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"auth"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"bearer": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"title": "OMDSOpenAPI",
|
||||
"title": "ODMSOpenAPI",
|
||||
"description": "",
|
||||
"version": "1.0.0",
|
||||
"contact": {}
|
||||
@ -23,6 +122,72 @@
|
||||
"tags": [],
|
||||
"servers": [],
|
||||
"components": {
|
||||
"schemas": {}
|
||||
"securitySchemes": {
|
||||
"bearer": {
|
||||
"scheme": "bearer",
|
||||
"bearerFormat": "JWT",
|
||||
"type": "http",
|
||||
"in": "header"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"TokenRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"idToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"description": "web or mobile or desktop"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"idToken",
|
||||
"type"
|
||||
]
|
||||
},
|
||||
"TokenResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"refreshToken": {
|
||||
"type": "string"
|
||||
},
|
||||
"accessToken": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"refreshToken",
|
||||
"accessToken"
|
||||
]
|
||||
},
|
||||
"ErrorResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"code": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"message",
|
||||
"code"
|
||||
]
|
||||
},
|
||||
"AccessTokenResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"accessToken": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"accessToken"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,11 @@
|
||||
import { MiddlewareConsumer, Module } from '@nestjs/common';
|
||||
import { HealthController } from './health.controller';
|
||||
import { ServeStaticModule } from '@nestjs/serve-static';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { join } from 'path';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { LoggerMiddleware } from './common/loggerMiddleware';
|
||||
import { AuthModule } from './features/auth/auth.module';
|
||||
import { AuthController } from './features/auth/auth.controller';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -32,7 +32,7 @@ import { AuthModule } from './features/auth/auth.module';
|
||||
// inject: [ConfigService],
|
||||
// }),
|
||||
],
|
||||
controllers: [HealthController],
|
||||
controllers: [HealthController, AuthController],
|
||||
providers: [],
|
||||
})
|
||||
export class AppModule {
|
||||
|
||||
4
dictation_server/src/common/error/code.ts
Normal file
4
dictation_server/src/common/error/code.ts
Normal file
@ -0,0 +1,4 @@
|
||||
//TODO 仮のエラーコード作成
|
||||
export const ErrorCodes = [
|
||||
'E009999', // 汎用エラー
|
||||
] as const;
|
||||
10
dictation_server/src/common/error/makeErrorResponse.ts
Normal file
10
dictation_server/src/common/error/makeErrorResponse.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { errors } from './message';
|
||||
import { ErrorCodeType, ErrorResponse } from './types/types';
|
||||
|
||||
export const makeErrorResponse = (errorcode: ErrorCodeType): ErrorResponse => {
|
||||
const msg = errors[errorcode];
|
||||
return {
|
||||
code: errorcode,
|
||||
message: msg,
|
||||
};
|
||||
};
|
||||
6
dictation_server/src/common/error/message.ts
Normal file
6
dictation_server/src/common/error/message.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { Errors } from './types/types';
|
||||
|
||||
// エラーコードとメッセージ対応表
|
||||
export const errors: Errors = {
|
||||
E009999: 'Internal Server Error',
|
||||
};
|
||||
15
dictation_server/src/common/error/types/types.ts
Normal file
15
dictation_server/src/common/error/types/types.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
import { ErrorCodes } from '../code';
|
||||
|
||||
export class ErrorResponse {
|
||||
@ApiProperty()
|
||||
message: string;
|
||||
@ApiProperty()
|
||||
code: string;
|
||||
}
|
||||
|
||||
export type ErrorCodeType = (typeof ErrorCodes)[number];
|
||||
|
||||
export type Errors = {
|
||||
[P in ErrorCodeType]: string;
|
||||
};
|
||||
@ -1,4 +1,66 @@
|
||||
import { Controller } from '@nestjs/common';
|
||||
|
||||
import { Body, Controller, Headers, HttpStatus, Post } from '@nestjs/common';
|
||||
import {
|
||||
ApiResponse,
|
||||
ApiOperation,
|
||||
ApiBearerAuth,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { ErrorResponse } from '../../common/error/types/types';
|
||||
import {
|
||||
AccessTokenResponse,
|
||||
TokenRequest,
|
||||
TokenResponse,
|
||||
} from './types/types';
|
||||
@ApiTags('auth')
|
||||
@Controller('auth')
|
||||
export class AuthController {}
|
||||
export class AuthController {
|
||||
@Post('token')
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: TokenResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.UNAUTHORIZED,
|
||||
description: '認証エラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
description: '想定外のサーバーエラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiOperation({ operationId: 'token' })
|
||||
async token(@Body() body: TokenRequest): Promise<TokenResponse> {
|
||||
console.log(body);
|
||||
|
||||
return {
|
||||
accessToken: '',
|
||||
refreshToken: '',
|
||||
};
|
||||
}
|
||||
|
||||
@Post('accessToken')
|
||||
@ApiBearerAuth()
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: AccessTokenResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.UNAUTHORIZED,
|
||||
description: '認証エラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
description: '想定外のサーバーエラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiOperation({ operationId: 'accessToken' })
|
||||
async accessToken(@Headers() headers): Promise<AccessTokenResponse> {
|
||||
console.log(headers['authorization']);
|
||||
|
||||
return { accessToken: '' };
|
||||
}
|
||||
}
|
||||
|
||||
19
dictation_server/src/features/auth/types/types.ts
Normal file
19
dictation_server/src/features/auth/types/types.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class TokenRequest {
|
||||
@ApiProperty()
|
||||
idToken: string;
|
||||
@ApiProperty({ description: 'web or mobile or desktop' })
|
||||
type: string;
|
||||
}
|
||||
export class TokenResponse {
|
||||
@ApiProperty()
|
||||
refreshToken: string;
|
||||
@ApiProperty()
|
||||
accessToken: string;
|
||||
}
|
||||
export class AccessTokenResponse {
|
||||
@ApiProperty()
|
||||
accessToken: string;
|
||||
}
|
||||
export class AccessTokenRequest {}
|
||||
@ -18,6 +18,12 @@ async function bootstrap() {
|
||||
const options = new DocumentBuilder()
|
||||
.setTitle('ODMSOpenAPI')
|
||||
.setVersion('1.0.0')
|
||||
.addBearerAuth({
|
||||
type: 'http',
|
||||
scheme: 'bearer',
|
||||
bearerFormat: 'JWT',
|
||||
in: 'header',
|
||||
})
|
||||
.build();
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
SwaggerModule.setup('api', app, document);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user