Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

미래학자

우버 클론 코딩 (nomad coders) #2 본문

nomad corders

우버 클론 코딩 (nomad coders) #2

미래학자 2019. 4. 8. 18:44

노마드코더 - 우버 클론 코딩

#1.8 Graphql To Typescript

  • src/hello/sayHello/sayHello.graphql 파일을 다음처럼 수정한 후 서버를 재시작 해보자.

      type Greeting {
        text: String!
        error: Boolean!
      }
    
      type Query {
        sayHello: Greeting!
      }

sayHello 쿼리의 타입을 Greeting으로 변경을 했다.

  • src/api/hello/sayHello/sayHello.resolvers.ts

      const resolvers = {
        Query: {
          sayHello: () => "Hey Hello how are ya"
        }
      }
    
      export default resolvers;

그런데 resolver에서는 여전히 string을 리턴한다. 정의한 스키마와 실제 코드 사이에 다른 타입을 처리하도록 되어 있지만, 타입스크립트에서 이를 알아채지 못한다. 물론 http://localhost:4000/playground 에 들어가서 sayHello를 호출 했을 때 에러는 난다. 어쨋든 타입스크립트에서 이런 타입문제를 알려줘야 한다.

아래의 모듈들이 이런 타입체킹을 도와줄 것이다.

$ yarn add graphql-to-typescript gql-merge --dev

이렇게 한 후 아직 코드는 변경하지 않고 스크립트를 추가 해야 한다.

graphql-to-typescript 모듈은 쿼리을 정의한 graphql 파일을 typescript로 변경해주는데, 이 모듈을 실행하기 전에 여러 파일로 정의된 graphql을 하나의 파일로 합쳐주는 것이 필요하다 그 역할을 하는게 gql-merge다.

  • package.json

      {
        ...,
        "dependencies": {
          ...
        },
        "devDependencies": {
          ...
        },
        "scripts": {
          "dev": "cd src && nodemon --exec ts-node index.ts -e ts,graphql",
          "pretypes": "gql-merge --out-file ./src/schema.graphql ./src/api/**/*.graphql",
          "types": "graphql-to-typescript ./src/schema.graphql ./src/types/graph.d.ts"
        }
      }

    pretypes 명령어는 gql-merge를 이용하여 ./src/schema.graphql 에 하나의 파일로 합친다.

    types 명령어는 graphql-to-thypescript를 이용하여 ./src/schema.graphql에 graphql 스키마 정의를 ./src/types/graph.d.ts 타입스크립트 파일로 만든다. (d.ts 는 definition.typescript로 vscode가 알아서 타입 정의 파일인것을 인지한다.)

이제 타입 정의 파일을 생성해보자. 아마 babel-runtime 모듈이 없다고 뜰 건데 설치해주자.

그리고 타입 정의 파일이 생성될 디렉토리도 먼저 만들어주자.

$ yarn add babel-runtime --dev
$ mkdir src/types    # src/types 빈 디렉토리 생성
$ yarn types

명령어가 제대로 실행되었다면,

src/schema.graphql, src/types/graph.d.ts 파일이 생성된 것을 볼 수 있다.

이제 우리가 할 것은 d.ts을 통해 타입스크립트에 타입을 명시해주는 것이다.

  • src/api/hello/sayHello/sayHello.resolvers.ts

      import { Greeting } from "src/types/graph";
    
      const resolvers = {
        Query: {
          sayHello: () : Greeting => {
            return {
              error: true,
              text: "good!"
            }
          }
        }
      }
    
      export default resolvers;

    특히 위 코드를 입력할 때 import를 하지 않고 타입만 써주면 auto import 해준다.!

서버 재시작 후 http://localhost:4000/playground 에 가서 다음의 쿼리를 입력하면 우리가 정의한 결과가 제대로 나오는 것을 확인 할 수 있다.

query {
    sayHello {
    error
    text
  }
}

