LifeSports Application(ReactNative & Nest.js) - 25. message-service(1)
34125 ワード
#1 message-service
Message-serviceはユーザー間でチャットするサービスです.例えば、user-aの文章を見たuser-bは、user-aと直接話して、一緒に運動したいという意味を表すことができます.
上の図に示すように、UIを構成し、まずメッセージ・サービスを実装します.
Message-serviceは少し複雑なので、まずケースを作成して作成します.
1)出版物(最初のメール):出版物を使用してメールを送信する場合は、出版物作成者のステータスである作成者をMessageRoomコンポーネントに送信してメールを作成できます.この場合、initRoomメソッドを使用してチャットルームを作成できます.
2)投稿(最初のメール以降):投稿でメールを送信すると、ユーザー間のチャットルームが存在する可能性があります.この場合、既存のチャットルームに入れます.
3)メッセージ・プライマリ・コンポーネントからチャット・ルームにジャンプした場合:この場合、ユーザー間にチャット・ルームがまだ存在するため、既存のチャット・ルームにロードされる.
#2プロジェクトの作成
次のコマンドを使用してmessage-serviceを作成します.
nest new message-service
cd message-service
nest generate module message
nest generate service message
コントローラを作成します.import { Body, Controller, Delete, Get, HttpStatus, Param, Post } from "@nestjs/common";
import { Builder } from "builder-pattern";
import { statusConstants } from "./constants/status.constants";
import { MessageDto } from "./dto/message.dto";
import { RoomDto } from "./dto/room.dto";
import { MessageService } from "./message/message.service";
import { RequestCheckRoom } from "./vo/request.check.room";
import { RequestInitRoom } from "./vo/request.init.room";
import { RequestMessage } from "./vo/request.message";
import { ResponseRoom } from "./vo/response.room";
@Controller("message-service")
export class AppController{
constructor(private readonly messageService: MessageService) {}
@Post('room/init-room')
public async initRoom(@Body() vo: RequestInitRoom): Promise<any> {
try {
if(!vo.user_a || !vo.user_b) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "vo is null"
});
}
const users: string[] = [];
users.push(vo.user_a);
users.push(vo.user_b);
const dto: any = await this.messageService.initRoom(Builder(RoomDto).users(users)
.build());
if(dto.status === statusConstants.ERROR) {
return await Object.assign({
status: HttpStatus.INTERNAL_SERVER_ERROR,
payload: null,
message: "Error message: " + dto.message
});
}
if(!dto.payload) {
return await Object.assign({
status: HttpStatus.NO_CONTENT,
payload: null,
message: dto.message
});
}
return await Object.assign({
status: HttpStatus.CREATED,
payload: Builder(ResponseRoom).roomId(dto.payload.roomId)
.users(dto.payload.users)
.messages(dto.payload.messages)
.createdAt(dto.payload.createdAt)
.build(),
message: "Successful make room",
});
} catch(err) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "Error message: " + err
});
}
}
@Post('message')
public async create(@Body() requestMessage: RequestMessage): Promise<any> {
try {
const dto: any = await this.messageService.create(Builder(MessageDto).sender(requestMessage.sender)
.receiver(requestMessage.receiver)
.content(requestMessage.content)
.build());
if(dto.status === statusConstants.ERROR) {
return await Object.assign({
status: HttpStatus.INTERNAL_SERVER_ERROR,
payload: null,
message: "Error message: " + dto.message
});
}
return await Object.assign({
status: HttpStatus.CREATED,
payload: true,
message: "Successfully create message"
});
} catch(err) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "Error message: " + err
});
}
}
@Get(':roomId/room')
public async getRoom(@Param('roomId') roomId: string): Promise<any> {
try {
const dto: any = await this.messageService.getRoom(roomId);
if(dto.status === statusConstants.ERROR) {
return await Object.assign({
status: HttpStatus.INTERNAL_SERVER_ERROR,
payload: null,
message: "Error message: " + dto.message
});
}
return await Object.assign({
status: HttpStatus.OK,
payload: Builder(ResponseRoom).roomId(dto.payload.roomId)
.users(dto.payload.users)
.messages(dto.payload.messages)
.createdAt(dto.payload.createdAt)
.build(),
message: "Get room data"
});
} catch(err) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "Error message: " + err
});
}
}
@Get(':nickname/rooms')
public async getRooms(@Param('nickname') nickname: string): Promise<any> {
try {
const dtos: any = await this.messageService.getRooms(nickname);
if(dtos.status === statusConstants.ERROR) {
return await Object.assign({
status: HttpStatus.INTERNAL_SERVER_ERROR,
payload: null,
message: "Error message: " + dtos.message
});
}
const responseRooms: Array<ResponseRoom> = [];
for(const dto of dtos.payload) {
responseRooms.push(Builder(ResponseRoom).roomId(dto.roomId)
.users(dto.users)
.messages(dto.messages)
.createdAt(dto.createdAt)
.build());
}
return await Object.assign({
status: HttpStatus.OK,
payload: responseRooms,
message: "Successfully get rooms data"
});
} catch(err) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "Error message: " + err
});
}
}
@Get(':keyword/keyword/rooms')
public async getRoomsByKeyword(@Param('keyword') keyword: string): Promise<any> {
try {
const dtos: any = await this.messageService.getRoomsByKeyword(keyword);
if(dtos.status === statusConstants.ERROR) {
return await Object.assign({
status: HttpStatus.INTERNAL_SERVER_ERROR,
payload: null,
message: "Error message: " + dtos.message
});
}
const responseRooms: Array<ResponseRoom> = [];
for(const dto of dtos.payload) {
responseRooms.push(Builder(ResponseRoom).roomId(dto.roomId)
.users(dto.users)
.messages(dto.messages)
.createdAt(dto.createdAt)
.build());
}
return await Object.assign({
status: HttpStatus.OK,
payload: responseRooms,
message: "Successfully get rooms data"
});
} catch(err) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "Error message: " + err
});
}
}
@Delete(':roomId/room')
public async deleteRoom(@Param('roomId') roomId: string): Promise<any> {
try {
const result: any = await this.messageService.deleteRoom(roomId);
if(result.status === statusConstants.ERROR) {
return await Object.assign({
status: HttpStatus.INTERNAL_SERVER_ERROR,
payload: null,
message: "Error message: " + result.message
});
}
return await Object.assign({
status: HttpStatus.NO_CONTENT,
payload: statusConstants.SUCCESS,
message: "Delete room"
});
} catch(err) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "Error message: " + err
});
}
}
@Get('room/check')
public async checkRoom(@Body() vo: RequestCheckRoom): Promise<any> {
try {
const result: any = await this.messageService.checkRoom(
vo.user_a,
vo.user_b
);
if(result.status === statusConstants.ERROR) {
return await Object.assign({
status: HttpStatus.INTERNAL_SERVER_ERROR,
payload: null,
message: "Error message: " + result.message
});
}
return await Object.assign({
status: HttpStatus.OK,
payload: result.payload,
message: result.message
});
} catch(err) {
return await Object.assign({
status: HttpStatus.BAD_REQUEST,
payload: null,
message: "Error message: " + err
});
}
}
}
1)initRoom:チャットルームを作成する方法.最初のメッセージを送信する場合、ユーザ間のチャットルームが存在しないため、この方法を使用してチャットルームを作成します.2)create:メッセージを格納する方法.requestMessage形式で入力したvoオブジェクトの値をMessageDto形式に変換し、MessageServiceレイヤに送信します.返される値はROOMDtoとして返されます.
3)getRoom:ユーザー間の部屋を返す方法.roomIdをパラメータとして渡し、メッセージ・サービス・レイヤに送信します.
4)getRooms:ニックネームとは、現在ログインしているユーザのニックネームを受信することによって、ユーザに関連するすべてのチャットルームをロードする方法である.
5)getRoomsByKeyword:keyword:すべてのニックネームが一致するチャットルームを読み込む方法.
6)eRoomの削除:部屋を削除する方法.パラメータroomIdをメッセージ・サービス・レイヤに送信し、roomを削除します.
7)checkRoom:requestCheckRoom voオブジェクトは、ユーザ間にチャットルームが存在するかどうかを確認するために使用される.
コントローラが作成され、次のライブラリがインストールされます.
npm install --save class-validator class-transformer builder-pattern uuid
vo、dto、インタフェースを作成します.import { IsString } from "class-validator";
export class RequestInitRoom {
@IsString()
user_a: string;
@IsString()
user_b: string;
}
import { IsString } from "class-validator";
export class RequestCheckRoom {
@IsString()
user_a: string;
@IsString()
user_b: string;
}
import { IsString } from "class-validator";
export class RequestMessage {
@IsString()
sender: string;
@IsString()
receiver: string;
@IsString()
content: string;
}
import { IsArray, IsDate, IsString } from "class-validator";
import { Message } from "src/interfaces/message.interface";
export class ResponseRoom {
@IsString()
roomId: string;
@IsArray()
users: string[];
@IsArray()
messages: Message[];
@IsDate()
createdAt: Date;
}
import { IsDate, IsString } from "class-validator";
export class MessageDto {
@IsString()
roomId: string;
@IsString()
messageId: string;
@IsString()
sender: string;
@IsString()
receiver: string;
@IsString()
content: string;
@IsDate()
createdAt: Date;
}
import { IsArray, IsDate, IsString } from "class-validator";
import { Message } from "src/interfaces/message.interface";
export class RoomDto {
@IsString()
roomId: string;
@IsArray()
users: string[];
@IsArray()
messages: Message[];
@IsDate()
createdAt: Date;
}
export class Message {
roomId: string;
sender: string;
receiver: string;
content: string;
createdAt: Date;
}
vo~インタフェースの作成が完了すると、コントローラには4つのサービスに関連する方法の4つのエラーしか残っていません.次に、メッセージサービスを作成します.#3 MessageService
mongodb接続のために、次のライブラリをインストールします.
npm install --save mongoose @nestjs/mongoose
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { Room, RoomSchema } from 'src/schema/room.schema';
import { MessageService } from './message.service';
@Module({
imports: [
MongooseModule.forFeature([{
name: Room.name,
schema: RoomSchema,
}]),
],
providers: [MessageService],
exports: [MessageService]
})
export class MessageModule {}
import { Module } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { MessageModule } from './message/message.module';
@Module({
imports: [
MongooseModule.forRoot("mongodb://localhost:27017/MESSAGESERVICE?readPreference=primary&appname=MongoDB%20Compass&directConnection=true&ssl=false"),
MessageModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose";
import { Message } from "src/interfaces/message.interface";
export type RoomDocument = Room & Document;
@Schema()
export class Room {
@Prop({ required: true })
roomId: string;
@Prop({ required: true })
users: string[];
@Prop({ required: true })
messages: Message[];
@Prop({ required: true })
createdAt: Date;
}
export const RoomSchema = SchemaFactory.createForClass(Room);
schemaが作成されている以上、サービスクラスの作成を開始しましょう.import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Builder } from 'builder-pattern';
import { Model } from 'mongoose';
import { statusConstants } from 'src/constants/status.constants';
import { MessageDto } from 'src/dto/message.dto';
import { RoomDto } from 'src/dto/room.dto';
import { Message } from 'src/interfaces/message.interface';
import { Room, RoomDocument } from 'src/schema/room.schema';
import { v4 as uuid } from 'uuid';
@Injectable()
export class MessageService {
constructor(@InjectModel(Room.name) private roomModel: Model<RoomDocument>) {}
public async initRoom(dto: RoomDto): Promise<any> {
try {
const entity: any = await new this.roomModel(Builder(Room).roomId(uuid())
.users([dto.users[0], dto.users[1]])
.messages([])
.createdAt(new Date())
.build())
.save();
if(!entity) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: database error"
});
}
return await Object.assign({
status: statusConstants.SUCCESS,
payload: Builder(RoomDto).roomId(entity.roomId)
.users(entity.users)
.messages(entity.messages)
.createdAt(entity.createdAt)
.build(),
message: "Successful transaction"
});
} catch(err) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: " + err
});
}
}
public async create(dto: MessageDto): Promise<any> {
try {
const result: any = await this.checkRoom(dto.sender, dto.receiver);
const roomId = result.payload;
await this.roomModel.updateOne(
{ roomId: roomId },
{ $push: {
messages: Builder(Message).sender(dto.sender)
.receiver(dto.receiver)
.content(dto.content)
.createdAt(new Date())
.build()
}}
)
const entity = await this.roomModel.findOne({ roomId: roomId });
if(!entity) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: database error"
});
}
return await Object.assign({
status: statusConstants.SUCCESS,
payload: Builder(RoomDto).roomId(entity.roomId)
.users(entity.users)
.messages(entity.messages)
.createdAt(entity.createdAt)
.build(),
message: "Successful transaction"
});
} catch(err) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: " + err
});
}
}
public async getRoom(roomId: string): Promise<any> {
try {
const entity: any = await this.roomModel.findOne({ roomId: roomId });
if(!entity) {
return await Object.assign({
status: statusConstants.SUCCESS,
payload: null,
message: "Not exist room"
});
}
return await Object.assign({
status: statusConstants.SUCCESS,
payload: Builder(Room).roomId(entity.roomId)
.users(entity.users)
.messages(entity.messages)
.createdAt(entity.createdAt)
.build(),
message: "Successful transaction"
});
} catch(err) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: " + err
});
}
}
public async getRooms(nickname: string): Promise<any> {
try {
const entities: any = await this.roomModel.find({
users: {
$in: [nickname]
}
});
if(!entities) {
return await Object.assign({
status: statusConstants.SUCCESS,
payload: null,
message: "Not exist rooms data"
});
}
const dtos: Array<RoomDto> = [];
for(const entity of entities) {
dtos.push(Builder(RoomDto).roomId(entity.roomId)
.users(entity.users)
.messages(entity.messages)
.createdAt(entity.createdAt)
.build());
}
return await Object.assign({
status: statusConstants.SUCCESS,
payload: dtos,
message: "Successful transaction"
})
} catch(err) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: " + err
});
}
}
public async getRoomsByKeyword(keyword: string): Promise<any> {
try {
const entities: any = await this.roomModel.find({
users: {
$in: [keyword]
}
});
if(!entities) {
return await Object.assign({
status: statusConstants.SUCCESS,
payload: null,
message: "Not exist rooms data"
});
}
const dtos: Array<RoomDto> = [];
for(const entity of entities) {
dtos.push(Builder(RoomDto).roomId(entity.roomId)
.users(entity.users)
.messages(entity.messages)
.createdAt(entity.createdAt)
.build());
}
return await Object.assign({
status: statusConstants.SUCCESS,
payload: dtos,
message: "Successful transaction"
})
} catch(err) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: " + err
});
}
}
public async deleteRoom(roomId: string) {
try {
const result: any = await this.roomModel.deleteOne({ roomId: roomId });
if(!result) {
return await Object.assign({
status: statusConstants.SUCCESS,
payload: null,
message: "Not exist room"
});
}
return await Object.assign({
status: statusConstants.SUCCESS,
payload: true,
message: "Successful delete room"
});
} catch(err) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: " + err
});
}
}
public async checkRoom(
user_a: string,
user_b: string
): Promise<any> {
try {
const check: any = await this.roomModel.findOne({
users: {
$all: [user_a, user_b]
}
});
if(!check) {
return await Object.assign({
status: statusConstants.SUCCESS,
payload: null,
message: "Not exist room"
});
}
return await Object.assign({
status: statusConstants.SUCCESS,
payload: check.roomId,
message: "Exist room"
});
} catch(err) {
return await Object.assign({
status: statusConstants.ERROR,
payload: null,
message: "message-service: " + err
});
}
}
}
方法を順番に見てみましょう.1)initRoom:ユーザ間チャットルームを作成する方法.dtoオブジェクトに渡されたユーザーをusersという属性値に入れることで、チャットしているユーザーを知ることができます.
2)create:チャットをチャットルームに入れる方法.まず,コントローラから送信されたdtoオブジェクトに基づいてcheckRoomメソッドを呼び出しroomIdを取得する.このroomId値に基づいてチャットルームをブラウズし、$pushオプションを使用して更新します.
3)getRoom:チャットルームカードを選択する際に要求する方法.roomId値に基づいてroomオブジェクトをインポートし、ユーザーに返します.
4)getRooms:$inオプションを使用して、チャットウィンドウのホームページにログインしているユーザーのニックネーム値を持つすべてのチャットルームのデータを取得する方法.
5)getRoomsByKeyword:keyword:これらのチャットルームに関するデータは、ユーザに存在する値と一致することによって取得される.
6)eRoomの削除:dtoオブジェクトで受信したroomId値を使用してチャットルームを削除します.
7)checkRoom:user a,user bはユーザに渡され,ユーザ配列に存在するすべての値と一致し,user a,user bが存在する場合にのみroomIdを返し,そうでなければnull値を返す.
メッセージ・サービス・クラスが完了しました.テストを続行してください.
#4テスト
以下の手順で行いましょう
i)checkRoomでユーザ間にチャットルームがあるか確認する
ii)null値を返す場合、initRoomメソッドを使用してチャットルームを作成する
iii)initRoom戻り値に従ってメッセージを送信する
2)メッセージ送信(ルーム作成後のメッセージ)
i)checkRoomでユーザ間にチャットルームがあるか確認する
ii)roomId値を返すとgetRoomメソッドでチャットルームを呼び出す
iii)メッセージ転送
3)チャットルームデータのインポート
i)getRoomsによるチャットルームのインポート
{
"status": 200,
"payload": [
{
"roomId": "5144d5d8-a1e5-493d-9f54-b9e5234e9177",
"users": [
"asd",
"biuea"
],
"messages": [
{
"sender": "asd",
"receiver": "biuea",
"content": "sad",
"createdAt": "2021-10-28T02:16:23.247Z"
},
{
"sender": "biuea",
"receiver": "asd",
"content": "test-001 message that is send by biuea to asd",
"createdAt": "2021-10-28T02:20:43.951Z"
}
],
"createdAt": "2021-10-28T02:15:31.704Z"
},
{
"roomId": "b01c9085-5a09-4d9f-aafb-8960ba730a31",
"users": [
"biuea",
"test"
],
"messages": [
{
"sender": "biuea",
"receiver": "test",
"content": "test-001 message that is send by biuea to test",
"createdAt": "2021-10-28T02:24:45.395Z"
}
],
"createdAt": "2021-10-28T02:24:12.067Z"
}
],
"message": "Successfully get rooms data"
}
ii)チャットルームで必要なroomId値を使用してgetRoomを呼び出す4)チャットルームの削除
i)getRoomsによるチャットルームのインポート
{
"status": 200,
"payload": [
{
"roomId": "5144d5d8-a1e5-493d-9f54-b9e5234e9177",
"users": [
"asd",
"biuea"
],
"messages": [
{
"sender": "asd",
"receiver": "biuea",
"content": "sad",
"createdAt": "2021-10-28T02:16:23.247Z"
},
{
"sender": "biuea",
"receiver": "asd",
"content": "test-001 message that is send by biuea to asd",
"createdAt": "2021-10-28T02:20:43.951Z"
}
],
"createdAt": "2021-10-28T02:15:31.704Z"
},
{
"roomId": "b01c9085-5a09-4d9f-aafb-8960ba730a31",
"users": [
"biuea",
"test"
],
"messages": [
{
"sender": "biuea",
"receiver": "test",
"content": "test-001 message that is send by biuea to test",
"createdAt": "2021-10-28T02:24:45.395Z"
}
],
"createdAt": "2021-10-28T02:24:12.067Z"
}
],
"message": "Successfully get rooms data"
}
ii)チャットルームのroomId値を使用してdeleteeRoomを呼び出す1)から4)のREST要求はすべて正常に処理できる.次の記事では、message-serviceのUIを作成します.
Reference
この問題について(LifeSports Application(ReactNative & Nest.js) - 25. message-service(1)), 我々は、より多くの情報をここで見つけました https://velog.io/@biuea/LifeSports-ApplicationReactNative-Nest.js-26.-message-serviceテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol