GraphQL + MySQL 데이터 가져오기 스터디

네이버에 개발자 모집 공고를 보다가 React Native 개발자를 구하는데 GraphQL 기반의 백엔드 프로그래밍 역할도 필요하다는 것을 보고 놀랐다. 세상이 진짜 변하긴 했다.

물론 프론트 개발자가 백엔드를 동시에 작업할 수 있으면 매우 생산성이 높고 문서작업 & 협의 과정 없이 빠르게 서비스를 만들수 있다. 나는 Node.js 와 Vue.js를 이용해서 그런방식으로 작업을 하고 있는데 매번 프론트에서 엔드포인트가 필요할때마다 Node에서 api를 만들고 그걸 받아서 쓰고 있지만 프론트에서 이걸 끝내는 방법이 없나 하는 생각은 늘 하고 있던 차였다.

GraphQL이 이걸 해줄 수 있다고 해서 공부를 해봐야지 한게 벌써 두해를 넘기고 있기도 하고 여러가지 문서를 읽어 봤지만 역시 만들어 보는게 최고라… 그게 뭔지는 대충 아래 링크로 퉁치고 Hello World 와 좀 더 실제적인 Mysql DB에서 데이터를 읽어와서 뿌려주는데까지 한번 해보기로 했다.

Node.js & Express.js 로 서버를 구성하면 빠른방법으로 Hello World를 찍어 볼 수 있다.

> express --view=pug
> npm install express-graphql graphql

Express Generator를 이용해 프로젝트를 생성하고 npm으로 express-graphql, graphql을 설치했다.

var express = require('express');
var graphqlHTTP = require('express-graphql');
var { buildSchema } = require('graphql');

var app = express();

var schema = buildSchema(`
  type Query {
    hello: String
  }  
`);

var root = {
  hello: ()=>{
    return 'Hello World'
  },
};

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true
}));

코드를 실행하고 http://localhost:3000/graphql 에 접속하면 다음과 같은 화면을 볼 수 있다. 이것은 app.use() 에서 graphiql 옵션을 true로 셋팅하면 나타나는 화면으로 GraphQL의 테스트 인터페이스이다. 여기서 api를 미리 테스트 해볼 수 있다. 자동완성 기능도 지원한다.

Hello World는 찍었다. 대충 이제 다 알았다…는 아니고 현재 가장 많이 쓰고 있는 DB인 MySQL에 연결해서 데이터를 가져오는데 까지 해야한다. Node에서 MySQL 연결과 기타 과정은 생략하고 아래와 같은 코드를 작성 했다.

var app = express();
var schema = buildSchema(`
  type Query {
    user: [User]
  }
  
  type User {
    name: String
    age: Int
    sex: String
  }  
`);

var root = {
  user: ()=>{
    return new Promise(function (resolve) {
      pool.query('select * from users', function (err, res) {
        resolve(res);
      });
    });
  },
};

app.use('/graphql', graphqlHTTP({
  schema: schema,
  rootValue: root,
  graphiql: true
}));

의의 코드를 실행한 결과로 아래와 같은 화면을 얻었다.

분명 데이터는 나왔는데 뭔가 잘못한게 아닌가 싶은 생각이 들었다. 타입도 서버에서 선언해 줘야 하고 쿼리도 서버에서 실행시킨다면 이게 기존의 REST API와 무었이 다른가? 그저 한개의 엔드 포인트를 쓴거 말고 다른게 있나 싶은 생각이 들었다.

그래서 좀 더 검색을 해봤다. 아래 링크에서 하나의 엔드포인트가 중요한 차이점이며 Query의 요청과정에서 파라메타의 차이로 결과를 다르게 가져올 수 있다는 점이 중요하다고 알려줬다.

https://www.holaxprogramming.com/2018/01/20/graphql-vs-restful-api/

결론

나는 이걸 어떻게 써야 하나 하는 문제가 고민이었는데 어차피 현재 Node.js 를 서버로 쓰고 있기 때문에 기존의 REST API에 GraphQL을 더 붙여 써도 괜찮지 않을까 하는 생각을 했다.

개발자들이 뭔가 바꾸고 싶으면 아주 갈아엎는(?) 나쁜 습성이 있지만 그러지 않아도 된다면 엔드 포인트 한두개씩 GraphQL로 바꿔도 무방할지 않을까 싶다.

소스코드는 아래 링크에 있습니다.

https://github.com/bipark/graphql_study

2020/12/10 박병일

웹서비스의 검색엔진 최적화 (SEO) 작업

