[Nest JS] GraphQL + Mongoose 서버 구축하기

Kylie·2022년 10월 25일
0
post-thumbnail
post-custom-banner

들어가기 전

요즘 NestJS를 공부하고 있다. NestJS로 이것저것 만들어보다 Graphql과 Mongoose를 사용하여 API를 만들어보고 싶었다. 공식 문서와 구글링한 정보를 조합하여 정보도 공유할 겸, 다음에 내가 활용하기 위해 기록하고자 한다.

NestJS 공식문서

https://docs.nestjs.com


NesetJs 프로젝트 생성하기

$ npm i -g @nestjs/cli
$ nest new {your project name}

💡 설치 중 'Which package manager would you to use?' 라는 문구가 뜨면 본인이 원하는 패키지 매니저를 선택하면 된다. 나는 npm을 사용할 것이라 npm으로 설치했다.


프로젝트가 생성되면 프로젝트를 열어서 다음 코드 실행

$ npm install
$ npm run start:dev

웹브라우에 다음과 같이 입력한다.

http://localhost:3000/

화면에 'Hello World!' 라고 나오면 NestJS 프로젝트 생성이 끝났다.


(+) PORT 번호 바꾸기
src/main.ts

import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  const PORT = 9000;
  await app.listen(PORT);
}

bootstrap();

GraphQL 연동하기 (Code First)

1. npm 설치

$ npm i @nestjs/graphql @nestjs/apollo graphql apollo-server-express

2. src/app.modules.ts

Graphql Module 입력하기

import { Module } from "@nestjs/common";
import { GraphQLModule } from "@nestjs/graphql";
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";


@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: "schema.gql"
    })],
  controllers: [],
  providers: []
})
export class AppModule {
}

3. 코드 작성

💡 모든 코드가 작성될때 까지 오류 코드 계속 뜸

src/schemas/user.schema.ts

  • 스키마는 마음대로 정의하면 된다.
import { Field, ID, ObjectType } from "@nestjs/graphql";

@ObjectType()
export class User {
  @Field(() => ID)
  uid: string;

  @Field(() => String)
  email: string;

  @Field(() => String)
  displayName: string;

  @Field(() => String, { nullable: true })
  photoURL: string;

  @Field(() => String, { nullable: true })
  intro: string;

  @Field(() => String, { nullable: true })
  date_crated: string;

  @Field(() => String, { nullable: true })
  access_token: string;

  password: string;
}

@ArgsType()
@InputType()
export class UserInputType {
  @IsEmail()
  @Field()
  email: string;

  @Length(2, 8)
  @Field()
  displayName: string;

  @Field({ nullable: true })
  photoURL: string;

  @Field({ nullable: true })
  intro: string;

  @Field()
  password1: string;

  @Field()
  password2: string;
}

src/schemas/user.resolver.ts

  • GraphQL이 제대로 작동하는지 보기 위해 하드코딩으로 데이터를 넣어보자
import { Query, Resolver, Args, Mutation } from "@nestjs/graphql";
import { User } from "../schemas/user.schema";
import { ApolloError } from "apollo-server-express";


@Resolver()
export class UsersResolver {
  constructor() {
  }

  @Query(() => [User])
  async findAll() {
    try {
      return [
        {uid:"1", email:"apple@test.com", displayName:"돌아온애쁠"},
        {uid:"2", email:"banan@test.com", displayName:"바나나반하나"}
      ]
    } catch (e) {
      throw new ApolloError(e);
    }

  }
}

src/users.module.ts

  • providers:[] 에 'UserResolver' 추가
import { Module } from "@nestjs/common";
import { UsersResolver } from "./users.resovler";

@Module({
  providers: [UsersResolver] //추가
})
export class UsersModule {
}

src/app.module.ts

  • app.modules.ts에 'UserModule' 추가
import { Module } from "@nestjs/common";
import { GraphQLModule } from "@nestjs/graphql";
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
import { UsersModule } from './users/users.module';


@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: "schema.gql"
    }),
    UsersModule  // 추가
    ],
  controllers: [],
  providers: []
})
export class AppModule {
}

4. GraphQL playground 확인

웹브러우저

http://localhost:{PORT}/graphql


Mongoose 연결하기

1. npm 설치

npm install --save mongoose

2. 코드 작성

database.providers.ts

import * as mongoose from 'mongoose';

const database_name = "nest"
export const databaseProviders = [
  {
    provide: 'DATABASE_CONNECTION',
    useFactory: (): Promise<typeof mongoose> =>
      mongoose.connect(`mongodb://localhost/${database_name}`),
  },
];

