Express.js에서 네이버 Papago API 요청해보기

Juice-Han·2024년 2월 22일
0
post-custom-banner

express 서버에서 papago API 요청을 보내기 위해 고군분투했던 과정을 글로 정리해보려고 한다.

개발 과정


Node.js용 papago API 사용 예제

node.js 파파고 api 사용 예제

네이버가 아주 친절하게 사용 예제를 정리해놨다.
request라는 모듈로 API요청을 한 것 같은데, 뭔지는 알고 지나가야할 것 같다는 생각에 구글링을 해봤다.

deprecated된 request 모듈

이런.. 2020년부터 deprecated 되었다고 한다.
'더 이상 사용되지 않는, 사라지게 될'이라는 뜻이다.

눈 앞이 깜깜해졌다.
그렇다면 나는 이 코드를 수정해서 API 요청을 해야했다.
마음을 가다듬고 API 요청하는 방법부터 차근차근 공부해보기로 했다.

express에서 API 요청 보내기

맨 처음엔 express에서 API 요청 보내는 방법이 따로 있는 줄 알았다.
항상 프론트엔드단에서 axios로 API 요청을 보내다가 서버에서 API 요청을 보내려니 기분이 묘했다.

express에서 API 요청보내는 법을 구글링해보니 온통 express'' API 요청 보내는 글만 나와서 당황스러웠다.

'그래도 js 기반이니까 fetch로 하면 되겠지'라는 생각에 fetch API를 사용해보기로 했다. (익숙한 axios를 사용해서 편하게 요청해도 됐지만 fetch라는 기본적인 함수를 공부하고 싶어서 fetch를 사용했다.)

fetch 함수 사용법을 구글링하니 잘 정리된 글들이 많았다.
덕분에 어렵지 않게 fetch를 사용할 수 있었다.

 fetch 사용법

fetch 함수는 axios 라이브러리와 다르게 body에 들어가는 data를 JSON 문자열로 바꿔줘야 한다는 귀찮음이 있다(JSON.stringify 활용).

일단 간단하게 fetch 함수 활용법은 알게 됐고, 이제 request 모듈 사용을 가정한 네이버 사용 예제를 fetch 함수에 맞게 바꿔야 하는 과정이 남았다.

fetch함수를 활용한 papago API 요청

네이버 참고 사항

이 단계에서 살짝 뇌정지가 왔다.
헤더를 어떻게 설정해야하는지, x-www-form-urlencoded는 무엇인지 등 너무 복잡해 보였기 때문이다.

일단 먼저 Content-Type: application/x-www-form-urlencoded 라는게 뭘 뜻하는지 알아봤다.

Content-Type: application/x-www-form-urlencoded 란?

간단하게 설명하자면 request 요청 속 body 데이터의 자료형이다.

클라이언트와 서버가 데이터를 주고 받을 땐 그냥 주고받지 않는다.
문자열 데이터로 바꿔서 주고 받는다.

클라이언트는 정해진 규칙에 따라 데이터를 문자열로 바꿔서 전달하고,
서버는 바뀐 자료형을 인식하고 그에 맞게 해석해서 데이터를 사용한다.

이때 request 요청의 header라는 부분에 '우리가 ~~ 형식으로 데이터 변환했으니까 알고있으세요~'라는 메세지를 남기는데 그게 바로 Content-Type이다.
Content-Type엔 application/json도 있고 multipart/form-data 등 여러가지가 있다. (요즘 많이 쓰이는 건 application/json 타입이다.)

Content-Type: application/x-www-form-urlencoded

x-www-form-urlencoded라는 형식으로 데이터를 변환했다는 것을 서버에게 알려준다.

x-www-form-urlencoded는 key=value 형식으로 데이터를 보내야하기 때문에 객체형 데이터를 key=value 형식으로 변환해주는 qs 라이브러리를 install해서 사용하였다. (query string의 줄인말)

qs의 사용법은 간단하다. JSON.stringify처럼 qs.stringify에 객체형 자료를 인수로 전달하면 된다.

{ source: "ko", target: "en", text: query}

"source=ko&target=en&text=만나서 반갑습니다. 앞으로 잘 부탁드립니다."

이런 식으로 객체형 자료가 문자열로 바뀐다.

npm qs 문서 링크

fetch 함수 작성

let query = "만나서 반갑습니다. 앞으로 잘 부탁드립니다.";
app.get('/translate', function (req, res) {
  const api_url = 'https://openapi.naver.com/v1/papago/n2mt';
  const data = qs.stringify({ source: "ko", target: "en", text: query },{ encode: false })
  console.log(data);
  const opt = {
    method: "POST",
    headers: {
      'Content-Type' : 'application/x-www-form-urlencoded; charset=UTF-8',
      'X-Naver-Client-Id': client_id,
      'X-Naver-Client-Secret': client_secret
    },
    body: encodeURI(data)
  }
  fetch(api_url, opt)
    .then((res) => {
      console.log(res.body);
    })
    .catch((err) => {
      console.error(err)
    })
});