#1.9 Typechecking Graphql Arguments

1.8 절에서 설정한 것들이 얼마나 멋진일인지를 확인할 수 있다.

  • src/api/hello/sayHello/sayHello.graphql sayHello 쿼리에 인자를 추가하자

    type Greeting {
      text: String!
      error: Boolean!
    }
    
    type Query {
      sayHello(name: String!): Greeting!
    }

src/api/hello/sayHello/sayHello.graphql sayHello 쿼리에 인자를 추가하자

그리고 타입을 생성하는 스크립트를 돌리자 yarn types

그러면 graph.d.ts 파일에 SayHelloQueryArgs 인터페이스가 정의되어 있을 것이다. 진짜 멋지다.

바꾼김에 조금만 더 작업을 해보자.

  • src/api/hello/sayHello/sayHello.graphql 의 파일을

      type SayHelloResponse {
        text: String!
        error: Boolean!
      }
    
      type Query {
        sayHello(name: String!): SayHelloResponse!
      }

    .graphql 파일을 변경하면 yarn types를 꼭 해주자.

  • src/api/hell/sayHello/sayHello.resolvers.ts

      import { SayHelloQueryArgs, SayHelloResponse } from "src/types/graph";
    
      // 모든 resolver는  parent, args, context를 전달받게 되어 있다.
      // 우리가 필요한 것은 args뿐이므로 parent는 _로 적어준다.(_는 사용하지 않음으로 암묵적으로 의미한다.)
      const resolvers = {
        Query: {
          sayHello: (_, args: SayHelloQueryArgs) : SayHelloResponse => {
            return {
              error: true,
              text: `hello ${args.name}`
            }
          }
        }
      }
    
      export default resolvers;
  • http://localhost:4000/playground 에서 쿼리를 날려보자.

      query {
          sayHello(name: "tamm") {
          error
          text
        }
      }
    
      # 응답
      {
        "data": {
          "sayHello": {
            "error": true,
            "text": "hello tamm"
          }
        }
      }

이건 진짜 멋진 같다.

#1.10 Configuring TypeORM

이번에는 데이터 베이스를 연결할 껀데, typeORM을 사용할 거다. typeORM은 타입스크립트를 지원하기 떄문에 딱 어울린다.

https://github.com/typeorm/typeorm

  • 우선 typeorm을 설치하자

      $ yarn add typeorm

app.ts 에서 데이터 베이스를 연결한 후 app을 실행하도록 해야한다.

src/entities 디렉토리를 생성한다. 이 디렉토리에는 데이터 베이스 스키마 정의가 들어간다. 지금은 빈 디렉토리다.

  • src/ormConfig.ts 파일에는 데이터 베이스 연결 정보를 셋팅한다.

      import { ConnectionOptions } from 'typeorm'
    
      const ConnectionOptions: ConnectionOptions = {
        type: "postgres",
        database: "nuber",
        synchronize: true,
        logging: true,
        entities: [
          "entities/**/*.*"
        ],
        host: process.env.DB_ENDPOINT || "localhost",
        port: 5432,
        username: process.env.DB_USERNAME || "tamm",
        password: process.env.DB_PASSWORD || ""
      };
    
      export default ConnectionOptions;

이 프로젝트에서는 postgresql 를 사용한다.

postgresql 은 각자 환경에 맞게 설치하자. 그리고 실행하자.

  • 맥이라면

      $ brew install postgresql
      $ postres -D /usr/local/var/postres

postgresql을 사용하기에 앞서 나는 위에서 tamm이라는 유저가 nuber라는 데이터 베이스를 사용하길 원한다. tamm이라는 유저를 생성하고, tamm 유저가 사용할 수 있는 nuber라는 데이터 베이스를 생성할 거다. 다음과 같이 뜨면 성공

$ createuser tamm
$ createdb -O tamm nuber     # -O 옵션은 권한을 가질 대상이다.
$ psql -U tamm number