개발 과정에서 웹서비스의 검색엔진 최적화 (SEO) 작업 진행 과정을 정리 해봤습니다. 내부 기록과 비슷한 작업을 하는 분들을 위해 두서없이 정리 했습니다.

  • 컨텐츠 서비스를 하고 있는 입장에서 SEO(search engine optimization – 검색엔진 최적화)는 엄청나게 중요한 기능이지만 웹 클라이언트를 SPA로 만들고 있던 타력 때문에 리뉴얼때도 어쩔 수 없이 SPA(React)로 진행 할 수 밖에 없었음
  • 웹 SPA Applications은 기능을 구현하고 서비스를 만들기에 용이 하지만 Client에서 서비스를 구동 시킨다는 근본적인 한계 때문에 검색엔진 최적화에는 치명적인 문제를 안고 있었음.
  • 그래서 만든 대안이 프록시 서버 – 가장 시급한 일이 페이스북 Open Graph에 대한 대응이었기 때문에 페이스북 검색봇이 서비스에 접근하면 User Agent를 확인하고 별도의 프록시 서버로 리다이렉션하여 Open Graph 메타 데이터를 전송하는것으로 기능 구현함
  • 구글봇 역시 프록시에서 처리 하였지만 프록시 서버에서 전달하는 데이터가 실제 서비스의 코어 데이터만 전달 하다보니 검색엔진이 크롤러가 온전한 컨텐츠를 모두 가지고 가지 못하는 문제가 생기고 각 컨텐츠 페이지의 링크 구조가 온전하게 검색엔진에 전송되지 않아서 검색 키워드에 대한 검색 결과가 완전하지 나나타지 않는 현상이 발생 하고 있었음
  • 서버 랜더링이 위의 문제들에 대한 완전한 해결방안임을 알고는 있었지만 레거시 코드와 기능 구현 문제로 SSR전환을 쉽게 결정하지 못하는 상태로 상당한 시간이 지나감
  • React의 경우 Next라는 프레임워크로 서버사이드 랜더링 기능이 지원 되고 있지만 기존에 사용중이던 클라이언트 Navigation 시스템과 User Management 시스템의 상당한 변경 이슈로 결정을 망설이게됨
  • 하지만 꼭 해야 하는 일이라서 Next – React 기반의 프로토타이핑 개발을 진행해서 기존 코드와의 변경점을 확인하고 실제 개발에 착수. https://github.com/zeit/next.js/

동시에 구글 서치엔진 SEO 기능에 대한 서베이 및 개발 진행

  • 구글 검색엔진 최적화에 관련한 자료는 대부분 https://developers.google.com/search/docs/guides/ 에서 찾을 수 있음
  • https://www.google.com/webmasters/tools/home 에서 구글 SEO 관련 셋팅을 진행함
  • 각 컨텐츠에 맞는 구조화 데이터에 대한 메타 데이터 및 LD+Json 스크립트를 지원하면 더 품부한 검색 결과 및 검색결과에서 더 좋은 표시 결과를 얻을 수 있음
  • LD+Json은 버즈아트의 경우 컨텐츠를 http://schema.org/VisualArtwork 의 구조와 같이 생성하도록 구성, 다른 컨텐츠 구조는 적절한 스키마를 찾아서 데이터를 삽입하는 과정을 거침
  • SiteMap은 가능 하면 모든 링크를 크롤링 후 생성해서 업로드 해주는 것이 원하는 경색 결과를 얻을 수 있음
  • 상용 서비스를 이용할 수도 있고 크롤러를 만들 수도 있음
  • 우리는 https://github.com/lgraubner/sitemap-generator 를 이용하여 Node.js 기반으로 만들어 사용함
  • 컨텐츠는 매일 생성되므로 가능한 자주 SiteMap을 생성하여 업데이트 해주는 것이 SEO에 최적화에 좋은것으로 판단
  • 메타 데이터의 생성은 Next – Head Tag를 이용하여 서버 랜더링 상황에서 Setting

결론

  • SEO는 참을성이 필요한 작업으로 생각됨
  • 검색엔진의 요청사항을 파악하고 꾸준한 업데이트와 최적화의 과정을 거쳐야 최적화 가능
  • 작업 완료 이후에도 검색봇이 크롤링 해서 인덱싱 하는 과정에 상당한 시간이 소요되므로 개발완료 이후 1~2달에 걸쳐 꾸준히 검색결과의 변화를 확인하고 조금씩 옵티마이즈하는 과정을 거쳐서 최적화 해야함

웹 서비스 검색 & 공유 최적화

