NestJS userProfile Mutation
userProfile DTO import { ArgsType, Field, ObjectType } from '@nestjs/graphql';
import { CoreOutput } from 'src/common/dtos/output.dto';
import { User } from '../entities/user.entity';
@ArgsType()
export class UserProfileInput {
@Field((type) => Number)
userId: number;
}
@ObjectType()
export class UserPofileOutput extends CoreOutput {
@Field((type) => User, { nullable: true })
user?: User;
}
CoreOutput
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class CoreOutput {
@Field((type) => String, { nullable: true })
error?: string;
@Field((type) => Boolean)
ok: boolean;
}
users.resolver.ts
import { UseGuards } from '@nestjs/common';
import { Resolver, Query, Mutation, Args, Context } from '@nestjs/graphql';
import { AuthUser } from 'src/auth/auth-user.decorator';
import { AuthGuard } from 'src/auth/auth.guard';
import {
CreateAccountInput,
CreateAccountOutput,
} from './dtos/create-account.dto';
import { LoginInput, LoginOutput } from './dtos/login.dto';
import { UserPofileOutput, UserProfileInput } from './dtos/user-profile.dto';
import { User } from './entities/user.entity';
import { UsersService } from './users.service';
@Resolver((of) => User)
export class UsesrResolver {
constructor(private readonly usesrService: UsersService) {}
...
@UseGuards(AuthGuard)
@Query((returns) => UserPofileOutput)
async userProfile(
@Args() userProfileInput: UserProfileInput,
): Promise<UserPofileOutput> {
try {
const user = await this.usesrService.findById(userProfileInput.userId);
if (!user) {
throw Error();
}
return {
ok: true,
user,
};
} catch (error) {
return {
error: 'User Not Found',
ok: false,
};
}
}
}
まずuserServiceのfindByIdメソッドでユーザーを検索し、そうでない場合はthrow Error()でcatch文に接続します.ユーザーが存在する場合は、そのユーザーを返します.
EditPorfile
EditProfile DTO
EditProfileInputでは、PartialTypeを使用してPickTypeのemail、passwordを選択し、オプションに設定します.import { InputType, ObjectType, PartialType, PickType } from '@nestjs/graphql';
import { CoreOutput } from 'src/common/dtos/output.dto';
import { User } from '../entities/user.entity';
@InputType()
export class EditProfileInput extends PartialType(
PickType(User, ['email', 'password']),
) {}
@ObjectType()
export class EditProfileOutput extends CoreOutput {}
users.service.ts import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateAccountInput } from './dtos/create-account.dto';
import { LoginInput } from './dtos/login.dto';
import { User } from './entities/user.entity';
import { ConfigService } from '@nestjs/config';
import { JwtService } from 'src/jwt/jwt.service';
import { EditProfileInput } from './dtos/edit.profile';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly users: Repository<User>,
private readonly jwtService: JwtService,
) {}
...
async editProfile(userId: number, editProfileInput: EditProfileInput) {
this.users.update(userId, { ...editProfileInput });
}
}
editProfile関数を作成します.updateはqueryを迅速かつ効率的に更新できます.
users.resolver.ts import { UseGuards } from '@nestjs/common';
import { Resolver, Query, Mutation, Args, Context } from '@nestjs/graphql';
import { AuthUser } from 'src/auth/auth-user.decorator';
import { AuthGuard } from 'src/auth/auth.guard';
import {
CreateAccountInput,
CreateAccountOutput,
} from './dtos/create-account.dto';
import { EditProfileInput, EditProfileOutput } from './dtos/edit.profile';
import { LoginInput, LoginOutput } from './dtos/login.dto';
import { UserPofileOutput, UserProfileInput } from './dtos/user-profile.dto';
import { User } from './entities/user.entity';
import { UsersService } from './users.service';
@Resolver((of) => User)
export class UsesrResolver {
constructor(private readonly usesrService: UsersService) {}
...
@UseGuards(AuthGuard)
@Mutation((returns) => EditProfileOutput)
async editProfile(
@AuthUser() authUser: User,
@Args('input') editProfileInput: EditProfileInput,
): Promise<EditProfileOutput> {
try {
await this.usesrService.editProfile(authUser.id, editProfileInput);
return {
ok: true,
};
} catch (error) {
return {
ok: false,
error,
};
}
}
}
AuthUserでログインしたユーザーをAuthUserに入れます.
ただし、ここでの問題は、ログインしたユーザがpasswordを変更した場合、パスワードはハッシュされずにデータベースに保存されます.
なので、User Entityに対して以下の操作をすれば良いのですimport {
Field,
InputType,
ObjectType,
registerEnumType,
} from '@nestjs/graphql';
import { CoreEntity } from 'src/common/entities/core.entity';
import * as bcrypt from 'bcrypt';
import { BeforeInsert, BeforeUpdate, Column, Entity } from 'typeorm';
import { InternalServerErrorException } from '@nestjs/common';
import { IsEmail, IsEnum } from 'class-validator';
enum UserRole {
Client,
Owner,
Delivery,
}
registerEnumType(UserRole, { name: 'UserRole' });
@InputType({ isAbstract: true })
@ObjectType()
@Entity()
export class User extends CoreEntity {
@Column()
@Field((type) => String)
@IsEmail()
email: string;
@Column()
@Field((type) => String)
password: string;
@Column({ type: 'enum', enum: UserRole })
@Field((type) => UserRole)
@IsEnum(UserRole)
role: UserRole;
@BeforeInsert()
@BeforeUpdate()
async hashpassword(): Promise<void> {
try {
this.password = await bcrypt.hash(this.password, 10);
} catch (error) {
console.log(error);
throw new InternalServerErrorException();
}
}
async checkPassword(aPassword: string): Promise<boolean> {
try {
const ok = await bcrypt.compare(aPassword, this.password);
return ok;
} catch (error) {
console.log(error);
throw new InternalServerErrorException();
}
}
}
@BeforeUpdate()を使用すると、更新前にパスワードを解放できます.
しかし実際にpasswordを編集するとhashはありません.どうしてこんなことになったの?それはupdate()メソッドのためです.updateメソッドでは、エンティティが存在するかどうかはチェックされません.これはentityを直接更新していないことを意味します.私たちはdbにqueryを送信するだけです.
だからupdateメソッドではなくsaveメソッドを使用します.
エンティティが存在しない場合はsaveメソッドがエンティティを作成、挿入し、エンティティがすでに存在する場合はエンティティを更新します.
Bug fix
users.service.tsimport { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateAccountInput } from './dtos/create-account.dto';
import { LoginInput } from './dtos/login.dto';
import { User } from './entities/user.entity';
import { ConfigService } from '@nestjs/config';
import { JwtService } from 'src/jwt/jwt.service';
import { EditProfileInput } from './dtos/edit.profile';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly users: Repository<User>,
private readonly jwtService: JwtService,
) {}
...
async editProfile(
userId: number,
{ email, password }: EditProfileInput,
): Promise<User> {
const user = await this.users.findOne(userId);
if (email) {
user.email = email;
}
if (password) {
user.password = password;
}
return this.users.save(user);
}
}
userIdを使用してuserを検索し、ユーザーが変更する値をinputとして受け入れ、置換および保存します.
Reference
この問題について(NestJS userProfile Mutation), 我々は、より多くの情報をここで見つけました
https://velog.io/@abc5259/NestJS-userProfile-Mutation
テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol
import { ArgsType, Field, ObjectType } from '@nestjs/graphql';
import { CoreOutput } from 'src/common/dtos/output.dto';
import { User } from '../entities/user.entity';
@ArgsType()
export class UserProfileInput {
@Field((type) => Number)
userId: number;
}
@ObjectType()
export class UserPofileOutput extends CoreOutput {
@Field((type) => User, { nullable: true })
user?: User;
}
import { Field, ObjectType } from '@nestjs/graphql';
@ObjectType()
export class CoreOutput {
@Field((type) => String, { nullable: true })
error?: string;
@Field((type) => Boolean)
ok: boolean;
}
import { UseGuards } from '@nestjs/common';
import { Resolver, Query, Mutation, Args, Context } from '@nestjs/graphql';
import { AuthUser } from 'src/auth/auth-user.decorator';
import { AuthGuard } from 'src/auth/auth.guard';
import {
CreateAccountInput,
CreateAccountOutput,
} from './dtos/create-account.dto';
import { LoginInput, LoginOutput } from './dtos/login.dto';
import { UserPofileOutput, UserProfileInput } from './dtos/user-profile.dto';
import { User } from './entities/user.entity';
import { UsersService } from './users.service';
@Resolver((of) => User)
export class UsesrResolver {
constructor(private readonly usesrService: UsersService) {}
...
@UseGuards(AuthGuard)
@Query((returns) => UserPofileOutput)
async userProfile(
@Args() userProfileInput: UserProfileInput,
): Promise<UserPofileOutput> {
try {
const user = await this.usesrService.findById(userProfileInput.userId);
if (!user) {
throw Error();
}
return {
ok: true,
user,
};
} catch (error) {
return {
error: 'User Not Found',
ok: false,
};
}
}
}
EditProfile DTO
EditProfileInputでは、PartialTypeを使用してPickTypeのemail、passwordを選択し、オプションに設定します.
import { InputType, ObjectType, PartialType, PickType } from '@nestjs/graphql';
import { CoreOutput } from 'src/common/dtos/output.dto';
import { User } from '../entities/user.entity';
@InputType()
export class EditProfileInput extends PartialType(
PickType(User, ['email', 'password']),
) {}
@ObjectType()
export class EditProfileOutput extends CoreOutput {}
users.service.ts import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateAccountInput } from './dtos/create-account.dto';
import { LoginInput } from './dtos/login.dto';
import { User } from './entities/user.entity';
import { ConfigService } from '@nestjs/config';
import { JwtService } from 'src/jwt/jwt.service';
import { EditProfileInput } from './dtos/edit.profile';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly users: Repository<User>,
private readonly jwtService: JwtService,
) {}
...
async editProfile(userId: number, editProfileInput: EditProfileInput) {
this.users.update(userId, { ...editProfileInput });
}
}
editProfile関数を作成します.updateはqueryを迅速かつ効率的に更新できます.users.resolver.ts
import { UseGuards } from '@nestjs/common';
import { Resolver, Query, Mutation, Args, Context } from '@nestjs/graphql';
import { AuthUser } from 'src/auth/auth-user.decorator';
import { AuthGuard } from 'src/auth/auth.guard';
import {
CreateAccountInput,
CreateAccountOutput,
} from './dtos/create-account.dto';
import { EditProfileInput, EditProfileOutput } from './dtos/edit.profile';
import { LoginInput, LoginOutput } from './dtos/login.dto';
import { UserPofileOutput, UserProfileInput } from './dtos/user-profile.dto';
import { User } from './entities/user.entity';
import { UsersService } from './users.service';
@Resolver((of) => User)
export class UsesrResolver {
constructor(private readonly usesrService: UsersService) {}
...
@UseGuards(AuthGuard)
@Mutation((returns) => EditProfileOutput)
async editProfile(
@AuthUser() authUser: User,
@Args('input') editProfileInput: EditProfileInput,
): Promise<EditProfileOutput> {
try {
await this.usesrService.editProfile(authUser.id, editProfileInput);
return {
ok: true,
};
} catch (error) {
return {
ok: false,
error,
};
}
}
}
AuthUserでログインしたユーザーをAuthUserに入れます.ただし、ここでの問題は、ログインしたユーザがpasswordを変更した場合、パスワードはハッシュされずにデータベースに保存されます.
なので、User Entityに対して以下の操作をすれば良いのです
import {
Field,
InputType,
ObjectType,
registerEnumType,
} from '@nestjs/graphql';
import { CoreEntity } from 'src/common/entities/core.entity';
import * as bcrypt from 'bcrypt';
import { BeforeInsert, BeforeUpdate, Column, Entity } from 'typeorm';
import { InternalServerErrorException } from '@nestjs/common';
import { IsEmail, IsEnum } from 'class-validator';
enum UserRole {
Client,
Owner,
Delivery,
}
registerEnumType(UserRole, { name: 'UserRole' });
@InputType({ isAbstract: true })
@ObjectType()
@Entity()
export class User extends CoreEntity {
@Column()
@Field((type) => String)
@IsEmail()
email: string;
@Column()
@Field((type) => String)
password: string;
@Column({ type: 'enum', enum: UserRole })
@Field((type) => UserRole)
@IsEnum(UserRole)
role: UserRole;
@BeforeInsert()
@BeforeUpdate()
async hashpassword(): Promise<void> {
try {
this.password = await bcrypt.hash(this.password, 10);
} catch (error) {
console.log(error);
throw new InternalServerErrorException();
}
}
async checkPassword(aPassword: string): Promise<boolean> {
try {
const ok = await bcrypt.compare(aPassword, this.password);
return ok;
} catch (error) {
console.log(error);
throw new InternalServerErrorException();
}
}
}
@BeforeUpdate()を使用すると、更新前にパスワードを解放できます.しかし実際にpasswordを編集するとhashはありません.どうしてこんなことになったの?それはupdate()メソッドのためです.updateメソッドでは、エンティティが存在するかどうかはチェックされません.これはentityを直接更新していないことを意味します.私たちはdbにqueryを送信するだけです.
だからupdateメソッドではなくsaveメソッドを使用します.
エンティティが存在しない場合はsaveメソッドがエンティティを作成、挿入し、エンティティがすでに存在する場合はエンティティを更新します.
Bug fix
users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateAccountInput } from './dtos/create-account.dto';
import { LoginInput } from './dtos/login.dto';
import { User } from './entities/user.entity';
import { ConfigService } from '@nestjs/config';
import { JwtService } from 'src/jwt/jwt.service';
import { EditProfileInput } from './dtos/edit.profile';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private readonly users: Repository<User>,
private readonly jwtService: JwtService,
) {}
...
async editProfile(
userId: number,
{ email, password }: EditProfileInput,
): Promise<User> {
const user = await this.users.findOne(userId);
if (email) {
user.email = email;
}
if (password) {
user.password = password;
}
return this.users.save(user);
}
}
userIdを使用してuserを検索し、ユーザーが変更する値をinputとして受け入れ、置換および保存します.Reference
この問題について(NestJS userProfile Mutation), 我々は、より多くの情報をここで見つけました https://velog.io/@abc5259/NestJS-userProfile-Mutationテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol