Hasura를 사용하여 몇 분 내에 안전한 GraphQL 애플리케이션 구축

Hasura는 모든 PostgreSQL 데이터베이스를 가리키며 데이터에 실시간 GraphQL API를 자동으로 시작할 수 있는 탁월한 서비스입니다.이 안내서에서 Hasura를 사용하여 안전한 업무 목록 프로그램을 구축할 것입니다.다음은 우리가 구축할 응용 프로그램의 빠른 미리보기입니다✅

1. 백엔드 시작


Hasura으로 가서 계정을 만듭니다.Hasura가 데이터베이스 연결을 요청하면 "Heroku를 사용하여 무료 데이터베이스 시도"를 선택하십시오.

Heroku를 사용하여 원키 설정을 완료하면 https://<YOUR_HEROKU_PROJECT>.herokuapp.com과 유사한 URL에서 새 실례와 데이터베이스가 실행됩니다.프로젝트 탭으로 이동하여 시작 콘솔을 클릭하여 응용 프로그램의 Hasura 대시보드를 엽니다.

2. 데이터 테이블


데이터 탭으로 이동한 다음 테이블 만들기 를 클릭합니다.테이블을 todos으로 명명하고 두 열을 추가합니다. 예를 들어 다음과 같습니다.
  • id :: Integer (auto-incremented)
  • title :: Text
  • is_completed :: Boolean
  • user_id :: Text
  • created_at :: Timestamp
  • id 열을 유일한 키로 표시하고 키로 설정하는 것을 기억하십시오!

    3. 인증


    Hasura에 대해 당신이 알아야 할 것은 신분 검증을 대표한다는 것입니다.이것은 귀하가 원하는 제3자 인증 공급자를 사용할 수 있음을 의미합니다.이 설명서에서 Feather는 모든 애플리케이션에 인증과 사용자 계정을 쉽게 추가할 수 있는 경량 API입니다.
    Feather와 Hasura가 함께 작업하기 위해서는 HASURA_GRAPHQL_JWT_SECRET이라는 특수 환경 변수를 설정해야 합니다.이것은 Hasura가 Feather가 발행한 사용자 ID 영패(실제로는 JWTs)를 검증하는 방법을 알려줄 것이다.따라서 Feather에 방문하여 새 프로젝트를 등록하십시오.항목을 작성한 후 Feather 대시보드의 설정 탭으로 이동하여 항목 ID를 복사합니다.

    Feather 프로젝트 ID를 아래 JSON 템플릿의 "audience" 필드에 삽입합니다.
    {
      "type":"RS256",
      "jwk_url": "https://api.feather.id/v1/.well-known/jwks",
      "issuer": "api.feather.id",
      "audience": "<YOUR_PROJECT_ID>"
    }
    
    이제 환경 변수를 만들려면 프로젝트의 Heroku 대시보드(https://dashboard.heroku.com/apps/<YOUR_HEROKU_APP>)로 이동하여'설정'탭으로 이동하여'설정 변수'라는 제목의 부분을 찾으십시오.HASURA_GRAPHQL_JWT_SECRET이라는 새 값을 만들고 JSON 값에 붙여넣습니다.

    네, 저희는 이미 신분 검증을 설정했습니다!Feather와 Hasura의 라이센스 시스템을 계속 연결합니다.

    4. 권한 부여


    Hasura의 또 다른 특성은 실시간 세립도 등급 권한 수여 제어를 제공한다는 것이다!🤯 설정하려면 항목의 Feather 대시보드에서 ID 영패 탭으로 이동합니다.다음 JSON 구조를 복사하여 Custom Claims라는 제목이 붙은 텍스트 상자에 붙여넣습니다.저장 버튼을 클릭하여 변경 사항을 커밋합니다.
    {
      "https://hasura.io/jwt/claims": {
        "x-hasura-user-id": "{{.USER.ID}}",
        "x-hasura-allowed-roles": ["user"],
        "x-hasura-default-role": "user"
      }
    }
    
    지금부터 이 프로그램에 로그인한 모든 사용자는 Hasura에 요청할 때 "user"개의 역할을 얻게 됩니다.이렇게 하면 "user" 역할에 데이터 액세스 규칙을 설정하여 사용자가 자신의 TODO를 만들고, 액세스하고, 수정할 수 있도록 합니다.
    따라서 Hasura 대시보드의 데이터 옵션으로 돌아가 todos 테이블의 권한 하위 옵션으로 이동합니다."user"이라는 새 역할을 추가한 다음 삽입 작업을 클릭하여 편집합니다.우선 "user_id" 열에 열 사전 설정을 추가하여 "X-Hasura-User-Id"으로 설정합니다.이것은 누군가가 새로운 대기항목을 만들 때마다 Hasura가 자동으로 새 줄에 사용자 ID를 설정한다는 것을 의미한다.멋있지!?😎

    선택, 업데이트, 삭제 작업에 사용자 정의 검사를 추가함으로써 인증을 끝냅니다.만약 호출자의 "X-Hasura-User-Id"이 작업 중인 줄의 "user_id"열과 일치한다면, 우리는 그 중 하나만 권한을 부여할 것입니다.

    하나의 PostgreSQL 데이터베이스, GraphQL API, 사용자 인증, 행 등급 인증을 포함하여 완전한 백엔드만 설정하면 코드를 작성할 필요가 없습니다!모든 응용 프로그램의 재미있는 부분으로 끝냅시다: 전단!🥳

    5, 프런트엔드


    터미널을 열고 깨끗한 디렉터리를 찾은 다음 다음 명령을 실행하여 우리가 필요로 하는 모든 의존 항목을 포함하는 새 React 프로그램을 만듭니다.
    $ npx create-react-app hasurademo && cd hasurademo && yarn add @apollo/client apollo-link-context apollo-link-http apollo-cache-inmemory feather-client-react graphql graphql-tag
    
    현재 가장 좋아하는 텍스트 편집기에서 이 항목을 열고 src/feather.js이라는 새 파일을 만듭니다.프로젝트의 Feather 대시보드에서 게시 가능한 API 키를 복사하고 이를 사용하여 Feather 클라이언트를 초기화합니다.

    import {FeatherClient} from "feather-client-react"
    
    export const feather = FeatherClient("pk_live_...")
    
    이제 Feather API와 대화할 준비가 되었습니다. GraphQL 클라이언트를 만들어서 Hasura API에 요청을 보냅니다.이를 위해, 우리는 Apollo을 사용할 것이다.src/apollo.js이라는 새 파일을 만들고 다음 코드를 추가합니다.
    import { ApolloClient } from "@apollo/client";
    import { InMemoryCache } from "apollo-cache-inmemory";
    import { HttpLink } from "apollo-link-http";
    import { setContext } from "apollo-link-context";
    import { feather } from "./feather";
    
    const httpLink = new HttpLink({
      uri: "https://hasura-test-pliao.herokuapp.com/v1/graphql",
      fetchPolicy: "network-only"
    });
    
    const authLink = setContext((_, { headers }) =>
      feather
        .currentUser()
        .then(u => ({
          headers: {
            ...headers,
            authorization: `Bearer ${u.tokens.idToken}`
          }
        }))
        .catch(_ => ({ headers }))
    );
    
    export const apollo = new ApolloClient({
      cache: new InMemoryCache(),
      link: authLink.concat(httpLink)
    });
    
    응용 프로그램이 사용할 수 있도록 이 클라이언트들을 React 구성 요소 트리에 연결합니다.src/index.js을 열고 다음 코드를 추가합니다.
    import React from "react";
    import ReactDOM from "react-dom";
    import "./index.css";
    import App from "./App";
    import * as serviceWorker from "./serviceWorker";
    import { FeatherProvider } from "feather-client-react";
    import { feather } from "./feather";
    import { ApolloProvider } from "@apollo/client";
    import { apollo } from "./apollo";
    
    ReactDOM.render(
      <React.StrictMode>
        <FeatherProvider client={feather}>
          <ApolloProvider client={apollo}>
            <App />
          </ApolloProvider>
        </FeatherProvider>
      </React.StrictMode>,
      document.getElementById("root")
    );
    
    // If you want your app to work offline and load faster, you can change
    // unregister() to register() below. Note this comes with some pitfalls.
    // Learn more about service workers: https://bit.ly/CRA-PWA
    serviceWorker.unregister();
    
    이제 모든 통신 부분이 준비되어 있습니다. 시각 구성 요소를 비웁니다.src/App.js을 엽니다.우리가 해야 할 첫 번째 일은 현재 사용자가 로그인했는지 확인하는 것이다.없으면 인증 양식을 표시합니다.그렇지 않으면, 사용자의 대기 사항을 열거합시다.
    import React from "react";
    import { AuthenticationForm, useCurrentUser } from "feather-client-react";
    import Todos from "./Todos";
    
    const styles = {
      title: provided => ({
        ...provided,
        fontSize: "40px",
        fontWeight: 700
      })
    };
    
    function App(props) {
      const { loading, currentUser } = useCurrentUser();
    
      if (loading) return <div />;
      if (!currentUser)
        return (
          <div className="app">
            <AuthenticationForm styles={styles} />
          </div>
        );
      return (
        <div className="app">
          <div className="app-header">
            <h1>My to-do list</h1>
            <p>{currentUser.email}</p>
          </div>
          <Todos />
        </div>
      );
    }
    
    export default App;
    
    Feather에는 사용자 정의 스타일을 제공할 수 있는 사전 구성된 인증 양식이 포함되어 있습니다.이것은 새로운 프로젝트를 설정할 때 많은 시간을 절약할 수 있다. 왜냐하면 그것은 심지어 어떤 추가 작업도 필요하지 않은 상황에서 비밀번호 리셋 같은 일을 처리할 수 있기 때문이다.⚡️
    이제 사용자에게 TODO를 보는 방법을 추가합니다.src/Todos.js이라는 새 파일을 만들고 다음 코드를 추가합니다.
    import React from "react";
    import Todo from "./Todo";
    import NewTodo from "./NewTodo";
    import { useQuery, gql } from "@apollo/client";
    
    export const GET_TODOS = gql`
      query GetTodos {
        todos {
          id
          title
          is_completed
        }
      }
    `;
    
    function Todos(props) {
      const { loading, error, data } = useQuery(GET_TODOS);
    
      if (error) return <p>{error.message}</p>;
      if (loading) return <p>Loading ...</p>;
      return (
        <div>
          {data.todos.map(todo => (
            <Todo key={todo.id} todo={todo} />
          ))}
          <NewTodo />
        </div>
      );
    }
    
    export default Todos;
    
    Apollo를 사용하여 React에서 GraphQL 요청을 직접 보내는 방법에 유의하십시오!다음은 사용자가 TODO를 편집할 수 있는 방법이 필요합니다.src/Todo.js이라는 새 파일을 만들고 다음 코드를 추가합니다.
    import React from "react";
    import { useMutation, gql } from "@apollo/client";
    
    const TOGGLE_TODO = gql`
      mutation ToggleTodo($id: Int!, $is_completed: Boolean!) {
        update_todos(
          where: { id: { _eq: $id } }
          _set: { is_completed: $is_completed }
        ) {
          returning {
            id
            is_completed
          }
        }
      }
    `;
    
    export default function Todo(props) {
      const [toggleTodo] = useMutation(TOGGLE_TODO);
    
      const onChange = e => {
        toggleTodo({
          variables: {
            id: props.todo.id,
            is_completed: !props.todo.is_completed
          }
        });
      };
    
      return (
        <div style={{ display: "flex", flexDirection: "row" }}>
          <input
            type="checkbox"
            className="todo-checkbox"
            name={props.todo.id}
            checked={props.todo.is_completed}
            onChange={onChange}
          />
          <p>{props.todo.title}</p>
        </div>
      );
    }
    
    마지막으로, 만약 사용자가 todo를 만들 수 없다면, 이 todo 응용 프로그램은 매우 유용하지 않을 것입니다!src/NewTodo.js이라는 새 파일을 만들고 다음 코드를 추가합니다.
    import React, { useState } from "react";
    import { useMutation, gql } from "@apollo/client";
    
    const CREATE_TODO = gql`
      mutation CreateTodo($title: String!) {
        insert_todos_one(object: { title: $title }) {
          id
          title
          is_completed
        }
      }
    `;
    
    function NewTodo(props) {
      const [title, setTitle] = useState("");
      const [createTodo] = useMutation(CREATE_TODO);
    
      const onSubmit = e => {
        e.preventDefault();
        createTodo({ variables: { title } });
      };
    
      const onChange = e => {
        setTitle(e.target.value);
      };
    
      return (
        <form onSubmit={onSubmit}>
          <input
            className="new-todo-input"
            value={title}
            onChange={onChange}
            type="text"
            placeholder="Today I will..."
          />
        </form>
      );
    }
    
    export default NewTodo;
    
    마지막으로 (하지만 가장 중요하지 않은 것은 아니다!),응용 프로그램을 좀 더 예뻐 보이게 스타일링합시다.src/index.css을 열고 다음 CSS 클래스를 추가합니다.🎨:
    .app {
      padding: 80px;
      max-width: 400px;
      margin: 20px auto;
    }
    
    .app-header {
      margin-bottom: 40px;
    }
    
    .todo-checkbox {
      margin: auto 10px auto 0px;
    }
    
    .new-todo-input {
      font-size: 20px;
      padding: 20px;
      width: 100%;
      margin-top: 40px;
    }
    

    끝내다


    아이고!그건 코드가 많아요!단, 만약 당신이 계속 따른다면, 터미널로 돌아가서 yarn start을 실행하여 로컬에서 프로그램을 실행할 수 있습니다.
    우리가 한 모든 것을 되돌아보자.
  • 은 Heroku에 PostgreSQL 데이터베이스 실례를 배치했다.
  • 은 Hasura를 사용하여 이 데이터베이스에 GraphQL API를 생성합니다.
  • 은 사용자 역할을 인증하고 게시하기 위해 Feather를 설정합니다.
  • 은 사용자가 자신의 데이터에만 접근할 수 있도록 권한 수여 규칙을 추가했다.
  • 은 Feather와 Apollo를 사용하여 프런트엔드 React 응용 프로그램을 만들었습니다.
  • 이 응용 프로그램 on Github의 전체 코드 라이브러리를 볼 수 있습니다.이 응용 프로그램에서 사용되는 각 기술에 대한 자세한 설명서는 다음 웹 사이트에서 각각의 문서를 볼 수 있습니다.
  • Hasura docs
  • Feather docs
  • Apollo docs
  • 좋은 웹페이지 즐겨찾기