콘텐츠로 이동

Grpc web

grpc-web 이란

grpc-web은 웹 브라우저에서 직접 API를 호출하는 방식입니다. 이것이 REST 방식과 다른 점은 URL을 사용하지 않고, 미리 컴파일된 grpc 스텁을 사용해서 호출을 하는 것이 다릅니다.

grpc-web을 사용하기 위해서는 반드시 envoy를 경유해야만 합니다. grpc 전용 HTTP 요청을 grpc 호출로 변경해 주는 작업을 envoy에서 수행합니다. 반대로 grpc 응답을 HTTP 응답으로 변환하기도 합니다.

통상적으로 grpc가 사용하는 프로토콜 버퍼의 메지지 규격으로 전송하고, 응답도 프로토콜 버퍼 형식으로 받습니다. 그래서 주고받은 메시지 규격을 확인하기는 쉽지 않습니다.

하지만, 개발을 수행하는 관점에서는 매우 용이한 방식입니다.

envoy 설정

기본적으로 바른의 도커 버전을 사용하시면, grpc-web을 사용할 수 있습니다. 별도의 환경에서 grpc-web을 사용하시고 싶으면, 기술 지원을 받기를 권장합니다.

docker cp bareun:/bareun/envoy.yaml my-envoy.yaml

위 명령어로 bareun 도커에 포함된 envoy 설정을 참고하여 설정을 변경할 수 있습니다.

컴파일된 JS 라이브러리

바른의 배포판에는 미리 컴파일된 grpc-web 용 자바스크립트 라이브러리가 포함되어 있습니다.

ROOT/shared/grpc-web 폴더에 내용이 들어 있습니다.

./google
./google/api
./google/api/annotations_pb.js
./google/api/http_pb.js
./bareun
./bareun/custom_dict_grpc_web_pb.js
./bareun/language_service_pb.js
./bareun/dict_common_pb.js
./bareun/custom_dict_pb.js
./bareun/language_service_grpc_web_pb.js

코드 샘플

위 라이브러리를 다양한 웹 개발 환경에 포함하여 개발을 할 수 있습니다.

아래의 코드는 svelte 환경에서 grpc-web을 통해서 API를 호출한 예제입니다.

// 자신의 호스트로 바꾸세요.
let serverHost = "your.domain.com:5757"
// 자신이 키로 바꾸세요.
let apiKEY = "koba-ABCDEFG-1234567-LMNOPQR-7654321"

async function requestByGrpcWeb(textText, customDict) {
    let req = new proto.bareun.AnalyzeSyntaxRequest();
    let doc = new proto.bareun.Document();
    doc.setLanguage("ko_KR");
    doc.setContent(testText);
    req.setDocument(doc);
    req.setCustomDomain(customDict);
    req.setAutoSpacing(true);
    req.setAutoJointing(true);
    req.setAutoSplitSentence(true);
    let client = new LanguageServiceClient(serverHost);

    // SET META          
    const md = new grpc.Metadata();
    md.set('api-key', apiKey);

    client.analyzeSyntax(req, md, function (err, res) {
        if (err) console.log("analyze systax error", err);
        if (res) {
            resultSentences = [];
            for (let sent of res.getSentencesList()) {
                let s = {};
                s.text = sent.getText().toObject();
                s.tokens = [];
                s.refined = sent.getRefined();
                for (let tok of sent.getTokensList()) {
                    let t = {};
                    t.text = tok.getText().toObject();
                    t.tagged = tok.getTagged();
                    t.modified = tok.getModified();
                    t.lemma = tok.getLemma();
                    t.morphemes = [];
                    for (let morph of tok.getMorphemesList()) {
                        let m = {};
                        m.text = morph.getText().toObject();
                        m.tag = getEnumKey(
                            proto.bareun.Morpheme.Tag, morph.getTag());
                        m.probability = morph.getProbability();
                        m.outOfVocab = getEnumKey(
                            proto.bareun.Morpheme.OutOfVocab,
                            morph.getOutOfVocab()
                        );
                        t.morphemes.push(m);
                    }
                    s.tokens.push(t);
                }
                resultSentences.push(s);
            }
            console.log(resultSentences);
        }
    });
}

도움이 되었나요?