psql (11.2) # 필자 기준
Type "help" for help.

number=> []

데이터 베이스 설정을 마쳤고, 이제 앱이 실행될 때 데이터 베이스를 연결하도록 src/index.ts를 수정하자.

  • src/index.ts

      import { Options } from 'graphql-yoga';
      import { createConnection } from 'typeorm';
      import app from './app';
      import ConnectionOptions from './ormConfig';
    
      ...
    
      const handleAppStat = () => console.log(`Listening on port ${PORT}`)
      createConnection(ConnectionOptions).then(_ => {
        app.start(appOptions, handleAppStat);  
      });

자, 모든 설정을 맞췄다. typeorm에서 postgresql을 사용하려면 pg라는 모듈을 의존하는 것 같다. pg 모듈을 추가해주자. pg 모듈의 설명은 참고로 다음과 같다

pg : Non-blocking PostgreSQL client for Node.js. Pure JavaScript and optional native libpq bindings.

$ yarn add pg --dev
$ yarn dev

[nodemon] 1.18.10
[nodemon] to restart at any time, enter `rs`
[nodemon] watching: *.*
[nodemon] starting `ts-node index.ts`
query: START TRANSACTION
query: COMMIT
Listening on port 4000

postgresql이 연결되어 TRANSACTION을 시작한다. 이런 로그가 나오는 이유는 src/ormConfig.ts에서 logging: true 옵션을 주었기 때문이다. src/entities 디렉토리에 파일이 더 추가되면 이런 로그가 많아진다고 한다.

#1.11 Creating a Virtual Environment on NodeJS

이번에는 dotenv 모듈로 위에서 사용한 process.env.DB_ENDPOINT || "localhost"같은 표현을 없앨 것이다.

우선 dotenv 모듈을 설치하자. 굉장히 굉장히 유용하면서도 많이 사용되는 모듈이다.

$ yarn add dotenv

dotenv모듈은 src/.env 파일을 입력을 받는데, 만들어서 값을 입력하자

  • src/.env

      DB_ENDPOINT=localhosta
      DB_USERNAME=tamm
      DB_PASSWORD=
  • src/ormConfig.ts 깔끔하게 process.env에서 가져오도록 한다.

      import { ConnectionOptions } from 'typeorm'
    
      const ConnectionOptions: ConnectionOptions = {
        type: "postgres",
        database: "nuber",
        synchronize: true,
        logging: true,
        entities: [
          "entities/**/*.*"
        ],
        host: process.env.DB_ENDPOINT,
        port: 5432,
        username: process.env.DB_USERNAME,
        password: process.env.DB_PASSWORD
      };
    
      export default ConnectionOptions;

그런데 이렇게 쓰려면 dotenv 프로젝트가 실행될 때 셋팅을 하도록 해야 하는데

  • index.ts 에서 앱 시작할 때 설정 파일을 읽도록 하자.

      import dotenv from 'dotenv';
      dotenv.config();
      import { Options } from 'graphql-yoga';
      import { createConnection } from 'typeorm';
      ...

됐다. 이제 정상적으로 실행될 것이다.

src/.env 파일의 DB_ENDPOINT=localhosta 로 바꾸고 다시 실행하면 에러가 발생해야 한다.

  • index.ts 에서 데이터 베이스를 연결할 때 실패에 대한 catch를 추가하자.

      import dotenv from 'dotenv';
      dotenv.config();
      ...
    
      createConnection(ConnectionOptions).then(_ => {
        app.start(appOptions, handleAppStat);  
      }).catch(error => console.log(error))

단순히 출력을 하도록 했지만 어쨋든 더 자세한 에러 로그를 얻게 됐다. 이제

src/.env 파일의 DB_ENDPOINT=localhost 로 원상 복구하자.

지금까지 dotenv로 환경설정을 넣는 것을 했다.

Comments