인터넷으로 홈페이지를 서비스하고 있는 회사들의 상당수가 개발과 마케팅에 많은 비용을 쓰지만 의외로 검색 & 공유 최적화에는 돈을 쓰지 않는 편입니다. 이유는 이런 대응은 주로 마케팅의 영역에서 해야 한다는 개발 조직의 생각과 기술을 모르는 마케팅 조직의 대응방법에서 나오는 생각의 차이 때문입니다.

개발 조직에서 기존의 개발 업무에 약간의 노력을 더하면 홍보 & 마케팅에 쓰는 비용을 줄이거나 홍보의 효과를 극대화하는 방법을 찾을 수 있습니다. 그것은 흔히 검색 최적화라고 불리는 SEO(Search Engine Optimization)와 소셜 공유 최적화 입니다. 최초 서비스 개발시에 이런 기술들을 적용하는 것이 기장 이상적이지만 이미 운영중인 서비스에도 검색 & 공유 최적화를 할 수 있는 많은 방법들이 있습니다.

검색 최적화 방안

  • 검색 최적화의 방법은 구글도 모릅니다 – 검색 알고리듬이 계속 변화하고 있습니다.
  • 하지만 구글에서 제시하고 있는 가이드가 있습니다. 물론 가이드대로 해도 잘되지 않는 경우가 적지 않습니다.
  • 데이터를 측정할 수 있는 다양한 방법이 있기 때문에 결과를 측정해가면서 작은 조정들을 계속해 나가는 것이 가장 최선의 방법입니다.
  • 검색 최적화의 가장 좋은 방법은 Google Search Console https://www.google.com/webmasters/tools/home 에서 지시하고 있는 기능들을 구현하고 시간을 가지며 결과를 측정해서 조정하는 방법입니다.

검색 노출 향상을 위한 구조화된 데이터

구글 구조화된 데이터 (Google Structured Data)

  • 컨텐츠의 타입에 따라 구조화된 데이터를 지원(ld+json)하면 검색결과에서 더 다양한 형태로(이미지, 동영상 등) 결과를 조회할 수 있습니다.
  • 구조화된 데이터는 https://schema.org 에 정의된 schema 타입으로 서비스 데이터를 구조적으로 정의해서 표준화된 형태의 디스플레이 구조로 만들어 검색 결과로 나타나도록 보여줍니다.
  • “application/ld+json” 타입의 데이터를 검색봇에게 제공하여 구글이 표준화된 조회 결과를 나타낼 수 있도록 합니다.
  • 이미지, 동영상, 책, 상품 등의 검색 결과들을 아래 링크와 같은 형태로 최적화 시켜줍니다. 아래 링크에서 검색 결과를 조회할 수 있습니다.
  • https://developers.google.com/search/docs/guides/search-gallery?hl=ko
  • 기존 서비스를 수정할 수 없다면 프록시 서버 타입으로 검색봇에 대하여 대응할 수 있습니다. – 3.3 참조

Sitemap 작성 및 등록

  • Sitemap을 작성하는 것은 크롤링봇에게 컨텐츠의 정확한 주소를 알려 주는 것과 같습니다.
  • Sitemap 생성기를 활용하여 만든 Sitemap을 업로드 하여 주기적으로 페이지 변화를 구글에게 알려줍니다.
  • 서비스 내부에 페이지 변화가 생기면 자동으로 Sitemap을 생성하여 즉각 대응할 수도 있습니다.

데이터 하이라이터

  • 일정하고 표준화된 서비스 페이지의 경우 좀 더 쉽고 간단한 방법으로 검색결과를 표시할 수 있습니다.
  • https://support.google.com/webmasters/answer/2692911?hl=en

robot.txt 설정

  • 크롤링의 원하는 페이지 또는 보안이 필요한 페이지를 명확히 구분하여 크롤링봇의 접근을 제어해야 합니다.
  • Web Server, Api Server, Back Office 등에 대한 접근 권한을 차별화하여 웹 보안성도 확인해야 합니다.
  • 로봇 배제 표준 프로토콜 지원
  • https://en.wikipedia.org/wiki/Robots_exclusion_standard#About_the_standard

