포스트

Node.js로 gRPC 이용

gRPC를 알아봤으니 이를 js로 구현하는 방법을 알아보자. Typescript 기반이다. gRPC란?

Requirements

사용하는 라이브러리는 @grpc/grpc-js와 ts-proto를 사용한다. ts-proto는 아래에서 생성할 인터페이스를 Typescript에서 읽을 수 있는 타입으로 생성해 주는 역할을 해 준다.

1
2
  npm install @grpc/grpc-js
  npm install -D ts-proto

규약 (Contract)

서버와 클라이언트 간 통신을 위한 규약을 작성한다. 확장명은 “.proto” 파일에 저장하면 된다.

VS Code의 경우 vscode-proto3 익스텐션을 사용하면 유용하다.

코드

gRPC를 위한 언어로 작성해야 한다. 처음에는 구문과 패키지 이름을 제공해야 한다.

1
2
  syntax = "proto3";
  package authPackage;

패키지 이름은 원하는 대로 지정할 수 있다.

메세지 정의 (인터페이스 정의)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
enum LoginCode {
    SUCCESS = 0;
    FAIL = 1;
};

message LoginResult {
    LoginCode loginCode = 1;
    optional string token = 2;
}

message LoginRequest {
    string username = 1;
    string password = 2;
}

메시지의 각 필드에는 인코딩 중 사용되는 식별자인 고유 번호가 있다.

메세지 사용할 서비스 정의

위에서 정의한 인터페이스를 사용할 서비스를 정의한다.

1
2
3
service AuthService {
    rpc login(LoginRequest) returns (LoginResult);
}

Typescript에서 사용할 타입 생성

ts-proto의 protoc 명령을 사용한다.

1
protoc - plugin=protoc-gen-ts_proto=.\node_modules\.bin\protoc-gen-ts_proto.cmd - ts_proto_out=. ./protos/auth.proto - ts_proto_opt=outputServices=grpc-js,env=node,esModuleInterop=true

위 명령어를 사용하면 메세지 및 서비스 코드가 포함된 auth.ts 파일이 생성된다.

서버

이제 이를 사용하기 위한 서버 정의 코드를 짠다.

1
2
3
4
5
6
7
8
import { Server, ServerCredentials } from '@grpc/grpc-js';
import { AuthServiceService } from './protos/auth';

const server = new Server();
server.addService(AuthServiceService, { login: login }); // login 은 이후에 정의할 예정입니다.
server.bindAsync('localhost:8080', ServerCredentials.createInsecure(), () => {
  server.start();
});

로그인 기능 구현

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
import { LoginCode, LoginRequest, LoginResult } from './protos/auth';

const users = [{ id: 0, username: 'admin', password: 'qwerty' }];

const login = (
  call: ServerUnaryCall<LoginRequest, LoginResult>,
  callback: sendUnaryData<LoginResult>
) => {
  const user = users.find(
    (user) =>
      user.username === call.request.username &&
      user.password === call.request.password
  );

  if (user) {
    const result: LoginResult = {
      loginCode: LoginCode.SUCCESS,
      token: 'RandomSecretToken',
    };
    callback(null, result);
  } else {
    const result: LoginResult = {
      loginCode: LoginCode.FAIL,
    };
    callback(null, result);
  }
};

클라이언트

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { ServiceError, credentials } from '@grpc/grpc-js';
import { AuthServiceClient, LoginRequest, LoginResult } from './protos/auth';

const loginRequest: LoginRequest = {
  username: 'admin',
  password: 'qwerty',
};

const client = new AuthServiceClient(
  'localhost:8080',
  credentials.createInsecure()
);
client.login(
  loginRequest,
  (err: ServiceError | null, response: LoginResult) => {
    console.log(JSON.stringify(response));
  }
);

참고 링크

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.