application/x-www-form-urlencoded라서 encode 해줘야 되는줄 알고 encodeURI()를 통해 data를 encode했다.
(나중에 확인해보니 encode를 안 해도 응답이 잘 왔다. fetch 함수가 알아서 encoding을 해주는 것 같다.)

일단은 이렇게 fetch함수를 작성해봤다. papago로 번역된 결과를 콘솔창에서 확인해보자.

ReadableStream 데이터 읽기

번역된 결과를 확인하려고 res.body를 출력해봤는데 콘솔창에

ReadableStream { locked: false, state: 'readable', supportsBYOB: false }

이런 결과가 나왔다...

분명 응답의 body를 console.log로 출력했는데, ReadableStream이라는 이상한 데이터가 출력된 것이다.

구글링한 결과 json()함수를 사용해서 ReadableStream을 파싱하면 데이터를 제대로 확인할 수 있다는것을 알게됐다.

fetch(api_url, opt)
    .then(async (res) => {
      console.log(await res.json());
    })
    .catch((err) => {
      console.error(err)
    })

json()함수는 response를 리턴하는 비동기 함수이다. 따라서 async await으로 비동기처리를 하지 않으면 Response가 출력되는 일이 발생한다. 항상 주의하자.

stack overflow - readablestream object 링크

papago API 응답 확인

짜잔~ 번역결과를 정상적으로 확인할 수 있게 되었다.

Content-Type: application/json으로 해도 정상 작동

Content-Type을 application/json 바꿔도 잘 작동하는 지 궁금해서 확인해봤다.
데이터 형식을 json으로 변환하고 요청을 보냈더니 잘 작동하는 걸 확인할 수 있었다.

let query = "만나서 반갑습니다. 앞으로 잘 부탁드립니다.";
app.get('/translate', function (req, res) {
  const api_url = 'https://openapi.naver.com/v1/papago/n2mt';
  const data = JSON.stringify({ source: "ko", target: "en", text: query})
  console.log(data);
  const opt = {
    method: "POST",
    headers: {
      'Content-Type' : 'application/json; charset=UTF-8',
      'X-Naver-Client-Id': client_id,
      'X-Naver-Client-Secret': client_secret
    },
    body: data
  }
  fetch(api_url, opt)
    .then(async (res) => {
      console.log(await res.json());
    })
    .catch((err) => {
      console.error(err)
    })
});

데이터 형식이 요청을 보낼 때 크게 중요한 것 같지는 않다. header에 잘 명시해놓으면 서버가 알아서 변환을 하는 것 같다.

최종코드


Content-Type: x-www-form-urlencoded 일때

express, qs 모듈 install은 필수이고 dotenv 모듈은 선택사항이다.

client_id와 client_secret를 직접 입력하려면 상관없는데, 나는 보안성을 위해 .env파일에 저장한 뒤 dotenv모듈을 사용해서 가져왔다.

const express = require('express');
const app = express();
const qs = require('qs');
require("dotenv").config();

app.listen(8080, () => {
  console.log('8080 포트에서 서버 실행중');
})

const client_id = process.env.PAPAGO_CLIENT_ID;
const client_secret = process.env.PAPAGO_CLIENT_SECRET
let query = "만나서 반갑습니다. 앞으로 잘 부탁드립니다.";
app.get('/translate', function (req, res) {
  const api_url = 'https://openapi.naver.com/v1/papago/n2mt';
  const data = JSON.stringify({ source: "ko", target: "en", text: query})
  console.log(data);
  const opt = {
    method: "POST",
    headers: {
      'Content-Type' : 'application/json; charset=UTF-8',
      'X-Naver-Client-Id': client_id,
      'X-Naver-Client-Secret': client_secret
    },
    body: data
  }
  fetch(api_url, opt)
    .then(async (res) => {
      console.log(await res.json());
    })
    .catch((err) => {
      console.error(err)
    })
});

Content-Type: application/json 일 때

const express = require('express');
const app = express();
require("dotenv").config();
app.listen(8080, () => {
  console.log('8080 포트에서 서버 실행중');
})

const client_id = process.env.PAPAGO_CLIENT_ID;
const client_secret = process.env.PAPAGO_CLIENT_SECRET
let query = "만나서 반갑습니다. 앞으로 잘 부탁드립니다.";
app.get('/translate', function (req, res) {
  const api_url = 'https://openapi.naver.com/v1/papago/n2mt';
  const data = JSON.stringify({ source: "ko", target: "en", text: query})
  console.log(data);
  const opt = {
    method: "POST",
    headers: {
      'Content-Type' : 'application/json; charset=UTF-8',
      'X-Naver-Client-Id': client_id,
      'X-Naver-Client-Secret': client_secret
    },
    body: data
  }
  fetch(api_url, opt)
    .then(async (res) => {
      console.log(await res.json());
    })
    .catch((err) => {
      console.error(err)
    })
});

express에서 papago API를 활용하려는 분들에게 도움이 됐으면 좋겠다.

참고자료

profile
배우고 기록하고
post-custom-banner

0개의 댓글