SSR(Server Side Rendering)

  • SSR은 HTML 데이터의 일부 혹은 전부를 서버에서 생성해서 클라이언트(웹브라우저)에게 전달하는 방식입니다. 반대로 SPA(Single Page Application)는 클라이언트(브라우저)에서 HTML을 생성하고 데이터만 API 서버에서 받아서 결합하는 타입입니다. 따라서 렌더링을 하지 않는 Bot 형태의 접근자에 대한 일반적 처리에 어려움이 있습니다.
  • 현재 오픈되어 있는 서비스의 타입(SSR 인지 SPA인지)에 따라 검색 & 공유 봇에 대한 대응 방법이 다를 수 있습니다.
  • 서버 렌더링(Node.js, PHP등..)의 경우 소스 레벨의 수정을 통하여 메타 데이터를 코드에 삽입할 수 있습니다.
  • SPA(Single Page Application)방식의 서비스(React, Vue, Angular 등등..)라면 프록시 서버를 개발하여 특정 봇에만 대응하는 기능을 추가해서 기존 서비스와 별도의 운영이 가능합니다.
  • SPA 서비스를 SSR로 변환하는 방법도 가능합니다.
  • 기존 서비스 소스가 있다는 가정 하에 React.js의 경우 Next.js를 도입하고 일부 코드를 수정하여 SSR을 도입할 수 있습니다.
  • Vue.js의 경우 Nuxt.js 프레임워크를 도입할 수 있습니다.

프록시 서버 – SSR이 안되면

  • SSR(서버 사이드 랜더링)이 불가능한 시스템에 대한 검색엔진 대응 방법
  • 기존 서비스가 SPA 이거나 소스레벨의 수정이 불가능하면 Proxy Server를 이용하는 방법을 사용할 수 있습니다.
  • 서비스에 접근하는 접속의 UserAgent를 확인하여 검색봇, 공유봇 등을 구분하고 별도의 서버로 Redirect 합니다. 검색 봇에게는 위의 검색 결과에 필요한 정보를 제공하고, 공유봇에게는 공유를 위한 Open Graph 데이터만을 제공하는 별도의 서버를 구성할 수 있습니다.
  • 기존 시스템과 별도의 개발이 진행되어야 하지만 단지 봇을 위한 대응이므로 UI가 없는 서버만으로 대응이 가능합니다. 따라서 개발이 비교적 쉬운 편입니다.

소셜 공유 & 최적화 방안

  • 소셜 공유는 데이터를 사용자들이 자발적으로 다른 사용자에게 전달하게 하는 가장 좋은 홍보 & 마케팅 도구입니다.
  • 물론 기본적으로 사용자가 공유하고 싶은 컨텐츠를 만드는 것이 가장 중요하지만 쉽게 공유할 수 있도록 서비스를 구성하는 것도 매우 중요합니다.
  • 소셜공유는 대략 두가지 기술적인 방법으로 이루어집니다.
  • 첫번째는 사용자가 공유하는 시점에서 공유 데이터를 생성해서 소셜 서비스에 직접적으로 업로드하는 타입입니다.
  • 두번째는 Page Link를 등록하면 공유봇이 Site를 방문하여 제공된 데이터를 가지고 와서 포스팅하는 방법입니다.
  • 후자의 경우 Facebook이 대표적이고 Open Graph라는 TAG 기반의 정보를 활용합니다.

소셜 데이터 공유

  • 일반적인 데이터 공유는 플랫폼 별로 다양한 오픈 소스 공유 버튼을 이용하는 것이 편리하고 좋습니다.
  • JavaScript 기반의 다양한 프론트엔드 오픈소스들이 존재하므로 플랫폼에 따라 여러가지 오픈소스를 테스트한 후 가장 적합하고 쓰기 쉬운 것을 선택하는 것이 좋습니다.
  • iOS, Android 플랫폼의 경우 Facebook SDK, Firebase SDK 등을 활용하여 기능을 구현하는 것이 일반적입니다.

오픈 그래프 공유

  • Open Graph는 페이스북에서 만든 이후 다양한 소셜 서비스에서 이를 사용하고 있는데 페이스북과 트위터가 대표적입니다.
  • 이를 지원하기 위해서는 컨텐츠를 제공하는 각 페이지에서 META TAG를 이용하여 페이지가 이 컨텐츠를 소셜에 제공하고자 하는 의도를 미리 정의 해 두어야만 합니다.
  • META TAG 없이 공유된 페이지는 내용에 따라 서비스 의도에 부합하지 않는 데이터를 제공하게 될 수도 있습니다.
  • 페이지에서 제공하고자 하는 정보와 Open Graph의 Object Type을 맞추면 페이스북 타임라인에 제공되는 UI를 컨텐츠에 적합한 다양한 모양으로 제공할 수 있습니다.
  • 오픈 그래프에 정의된 다양한 옵션들은 다음 링크에서 참조하세요
  • https://developers.facebook.com/docs/reference/opengraph
  • 공유 디버거를 통하여 공유 결과를 미리 조회할 수 있습니다.
  • https://developers.facebook.com/tools/debug/sharing