Merged PR 76: API実装(I/F)
## 概要 [Task1576: API実装(I/F)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1576) - sas発行APIのIFを実装 - アップロード用のSAS発行API - GET /blob/uploadSas - ダウンロード用のSAS発行API - GET /blob/downloadSas - notification関連のフォーマット修正 - notification関連でlintエラーが出ていた箇所を修正 - openapi.jsonを生成するコマンドを使用できるように修正 ## レビューポイント - レスポンスとして返却する内容に不足は無いか - URIはこれで良さそうか ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば
This commit is contained in:
parent
6a5926ab3f
commit
0a970e814f
@ -8,8 +8,8 @@
|
||||
"scripts": {
|
||||
"prebuild": "rimraf dist",
|
||||
"build": "nest build",
|
||||
"apigen": "ts-node src/api/generate.ts",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"apigen": "ts-node src/api/generate.ts && prettier --write \"src/api/odms/*.json\"",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"src/api/odms/*.json\"",
|
||||
"start": "nest start",
|
||||
"start:dev": "nest start --watch",
|
||||
"start:debug": "nest start --debug --watch",
|
||||
|
||||
@ -1,24 +1,12 @@
|
||||
// XXX 現状うまく動作しないため運用できない
|
||||
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
|
||||
import { Test } from '@nestjs/testing';
|
||||
import { AppModule } from '../app.module';
|
||||
import { promises as fs } from 'fs';
|
||||
import { NestFactory } from '@nestjs/core';
|
||||
async function bootstrap(): Promise<void> {
|
||||
const controllers = Reflect.getMetadata('controllers', AppModule);
|
||||
const providers = Reflect.getMetadata('providers', AppModule);
|
||||
const mockedProviders = providers.map((provider) => {
|
||||
return {
|
||||
provide: provider.name,
|
||||
useValue: {},
|
||||
};
|
||||
const app = await NestFactory.create(AppModule, {
|
||||
preview: true,
|
||||
});
|
||||
|
||||
const testingModule = await Test.createTestingModule({
|
||||
controllers: controllers,
|
||||
providers: mockedProviders,
|
||||
}).compile();
|
||||
const app = testingModule.createNestApplication();
|
||||
|
||||
const options = new DocumentBuilder()
|
||||
.setTitle('ODMSOpenAPI')
|
||||
.setVersion('1.0.0')
|
||||
@ -32,7 +20,7 @@ async function bootstrap(): Promise<void> {
|
||||
const document = SwaggerModule.createDocument(app, options);
|
||||
await fs.writeFile(
|
||||
'src/api/odms/openapi.json',
|
||||
JSON.stringify(document, null, 2),
|
||||
JSON.stringify(document, null, 0),
|
||||
);
|
||||
}
|
||||
bootstrap();
|
||||
|
||||
@ -350,6 +350,88 @@
|
||||
"tags": ["notification"],
|
||||
"security": [{ "bearer": [] }]
|
||||
}
|
||||
},
|
||||
"/files/audio/upload-location": {
|
||||
"get": {
|
||||
"operationId": "uploadLocation",
|
||||
"summary": "",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功時のレスポンス",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AudioUploadLocationResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "認証エラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "想定外のサーバーエラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": ["files"],
|
||||
"security": [{ "bearer": [] }]
|
||||
}
|
||||
},
|
||||
"/files/audio/download-location": {
|
||||
"get": {
|
||||
"operationId": "downloadLocation",
|
||||
"summary": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"description": "音声ファイル情報をDBから取得するためのID",
|
||||
"schema": { "type": "string" }
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "成功時のレスポンス",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/AudioDownloadLocationResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "認証エラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||
}
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "想定外のサーバーエラー",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": ["files"],
|
||||
"security": [{ "bearer": [] }]
|
||||
}
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
@ -508,7 +590,17 @@
|
||||
},
|
||||
"required": ["pns", "handler"]
|
||||
},
|
||||
"RegisterResponse": { "type": "object", "properties": {} }
|
||||
"RegisterResponse": { "type": "object", "properties": {} },
|
||||
"AudioUploadLocationResponse": {
|
||||
"type": "object",
|
||||
"properties": { "url": { "type": "string" } },
|
||||
"required": ["url"]
|
||||
},
|
||||
"AudioDownloadLocationResponse": {
|
||||
"type": "object",
|
||||
"properties": { "url": { "type": "string" } },
|
||||
"required": ["url"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ import { UsersRepositoryModule } from './repositories/users/users.repository.mod
|
||||
import { NotificationhubModule } from './gateways/notificationhub/notificationhub.module';
|
||||
import { NotificationhubService } from './gateways/notificationhub/notificationhub.service';
|
||||
import { NotificationModule } from './features/notification/notification.module';
|
||||
import { BlobModule } from './features/blob/blob.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -56,6 +57,7 @@ import { NotificationModule } from './features/notification/notification.module'
|
||||
}),
|
||||
NotificationModule,
|
||||
NotificationhubModule,
|
||||
BlobModule,
|
||||
],
|
||||
controllers: [
|
||||
HealthController,
|
||||
|
||||
23
dictation_server/src/features/blob/blob.controller.spec.ts
Normal file
23
dictation_server/src/features/blob/blob.controller.spec.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { BlobController } from './blob.controller';
|
||||
import { BlobService } from './blob.service';
|
||||
|
||||
describe('BlobController', () => {
|
||||
let controller: BlobController;
|
||||
const mockBlobService = {};
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [BlobController],
|
||||
providers: [BlobService],
|
||||
})
|
||||
.overrideProvider(BlobService)
|
||||
.useValue(mockBlobService)
|
||||
.compile();
|
||||
|
||||
controller = module.get<BlobController>(BlobController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
79
dictation_server/src/features/blob/blob.controller.ts
Normal file
79
dictation_server/src/features/blob/blob.controller.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { Controller, Get, Headers, HttpStatus, Query } from '@nestjs/common';
|
||||
import {
|
||||
ApiResponse,
|
||||
ApiOperation,
|
||||
ApiBearerAuth,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { ErrorResponse } from '../../common/error/types/types';
|
||||
import { BlobService } from './blob.service';
|
||||
import {
|
||||
AudioUploadLocationResponse,
|
||||
AudioUploadLocationRequest,
|
||||
AudioDownloadLocationResponse,
|
||||
AudioDownloadLocationRequest,
|
||||
} from './types/types';
|
||||
|
||||
@ApiTags('files')
|
||||
@Controller('files')
|
||||
export class BlobController {
|
||||
constructor(private readonly blobService: BlobService) {}
|
||||
@Get('audio/upload-location')
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: AudioUploadLocationResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.UNAUTHORIZED,
|
||||
description: '認証エラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
description: '想定外のサーバーエラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiOperation({ operationId: 'uploadLocation' })
|
||||
@ApiBearerAuth()
|
||||
async uploadLocation(
|
||||
@Headers() headers,
|
||||
@Query() query: AudioUploadLocationRequest,
|
||||
): Promise<AudioUploadLocationResponse> {
|
||||
const {} = query;
|
||||
// コンテナ作成処理の前にアクセストークンの認証を行う
|
||||
// アップロード先を決定する国情報はトークンから取得する想定
|
||||
|
||||
return { url: '' };
|
||||
}
|
||||
|
||||
@Get('audio/download-location')
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
type: AudioDownloadLocationResponse,
|
||||
description: '成功時のレスポンス',
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.UNAUTHORIZED,
|
||||
description: '認証エラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiResponse({
|
||||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
description: '想定外のサーバーエラー',
|
||||
type: ErrorResponse,
|
||||
})
|
||||
@ApiOperation({ operationId: 'downloadLocation' })
|
||||
@ApiBearerAuth()
|
||||
async downloadLocation(
|
||||
@Headers() headers,
|
||||
@Query() body: AudioDownloadLocationRequest,
|
||||
): Promise<AudioDownloadLocationResponse> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const { id } = body;
|
||||
// コンテナ作成処理の前にアクセストークンの認証を行う
|
||||
//
|
||||
|
||||
return { url: '' };
|
||||
}
|
||||
}
|
||||
9
dictation_server/src/features/blob/blob.module.ts
Normal file
9
dictation_server/src/features/blob/blob.module.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { BlobService } from './blob.service';
|
||||
import { BlobController } from './blob.controller';
|
||||
|
||||
@Module({
|
||||
providers: [BlobService],
|
||||
controllers: [BlobController],
|
||||
})
|
||||
export class BlobModule {}
|
||||
18
dictation_server/src/features/blob/blob.service.spec.ts
Normal file
18
dictation_server/src/features/blob/blob.service.spec.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { BlobService } from './blob.service';
|
||||
|
||||
describe('BlobService', () => {
|
||||
let service: BlobService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [BlobService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<BlobService>(BlobService);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
4
dictation_server/src/features/blob/blob.service.ts
Normal file
4
dictation_server/src/features/blob/blob.service.ts
Normal file
@ -0,0 +1,4 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class BlobService {}
|
||||
18
dictation_server/src/features/blob/types/types.ts
Normal file
18
dictation_server/src/features/blob/types/types.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class AudioUploadLocationRequest {}
|
||||
|
||||
export class AudioUploadLocationResponse {
|
||||
@ApiProperty()
|
||||
url: string;
|
||||
}
|
||||
|
||||
export class AudioDownloadLocationRequest {
|
||||
@ApiProperty({ description: '音声ファイル情報をDBから取得するためのID' })
|
||||
id: string;
|
||||
}
|
||||
|
||||
export class AudioDownloadLocationResponse {
|
||||
@ApiProperty()
|
||||
url: string;
|
||||
}
|
||||
@ -4,8 +4,8 @@ import { NotificationController } from './notification.controller';
|
||||
import { NotificationhubModule } from '../../gateways/notificationhub/notificationhub.module';
|
||||
|
||||
@Module({
|
||||
imports:[NotificationhubModule],
|
||||
imports: [NotificationhubModule],
|
||||
providers: [NotificationService],
|
||||
controllers: [NotificationController]
|
||||
controllers: [NotificationController],
|
||||
})
|
||||
export class NotificationModule {}
|
||||
|
||||
@ -14,7 +14,7 @@ export class NotificationService {
|
||||
* @param pnsHandler
|
||||
* @returns register
|
||||
*/
|
||||
async register(pns: string, pnsHandler: string): Promise<{}> {
|
||||
async register(pns: string, pnsHandler: string): Promise<void> {
|
||||
this.logger.log(`[IN] ${this.register.name}`);
|
||||
try {
|
||||
await this.notificationhubService.register(pns, pnsHandler);
|
||||
@ -27,6 +27,5 @@ export class NotificationService {
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.register.name}`);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ import { NotificationhubService } from './notificationhub.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports:[ConfigModule],
|
||||
imports: [ConfigModule],
|
||||
exports: [NotificationhubService],
|
||||
providers: [NotificationhubService],
|
||||
})
|
||||
|
||||
@ -23,7 +23,7 @@ export class NotificationhubService {
|
||||
* @param pnsHandler
|
||||
* @returns register
|
||||
*/
|
||||
async register(pns: string, pnsHandler: string): Promise<{}> {
|
||||
async register(pns: string, pnsHandler: string): Promise<void> {
|
||||
this.logger.log(`[IN] ${this.register.name}`);
|
||||
let reg: RegistrationDescription;
|
||||
//登録情報作成
|
||||
@ -59,7 +59,5 @@ export class NotificationhubService {
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.register.name}`);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user