database.module.ts

import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';

@Module({
  providers: [...databaseProviders],
  exports: [...databaseProviders],
})
export class DatabaseModule {}

src/schemas/user.schema.ts

  • 기존의 user.schema.ts에 몽구스 스키마 추가
import { Field, ID, ObjectType, ArgsType, InputType } from "@nestjs/graphql";
import * as mongoose from "mongoose";
import { Document } from "mongoose";

// 추가
export const UserSchema = new mongoose.Schema({
  _id: { type: mongoose.Schema.Types.ObjectId, auto: true },
  displayName: String,
  email: String,
  photoURL: String,
  password: String,
  intro: String,
  date_crated: String
});

@ObjectType()
export class User extends Document {
  @Field(() => ID)
  uid: string;

  @Field(() => String)
  email: string;

  @Field(() => String)
  displayName: string;

  @Field(() => String, { nullable: true })
  photoURL: string;

  @Field(() => String, { nullable: true })
  intro: string;

  @Field(() => String, { nullable: true })
  date_crated: string;

  @Field(() => String, { nullable: true })
  access_token: string;

  password: string;
}

@ArgsType()
@InputType()
export class UserInputType {
  @Field()
  email: string;

  @Field()
  displayName: string;

  @Field({ nullable: true })
  photoURL: string;

  @Field({ nullable: true })
  intro: string;

  @Field()
  password: string;
}

src/users/users/providers.ts

import { Connection } from "mongoose";
import { UserSchema } from "../schemas/user.schema";

export const UsersProviders: any = [
  {
    provide: "USER_MODEL",
    useFactory: (connection: Connection) => connection.model("User", UserSchema,'users'),
    inject: ["DATABASE_CONNECTION"]
  }
];

src/users/users.service.ts

import { Injectable, Inject } from "@nestjs/common";
import { User, UserInputType } from "../schemas/user.schema";
import { Model } from "mongoose";
import { ApolloError } from "apollo-server-express";

@Injectable()
export class UsersService {
  constructor(
    @Inject("USER_MODEL")
    private readonly userModel: Model<User>
  ) {
  }

  async findAll(): Promise<User[]> {
    try {
      return this.userModel.find().exec();
    } catch (e) {
      throw new ApolloError(e);
    }
  }

  async createUser(user: UserInputType) {
    try {
      // CREATE DATA
      const data = {
        ...user,
        date_crated: new Date()
      };

      const result = await this.userModel.create(data);
      return {
        uid: result._id,
        ...data
      };

    } catch (e) {
      throw new ApolloError(e);
    }
  }
}

src/users/users.resovler.ts

  • 기존에 작성했던 user.resolver.ts 수정
import { Query, Resolver, Args, Mutation } from "@nestjs/graphql";
import { User, UserInputType } from "../schemas/user.schema";
import { UsersService } from "./users.service";
import { ApolloError } from "apollo-server-express";


@Resolver()
export class UsersResolver {
  constructor(private usersService: UsersService) {
  }

  @Query(() => [User])
  async findAll() {
    try {
      return await this.usersService.findAll();
    } catch (e) {
      throw new ApolloError(e);
    }
  }

  @Mutation(() => User)
  async createUser(@Args("input") user: UserInputType) {
    try {
      return await this.usersService.createUser(user);
    } catch (e) {
      throw new ApolloError(e);
    }
  }
}

src/users/users.module.ts

import { Module } from "@nestjs/common";
import { UsersResolver } from "./users.resovler";
import {UsersService} from "./users.service";
import {UsersProviders} from "./users.providers";
import {DatabaseModule} from "../database.module";

@Module({
  imports:[DatabaseModule],
  providers: [UsersResolver,UsersService, ...UsersProviders],
  exports: [UsersService]
})
export class UsersModule {
}

src/app.module.ts

import { Module } from "@nestjs/common";
import { GraphQLModule } from "@nestjs/graphql";
import { ApolloDriver, ApolloDriverConfig } from "@nestjs/apollo";
import { UsersModule } from "./users/users.module";


@Module({
  imports: [
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: "schema.gql"
    }),
    UsersModule],
  controllers: [],
  providers: []
})
export class AppModule {
}

3. GraphQL playgroud 확인


4. MongoDB 확인

'nest' 데이터베이스에 user collection에 방금 작성한 유저 정보가 제대로 입력된 것을 볼 수 있다.


전체코드 보기 : github

profile
올해보단 낫겠지....
post-custom-banner

0개의 댓글