Postgres에서 GraphQL 구독으로 실시간 앱을 빌드하는 방법
게시 됨: 2022-03-10이 기사에서 우리는 실시간 애플리케이션 구축과 관련된 문제와 새로운 도구가 추론하기 쉬운 우아한 솔루션으로 이를 해결하는 방법을 살펴볼 것입니다. 이를 위해 Postgres, GraphQL, React를 사용하고 백엔드 코드 없이 실시간 투표 앱(실시간 전체 통계가 포함된 Twitter 설문조사)을 구축합니다!
주요 초점은 백엔드 설정(즉시 사용 가능한 도구 배포, 스키마 모델링)과 프론트엔드의 UI/UX에 대한 GraphQL과 적은 프론트엔드 통합 측면(ReactJS에 대한 약간의 지식이 도움이 될 것입니다)입니다. 튜토리얼 섹션은 숫자로 그리는 접근 방식을 취하므로 처음부터 전체 앱을 빌드하는 대신 스키마 모델링 및 UI를 위한 GitHub 리포지토리를 복제하고 조정할 것입니다.
GraphQL의 모든 것
GraphQL에 대해 알아야 할 모든 것을 알고 있습니까? 의심이 가는 경우 Eric Baer가 그 기원, 단점 및 작업 방법에 대한 기본 사항에 대한 자세한 가이드를 제공합니다. 관련 기사 읽기 →
이 기사를 계속 읽기 전에 다음 기술(또는 대체 기술)에 대한 실무 지식이 유용하다는 점을 말씀드리고 싶습니다.
- ReactJS
이것은 클라이언트 라이브러리 문서에 따라 모든 프론트엔드 프레임워크, Android 또는 IOS로 대체할 수 있습니다. - 포스트그레스
다른 데이터베이스로 작업할 수 있지만 다른 도구를 사용하면 이 게시물에 설명된 원칙이 계속 적용됩니다.
또한 이 튜토리얼 컨텍스트를 다른 실시간 앱에 매우 쉽게 적용할 수 있습니다.
하단에 첨부된 GraphQL 페이로드에서 알 수 있듯이 구현해야 하는 세 가지 주요 기능이 있습니다.
- 투표 질문과 옵션 목록을 가져옵니다(왼쪽 상단).
- 사용자가 주어진 투표 질문에 투표할 수 있도록 허용합니다("투표" 버튼).
- 실시간으로 설문조사 결과를 가져와 막대 그래프로 표시합니다(오른쪽 상단, 이 사용 사례의 정확한 복제본이므로 현재 온라인 사용자 목록을 가져오는 기능을 생략할 수 있습니다).
실시간 앱 구축의 과제
실시간 앱 구축(특히 프론트엔드 개발자 또는 최근에 풀스택 개발자로 전환한 사람)은 해결하기 어려운 엔지니어링 문제입니다. 이것은 일반적으로 최신 실시간 앱이 작동하는 방식입니다(예제 앱 컨텍스트에서).
- 프론트엔드는 일부 정보로 데이터베이스를 업데이트합니다. 사용자의 투표는 백엔드, 즉 poll/option 및 사용자 정보(
user_id
,option_id
)로 전송됩니다. - 첫 번째 업데이트는 투표 데이터를 집계하여 실시간으로 앱에 다시 릴레이되는 출력을 렌더링하는 다른 서비스를 트리거합니다. 이 설문조사를 구독한 클라이언트만 업데이트됨):
- 투표 데이터는 먼저
poll_results
서비스를 트리거하는register_vote
서비스(여기에서 일부 유효성 검사가 발생한다고 가정)에 의해 처리됩니다. - 실시간 집계된 폴 데이터는 전체 통계를 표시하기 위해
poll_results
서비스에 의해 프런트엔드로 릴레이됩니다.
- 투표 데이터는 먼저
이 모델은 전통적인 API 구축 접근 방식에서 파생되었으며 결과적으로 유사한 문제가 있습니다.
- 순차적 단계가 잘못되어 UX가 중단되고 다른 독립적인 작업에 영향을 줄 수 있습니다.
- 여러 서비스와 상호 작용하는 프론트엔드 앱의 단일 접점이기 때문에 API 계층에 많은 노력이 필요합니다. 또한 웹 소켓 기반 실시간 API를 구현해야 합니다. 이에 대한 보편적인 표준이 없으므로 도구 자동화에 대한 지원이 제한적입니다.
- 프런트엔드 앱은 실시간 API를 사용하는 데 필요한 연결을 추가해야 하며 실시간 앱에서 일반적으로 나타나는 데이터 일관성 문제를 해결해야 할 수도 있습니다(선택한 예에서는 덜 중요하지만 실제 -시간 채팅 앱).
- 많은 구현에서 손쉬운 실시간 API 지원을 위해 서버 측(Firebase 등)에서 추가 비관계형 데이터베이스를 사용합니다.
GraphQL 및 관련 도구가 이러한 문제를 해결하는 방법을 살펴보겠습니다.
GraphQL이란 무엇입니까?
GraphQL은 API용 쿼리 언어 사양이며 쿼리 실행을 위한 서버 측 런타임입니다. 이 사양은 앱 개발을 가속화하고 데이터베이스에 구애받지 않는 표준화된 데이터 액세스 형식을 제공하기 위해 Facebook에서 개발했습니다. 사양을 준수하는 모든 GraphQL 서버는 다음을 지원해야 합니다.
- 읽기 쿼리
데이터 소스(데이터베이스, REST API 또는 다른 GraphQL 스키마/서버 중 하나 또는 조합일 수 있음)에서 중첩 데이터를 요청하기 위한 요청 유형입니다. - 쓰기에 대한 돌연변이
앞서 언급한 데이터 소스에 데이터 쓰기/릴레이를 위한 요청 유형입니다. - 라이브 쿼리 구독
클라이언트가 실시간 업데이트를 구독하기 위한 요청 유형입니다.
GraphQL은 또한 유형이 지정된 스키마를 사용합니다. 에코시스템에는 개발/컴파일 시 오류를 식별하여 런타임 버그를 줄이는 데 도움이 되는 많은 도구가 있습니다.
GraphQL이 실시간 앱에 적합한 이유는 다음과 같습니다.
- 라이브 쿼리(구독)는 GraphQL 사양의 암시적 부분입니다. 모든 GraphQL 시스템에는 기본 실시간 API 기능이 있어야 합니다.
- 실시간 쿼리에 대한 표준 사양은 클라이언트 측 도구에 대한 커뮤니티 노력을 통합하여 GraphQL API와 통합하는 매우 직관적인 방법을 제공합니다.
GraphQL과 데이터베이스 이벤트 및 서버리스/클라우드 기능을 위한 오픈 소스 도구의 조합은 구축 및 관리가 쉬운 비동기식 비즈니스 로직과 실시간 기능으로 클라우드 네이티브 애플리케이션을 구축하기 위한 훌륭한 기반을 제공합니다. 이 새로운 패러다임은 또한 훌륭한 사용자 및 개발자 경험을 제공합니다.
이 기사의 나머지 부분에서는 오픈 소스 도구를 사용하여 이 아키텍처 다이어그램을 기반으로 앱을 빌드합니다.
실시간 투표/투표 앱 구축
GraphQL에 대한 소개와 함께 첫 번째 섹션에서 설명한 대로 투표 앱을 구축하는 것으로 돌아가 보겠습니다.
세 가지 기능(또는 강조 표시된 스토리)은 앱에서 생성할 다양한 GraphQL 요청 유형을 보여주기 위해 선택되었습니다.
- 질문
설문조사 질문과 해당 옵션을 가져옵니다. - 돌연변이
사용자가 투표하도록 하십시오. - 신청
투표 결과에 대한 실시간 대시보드를 표시합니다.
전제 조건
- Heroku 계정 (프리 티어 사용, 신용 카드 필요 없음)
GraphQL 백엔드(아래 다음 항목 참조) 및 Postgres 인스턴스를 배포합니다. - Hasura GraphQL 엔진 (무료, 오픈 소스) Postgres에서 바로 사용할 수 있는 GraphQL 서버.
- Apollo Client (무료, 오픈 소스 SDK)
클라이언트 앱을 GraphQL 서버와 쉽게 통합합니다. - npm (무료, 오픈 소스 패키지 관리자)
React 앱을 실행하려면.
데이터베이스 및 GraphQL 백엔드 배포
Heroku의 프리 티어에 Postgres 및 GraphQL 엔진 각각의 인스턴스를 배포합니다. 멋진 Heroku 버튼을 사용하여 클릭 한 번으로 이 작업을 수행할 수 있습니다.
참고: 이 링크를 따라가거나 Heroku(또는 기타 플랫폼)용 Hasura GraphQL 배포 문서를 검색할 수도 있습니다.
추가 구성이 필요하지 않으며 "앱 배포" 버튼을 클릭하기만 하면 됩니다. 배포가 완료되면 앱 URL을 기록해 둡니다.
<app-name>.herokuapp.com
예를 들어 위의 스크린샷에서는 다음과 같습니다.
hge-realtime-app-tutorial.herokuapp.com
우리가 지금까지 한 것은 Postgres 인스턴스(Heroku 용어로 추가 기능으로)와 이 Postgres 인스턴스를 사용하도록 구성된 GraphQL Engine 인스턴스를 배포하는 것입니다. 그 결과, 이제 바로 사용할 수 있는 GraphQL API가 생겼지만 데이터베이스에 테이블이나 데이터가 없기 때문에 아직 유용하지 않습니다. 따라서 즉시 해결해 보겠습니다.
데이터베이스 스키마 모델링
다음 스키마 다이어그램은 설문조사 앱에 대한 간단한 관계형 데이터베이스 스키마를 캡처합니다.
보시다시피 스키마는 외래 키 제약 조건을 활용하는 단순하고 정규화된 스키마입니다. GraphQL 엔진이 1:1 또는 1:다 관계로 해석하는 것은 이러한 제약 조건입니다(예: poll:options
는 1:다 관계입니다. 각 폴에는 두 개 이상의 옵션이 있고, poll
테이블의 id
열과 option
테이블의 poll_id
열). 관련 데이터를 그래프로 모델링할 수 있으므로 GraphQL API를 구동할 수 있습니다. 이것이 바로 GraphQL 엔진이 하는 일입니다.
위의 내용을 기반으로 스키마를 모델링하려면 다음 테이블과 제약 조건을 만들어야 합니다.
-
Poll
설문조사 질문을 캡처하는 테이블입니다. -
Option
각 투표에 대한 옵션입니다. -
Vote
사용자의 투표를 기록합니다. - 다음 필드(
table : column
) 사이의 외래 키 제약 조건:-
option : poll_id → poll : id
-
vote : poll_id → poll : id
-
vote : created_by_user_id → user : id
-
이제 스키마 디자인이 있으므로 Postgres 데이터베이스에 구현해 보겠습니다. 이 스키마를 즉시 불러오기 위해 다음을 수행합니다.
- GraphQL 엔진 CLI를 다운로드합니다.
- 이 리포지토리를 복제합니다.
$ git clone clone https://github.com/hasura/graphql-engine $ cd graphql-engine/community/examples/realtime-poll
-
hasura/
로 이동하여config.yaml
을 편집합니다.endpoint: https://<app-name>.herokuapp.com
- 방금 복제를 통해 다운로드한 프로젝트 디렉터리 내에서 CLI를 사용하여 마이그레이션을 적용합니다.
$ hasura migrate apply
그것이 백엔드를 위한 것입니다. 이제 GraphQL 엔진 콘솔을 열고 모든 테이블이 있는지 확인할 수 있습니다(콘솔은 https://<app-name>.herokuapp.com/console
에서 사용 가능).
참고: 콘솔을 사용하여 개별 테이블을 만든 다음 UI를 사용하여 제약 조건을 추가하여 스키마를 구현할 수도 있습니다. GraphQL 엔진에서 마이그레이션에 대한 내장 지원을 사용하는 것은 샘플 리포지토리에 필요한 테이블을 불러오고 관계/제약을 구성하기 위한 마이그레이션이 있기 때문에 사용할 수 있는 편리한 옵션일 뿐입니다. 프로젝트 또는 프로덕션용 앱).
프론트엔드 React 앱을 GraphQL 백엔드와 통합하기
이 튜토리얼의 프론트엔드는 설문조사 질문, 투표 옵션 및 집계된 설문조사 결과를 한 곳에서 보여주는 간단한 앱입니다. 앞서 언급했듯이, 우리는 먼저 이 앱을 실행하는 데 중점을 두어 최근에 배포한 GraphQL API를 즉시 사용할 수 있도록 하고, 이 기사의 앞부분에서 살펴본 GraphQL 개념이 이러한 앱의 다양한 사용 사례를 어떻게 지원하는지 확인합니다. , 그리고 내부에서 GraphQL 통합이 어떻게 작동하는지 살펴보십시오.
참고: ReactJS를 처음 사용하는 경우 이 기사 중 일부를 확인하는 것이 좋습니다. 앱의 React 부분에 대한 자세한 내용은 다루지 않고 대신 앱의 GraphQL 측면에 더 집중할 것입니다. React 앱이 어떻게 구축되었는지에 대한 자세한 내용은 리포지토리의 소스 코드를 참조할 수 있습니다 .
프런트엔드 앱 구성
- 이전 섹션에서 복제된
HASURA_GRAPHQL_ENGINE_HOSTNAME
에서 src/apollo.js 파일(/community/examples/realtime-poll
폴더 내)의 HASURA_GRAPHQL_ENGINE_HOSTNAME을 편집하고 위의 Heroku 앱 URL로 설정합니다.export const HASURA_GRAPHQL_ENGINE_HOSTNAME = 'random-string-123.herokuapp.com';
- repository/app-folder(
/realtime-poll/
)의 루트로 이동하고 npm을 사용하여 필수 모듈을 설치한 다음 앱을 실행합니다.$ npm install $ npm start
이제 앱을 가지고 놀 수 있어야 합니다. 원하는 만큼 투표를 진행하세요. 결과가 실시간으로 변경되는 것을 확인할 수 있습니다. 실제로 이 UI의 다른 인스턴스를 설정하고 동일한 백엔드를 가리키면 모든 인스턴스에서 집계된 결과를 볼 수 있습니다.
그렇다면 이 앱은 GraphQL을 어떻게 사용합니까? 읽어.
비하인드 스토리: GraphQL
이 섹션에서는 앱을 구동하는 GraphQL 기능을 탐색하고 다음 섹션에서 통합의 용이성을 시연합니다.
설문 구성 요소 및 집계된 결과 그래프
모든 옵션이 포함된 투표를 가져오고 데이터베이스에서 사용자의 투표를 캡처하는 왼쪽 상단의 설문 구성 요소입니다. 이 두 작업은 모두 GraphQL API를 사용하여 수행됩니다. 설문의 세부 정보를 가져오기 위해 쿼리를 만듭니다(GraphQL 소개에서 이것을 기억합니까?).
query { poll { id question options { id text } } }
react-apollo
의 Mutation 구성 요소를 사용하여 HTML 양식에 변형을 연결할 수 있습니다. 이 변형은 양식이 제출될 때 optionId
및 userId
변수를 사용하여 실행됩니다.
mutation vote($optionId: uuid!, $userId: uuid!) { insert_vote(objects: [{option_id: $optionId, created_by_user_id: $userId}]) { returning { id } } }
투표 결과를 표시하려면 투표 테이블의 데이터에서 옵션당 투표 수를 도출해야 합니다. Postgres 보기를 만들고 GraphQL 엔진을 사용하여 추적하여 이 파생 데이터를 GraphQL에서 사용할 수 있도록 할 수 있습니다.
CREATE VIEW poll_results AS SELECT poll.id AS poll_id, o.option_id, count(*) AS votes FROM (( SELECT vote.option_id, option.poll_id, option.text FROM ( vote LEFT JOIN public.option ON ((option.id = vote.option_id)))) o LEFT JOIN poll ON ((poll.id = o.poll_id))) GROUP BY poll.question, o.option_id, poll.id;
poll_results
보기는 vote
및 poll
테이블의 데이터를 결합하여 각 옵션당 총 투표 수를 제공합니다.
이 보기에서 GraphQL 구독, react-google-charts 및 react-apollo
의 구독 구성 요소를 사용하여 클라이언트에서 새 투표가 발생할 때 실시간으로 업데이트되는 반응 차트를 연결할 수 있습니다.
subscription getResult($pollId: uuid!) { poll_results(where: {poll_id: {_eq: $pollId}}) { option { id text } votes } }
GraphQL API 통합
앞서 언급했듯이 저는 ReactJS 앱을 GraphQL 백엔드와 통합하기 위해 오픈 소스 SDK인 Apollo Client를 사용했습니다. Apollo Client는 Python에 대한 요청, JavaScript용 표준 http 모듈 등과 같은 모든 HTTP 클라이언트 라이브러리와 유사합니다. HTTP 요청(이 경우 POST 요청)에 대한 세부 정보를 캡슐화합니다. 구성( src/apollo.js
에 지정)을 사용하여 쿼리/변이/구독 요청(REACT 앱의 JavaScript 코드에서 동적으로 대체될 수 있는 변수를 사용하는 옵션과 함께 src/GraphQL.jsx 에 지정)을 수행합니다. GraphQL 끝점. 또한 앞서 언급한 요청에 대한 컴파일/개발 시간 유효성 검사를 제공하기 위해 GraphQL 끝점 뒤에 있는 형식화된 스키마를 활용합니다. 클라이언트 앱이 GraphQL API에 대한 라이브 쿼리(구독) 요청을 하는 것이 얼마나 쉬운지 봅시다.
SDK 구성
Apollo Client SDK는 GraphQL 서버를 가리켜야 하므로 이러한 통합에 일반적으로 필요한 상용구 코드를 자동으로 처리할 수 있습니다. 그래서 이것은 프론트엔드 앱을 설정할 때 src/apollo.js 를 수정할 때 했던 것과 정확히 같습니다.
GraphQL 구독 요청하기(라이브 쿼리)
src/GraphQL.jsx 파일의 이전 섹션에서 살펴본 구독을 정의합니다.
const SUBSCRIPTION_RESULT = ` subscription getResult($pollId: uuid!) { poll_results ( order_by: option_id_desc, where: { poll_id: {_eq: $pollId} } ) { option_id option { id text } votes } }`;
이 정의를 사용하여 React 구성 요소를 연결합니다.
export const Result = (pollId) => ( <Subscription subscription={gql`${SUBSCRIPTION_RESULT}`} variables={pollId}> {({ loading, error, data }) => { if (loading) return
로드 중...</p>; (오류) 반환하는 경우
오류:</p>; 반품 ( <div> <div> {렌더 차트(데이터)} </div> </div> ); }} </구독> )
여기서 주의할 점은 위의 구독도 쿼리일 수 있다는 것입니다. 단순히 하나의 키워드를 다른 키워드로 교체하는 것만으로도 "라이브 쿼리"가 제공되며 Apollo Client SDK가 이 실시간 API를 앱과 연결하는 데 필요한 전부입니다. 라이브 쿼리에서 새 데이터 세트가 있을 때마다 SDK는 이 업데이트된 데이터로 차트를 다시 렌더링합니다( renderChart(data)
호출 사용). 그게 다야 정말 간단합니다!
마지막 생각들
간단한 3단계(GraphQL 백엔드 생성, 앱 스키마 모델링, 프론트엔드를 GraphQL API와 통합)로 설정과 같은 불필요한 세부 사항에 빠져들지 않고 완전한 기능의 실시간 앱을 신속하게 연결할 수 있습니다. 웹 소켓 연결. 바로 GraphQL과 같은 추상화를 지원하는 커뮤니티 도구의 힘입니다.
이것이 흥미롭고 다음 사이드 프로젝트 또는 프로덕션 앱을 위해 GraphQL을 더 탐색하고 싶다면 다음은 GraphQL 도구 체인을 구축하는 데 사용할 수 있는 몇 가지 요소입니다.
- 성능 및 확장성
GraphQL은 프론트엔드 앱에서 직접 사용하도록 되어 있습니다(백엔드의 ORM보다 나을 것이 없습니다. 실제 생산성 이점은 이렇게 하는 것입니다). 따라서 도구는 데이터베이스 연결을 효율적으로 사용하는 데 스마트해야 하고 쉽게 확장할 수 있어야 합니다. - 보안
위에서부터 데이터에 대한 액세스 권한을 부여하려면 성숙한 역할 기반 액세스 제어 시스템이 필요합니다. - 오토메이션
GraphQL 생태계가 처음이라면 GraphQL 스키마를 손으로 작성하고 GraphQL 서버를 구현하는 것이 벅찬 작업처럼 보일 수 있습니다. 도구에서 자동화를 최대화하여 사용자 중심의 프론트엔드 기능 구축과 같은 중요한 사항에 집중할 수 있습니다. - 건축물 위의 노력이 사소해 보이지만 프로덕션 등급 앱의 백엔드 아키텍처에는 스키마 스티칭 등과 같은 고급 GraphQL 개념이 포함될 수 있습니다. 또한 실시간 API를 쉽게 생성/사용할 수 있는 기능은 비동기식, 반응형 빌드의 가능성을 열어줍니다. 탄력적이고 본질적으로 확장 가능한 앱. 따라서 GraphQL 도구가 아키텍처를 간소화할 수 있는 방법을 평가하는 것이 중요합니다.
관련 리소스
- 여기에서 앱의 라이브 버전을 확인할 수 있습니다.
- 전체 소스 코드는 GitHub에서 사용할 수 있습니다.
- 데이터베이스 스키마를 탐색하고 테스트 GraphQL 쿼리를 실행하려면 여기에서 수행할 수 있습니다.