Merged PR 62: デバイス登録APIのIF実装

## 概要
[Task1570: デバイス登録APIのIF実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1570)

- NotificationHubへのデバイス登録を行うAPIのIFを実装
  - MSへの問い合わせで想定していた引数で概ね問題ないとの回答
- OpenAPI生成関数が動作しなくなっていたので削除
  - 生成するためにはServiceごとにモックを作成しないといけないため修正コストが高すぎると判断

## レビューポイント
- Requestのプロパティについて認識違いは無いか
- 外部連携用のAPIも他のAPIと同様の場所に配置したが問題ないか
- 返却するステータスコードはこれで良いか?
  - 登録の成功は201?
  - エラー時のステータスコードの種類に過不足は無いか

## UIの変更
- Before/Afterのスクショなど
- スクショ置き場

## 動作確認状況
- OpenAPIを生成して確認

## 補足
This commit is contained in:
saito.k 2023-04-07 01:05:28 +00:00
parent 444cfda3b2
commit 382bb4e25f
11 changed files with 170 additions and 3 deletions

View File

@ -8,7 +8,7 @@
"scripts": {
"prebuild": "rimraf dist",
"build": "nest build",
"apigen:odms": "ts-node src/api/generate.ts",
"apigen": "ts-node src/api/generate.ts",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "nest start",
"start:dev": "nest start --watch",

View File

@ -1,3 +1,4 @@
// XXX 現状うまく動作しないため運用できない
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { Test } from '@nestjs/testing';
import { AppModule } from '../app.module';

View File

@ -171,6 +171,57 @@
},
"tags": ["users"]
}
},
"/notification/register": {
"post": {
"operationId": "register",
"summary": "",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RegisterRequest" }
}
}
},
"responses": {
"200": {
"description": "成功時のレスポンス",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/RegisterResponse" }
}
}
},
"400": {
"description": "不正なパラメータ",
"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": ["notification"],
"security": [{ "bearer": [] }]
}
}
},
"info": {
@ -260,7 +311,19 @@
"properties": { "token": { "type": "string" } },
"required": ["token"]
},
"ConfirmResponse": { "type": "object", "properties": {} }
"ConfirmResponse": { "type": "object", "properties": {} },
"RegisterRequest": {
"type": "object",
"properties": {
"pns": { "type": "string", "description": "wns or apns" },
"handler": {
"type": "string",
"description": "wnsのチャネルURI or apnsのデバイストークン"
}
},
"required": ["pns", "handler"]
},
"RegisterResponse": { "type": "object", "properties": {} }
}
}
}

View File

@ -19,6 +19,7 @@ import { AccountsRepositoryModule } from './repositories/accounts/accounts.repos
import { TypeOrmModule } from '@nestjs/typeorm';
import { SendGridModule } from './gateways/sendgrid/sendgrid.module';
import { UsersRepositoryModule } from './repositories/users/users.repository.module';
import { NotificationModule } from './features/notification/notification.module';
@Module({
imports: [
@ -51,6 +52,7 @@ import { UsersRepositoryModule } from './repositories/users/users.repository.mod
}),
inject: [ConfigService],
}),
NotificationModule,
],
controllers: [
HealthController,

View File

@ -11,7 +11,7 @@ import {
import { Account } from '../../repositories/accounts/entity/account.entity';
import { User } from '../../repositories/users/entity/user.entity';
import { TIER_5 } from '../../constants';
import { makeErrorResponse } from 'src/common/error/makeErrorResponse';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
@Injectable()
export class AccountsService {

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { NotificationController } from './notification.controller';
describe('NotificationController', () => {
let controller: NotificationController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [NotificationController],
}).compile();
controller = module.get<NotificationController>(NotificationController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@ -0,0 +1,42 @@
import { Body, Controller, HttpStatus, Post } from '@nestjs/common';
import {
ApiResponse,
ApiOperation,
ApiBearerAuth,
ApiTags,
} from '@nestjs/swagger';
import { ErrorResponse } from '../../common/error/types/types';
import { RegisterRequest, RegisterResponse } from './types/types';
import { NotificationService } from './notification.service';
@ApiTags('notification')
@Controller('notification')
@ApiBearerAuth()
export class NotificationController {
constructor(private readonly notificationService: NotificationService) {}
@Post('register')
@ApiResponse({
status: HttpStatus.OK,
type: RegisterResponse,
description: '成功時のレスポンス',
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: '不正なパラメータ',
type: ErrorResponse,
})
@ApiResponse({
status: HttpStatus.UNAUTHORIZED,
description: '認証エラー',
type: ErrorResponse,
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: '想定外のサーバーエラー',
type: ErrorResponse,
})
@ApiOperation({ operationId: 'register' })
async register(@Body() body: RegisterRequest): Promise<RegisterResponse> {
return {};
}
}

View File

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { NotificationService } from './notification.service';
import { NotificationController } from './notification.controller';
@Module({
providers: [NotificationService],
controllers: [NotificationController]
})
export class NotificationModule {}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { NotificationService } from './notification.service';
describe('NotificationService', () => {
let service: NotificationService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [NotificationService],
}).compile();
service = module.get<NotificationService>(NotificationService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class NotificationService {}

View File

@ -0,0 +1,10 @@
import { ApiProperty } from '@nestjs/swagger';
export class RegisterRequest {
@ApiProperty({ description: 'wns or apns' })
pns: string;
@ApiProperty({ description: 'wnsのチャネルURI or apnsのデバイストークン' })
handler: string;
}
export class RegisterResponse {}