From 21695a6590a4270002f2a00adc6a8bf91764fbad Mon Sep 17 00:00:00 2001 From: masaaki Date: Fri, 12 May 2023 01:00:10 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=2097:=20API=20I/F=E5=AE=9F=E8=A3=85?= =?UTF-8?q?=EF=BC=88=E3=83=A9=E3=82=A4=E3=82=BB=E3=83=B3=E3=82=B9=E6=B3=A8?= =?UTF-8?q?=E6=96=87=E7=99=BB=E9=8C=B2API=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task1681: API I/F実装(ライセンス注文登録API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1681) - 元PBIへのリンク(内容・目的などはそちらにあるはず)  [プロダクト バックログ項目 1221: ライセンスを注文したい](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_workitems/edit/1221) - 何をどう変更したか、追加したライブラリなど  ラフスケッチに基づき、ライセンス注文登録APIのI/F実装とopenapi化を行いました。 - このPull Requestでの対象/対象外  変更分すべてが対象になります - 影響範囲(他の機能にも影響があるか)  無し ## レビューポイント - Swagger UI上でテスト実行すると、正常時のレスポンスコードが200ではなく201となります。 湯本さんが実施されたユーザ追加のAPI I/F実装の動画を見ると、その時も201となっていたので、そのまま進めましたが、もし問題ある場合は指摘お願いします。 ## UIの変更 - 無し ## 動作確認状況 - ローカルでSwagger確認 ## 補足 - 相談、参考資料などがあれば --- dictation_server/src/api/odms/openapi.json | 81 +++++++++++++++++++ dictation_server/src/app.module.ts | 6 ++ .../licenses/licenses.controller.spec.ts | 24 ++++++ .../features/licenses/licenses.controller.ts | 49 +++++++++++ .../src/features/licenses/licenses.module.ts | 9 +++ .../licenses/licenses.service.spec.ts | 18 +++++ .../src/features/licenses/licenses.service.ts | 4 + .../src/features/licenses/types/types.ts | 11 +++ 8 files changed, 202 insertions(+) create mode 100644 dictation_server/src/features/licenses/licenses.controller.spec.ts create mode 100644 dictation_server/src/features/licenses/licenses.controller.ts create mode 100644 dictation_server/src/features/licenses/licenses.module.ts create mode 100644 dictation_server/src/features/licenses/licenses.service.spec.ts create mode 100644 dictation_server/src/features/licenses/licenses.service.ts create mode 100644 dictation_server/src/features/licenses/types/types.ts diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index 7331140..4ab6f02 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -1218,6 +1218,71 @@ } ] } + }, + "/licenses/orders": { + "post": { + "operationId": "createOrders", + "summary": "", + "parameters": [], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOrdersRequest" + } + } + } + }, + "responses": { + "200": { + "description": "成功時のレスポンス", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateOrdersResponse" + } + } + } + }, + "400": { + "description": "同一PONumberの注文がすでに存在する場合など", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "401": { + "description": "認証エラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "想定外のサーバーエラー", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "tags": ["licenses"], + "security": [ + { + "bearer": [] + } + ] + } } }, "info": { @@ -1867,6 +1932,22 @@ "RegisterResponse": { "type": "object", "properties": {} + }, + "CreateOrdersRequest": { + "type": "object", + "properties": { + "poNumber": { + "type": "string" + }, + "orderCount": { + "type": "number" + } + }, + "required": ["poNumber", "orderCount"] + }, + "CreateOrdersResponse": { + "type": "object", + "properties": {} } } } diff --git a/dictation_server/src/app.module.ts b/dictation_server/src/app.module.ts index b2b6929..2d5dd97 100644 --- a/dictation_server/src/app.module.ts +++ b/dictation_server/src/app.module.ts @@ -28,6 +28,9 @@ import { FilesService } from './features/files/files.service'; import { TasksService } from './features/tasks/tasks.service'; import { TasksController } from './features/tasks/tasks.controller'; import { TasksModule } from './features/tasks/tasks.module'; +import { LicensesModule } from './features/licenses/licenses.module'; +import { LicensesService } from './features/licenses/licenses.service'; +import { LicensesController } from './features/licenses/licenses.controller'; @Module({ imports: [ @@ -65,6 +68,7 @@ import { TasksModule } from './features/tasks/tasks.module'; }), NotificationModule, NotificationhubModule, + LicensesModule, ], controllers: [ HealthController, @@ -74,6 +78,7 @@ import { TasksModule } from './features/tasks/tasks.module'; FilesController, TasksController, UsersController, + LicensesController, ], providers: [ AuthService, @@ -82,6 +87,7 @@ import { TasksModule } from './features/tasks/tasks.module'; NotificationhubService, FilesService, TasksService, + LicensesService, ], }) export class AppModule { diff --git a/dictation_server/src/features/licenses/licenses.controller.spec.ts b/dictation_server/src/features/licenses/licenses.controller.spec.ts new file mode 100644 index 0000000..6577dce --- /dev/null +++ b/dictation_server/src/features/licenses/licenses.controller.spec.ts @@ -0,0 +1,24 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { LicensesController } from './licenses.controller'; +import { LicensesService } from './licenses.service'; + +describe('LicensesController', () => { + let controller: LicensesController; + const mockLicensesService = {}; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [LicensesController], + providers: [LicensesService], + }) + .overrideProvider(LicensesService) + .useValue(mockLicensesService) + .compile(); + + controller = module.get(LicensesController); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/dictation_server/src/features/licenses/licenses.controller.ts b/dictation_server/src/features/licenses/licenses.controller.ts new file mode 100644 index 0000000..57f5d87 --- /dev/null +++ b/dictation_server/src/features/licenses/licenses.controller.ts @@ -0,0 +1,49 @@ +import { Body, Controller, HttpStatus, Post, Req } from '@nestjs/common'; +import { + ApiResponse, + ApiTags, + ApiOperation, + ApiBearerAuth, +} from '@nestjs/swagger'; +import { ErrorResponse } from '../../common/error/types/types'; +import { LicensesService } from './licenses.service'; +import { CreateOrdersResponse, CreateOrdersRequest } from './types/types'; +import { Request } from 'express'; + +@ApiTags('licenses') +@Controller('licenses') +export class LicensesController { + constructor(private readonly licensesService: LicensesService) {} + + @ApiResponse({ + status: HttpStatus.OK, + type: CreateOrdersResponse, + description: '成功時のレスポンス', + }) + @ApiResponse({ + status: HttpStatus.BAD_REQUEST, + description: '同一PONumberの注文がすでに存在する場合など', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.UNAUTHORIZED, + description: '認証エラー', + type: ErrorResponse, + }) + @ApiResponse({ + status: HttpStatus.INTERNAL_SERVER_ERROR, + description: '想定外のサーバーエラー', + type: ErrorResponse, + }) + @ApiOperation({ operationId: 'createOrders' }) + @ApiBearerAuth() + @Post('/orders') + async createOrders( + @Req() req: Request, + @Body() body: CreateOrdersRequest, + ): Promise { + console.log(req.header('Authorization')); + console.log(body); + return {}; + } +} diff --git a/dictation_server/src/features/licenses/licenses.module.ts b/dictation_server/src/features/licenses/licenses.module.ts new file mode 100644 index 0000000..a223cf9 --- /dev/null +++ b/dictation_server/src/features/licenses/licenses.module.ts @@ -0,0 +1,9 @@ +import { Module } from '@nestjs/common'; +import { LicensesController } from './licenses.controller'; +import { LicensesService } from './licenses.service'; + +@Module({ + controllers: [LicensesController], + providers: [LicensesService], +}) +export class LicensesModule {} diff --git a/dictation_server/src/features/licenses/licenses.service.spec.ts b/dictation_server/src/features/licenses/licenses.service.spec.ts new file mode 100644 index 0000000..7288d3d --- /dev/null +++ b/dictation_server/src/features/licenses/licenses.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { LicensesService } from './licenses.service'; + +describe('LicensesService', () => { + let service: LicensesService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [LicensesService], + }).compile(); + + service = module.get(LicensesService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/dictation_server/src/features/licenses/licenses.service.ts b/dictation_server/src/features/licenses/licenses.service.ts new file mode 100644 index 0000000..4677a8f --- /dev/null +++ b/dictation_server/src/features/licenses/licenses.service.ts @@ -0,0 +1,4 @@ +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class LicensesService {} diff --git a/dictation_server/src/features/licenses/types/types.ts b/dictation_server/src/features/licenses/types/types.ts new file mode 100644 index 0000000..c34f0d1 --- /dev/null +++ b/dictation_server/src/features/licenses/types/types.ts @@ -0,0 +1,11 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class CreateOrdersRequest { + @ApiProperty() + poNumber: string; + + @ApiProperty() + orderCount: number; +} + +export class CreateOrdersResponse {}