본문 바로가기

두두의 IT

AWS Amplify로 리얼타임 서버리스 앱 만들기

728x90

AWS Amplify 서비스를 활용하면 유저 인증(auth), Rest, GraphQL API의 백엔드, 알림(notification), 파일 스토리지(storage), AI까지 아주 적은 양의 코드만으로 구현할 수 있음

Amplify는 유저 백엔드를 AWS Cognito를 이용해서 제공함


(base) xxx@xxxui-MacBookAir ~ % npm install -g @aws-amplify/cli		//npm을 통해 AWS Amplify CLI 설치 

(base) xxx@xxxui-MacBookAir ~ % amplify configure
//로그인 후 Enter
Specify the AWS Region
? region:  ap-northeast-2
Specify the username of the new IAM user:
? user name:  tweetify		//API Key를 위한 유저명
//다음,,다음,,다음,, 사용자 만들기

Enter the access key of the newly created user:
? accessKeyId:  ********************
? secretAccessKey:  ****************************************
? Profile Name:  tweetify		//AWS Profile 생성

(base) xxx@xxxui-MacBookAir ~ % npx create-react-app tweetify		//새로운 앱 생성
//yes

(base) xxx@xxxui-MacBookAir ~ % cd tweetify 
(base) xxx@xxxui-MacBookAir tweetify % amplify init
? Initialize the project with the above configuration? Yes
? Select the authentication method you want to use: AWS profile

(base) xxx@xxxui-MacBookAir tweetify % amplify add api		//새로운 APi 생성
? Select from one of the below mentioned services: GraphQL
? Here is the GraphQL API that we will create. Select a setting to edit or conti
nue Continue
? Choose a schema template: Blank Schema
//yes

 

### amplify > backend > api > schema.graphql에 위치함

# This "input" configures a global authorization rule to enable public access to
# all models in this schema. Learn more about authorization rules here: https://docs.amplify.aws/cli/graphql/authorization-rules
input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!

type Tweet @model{
    id:ID!
    text:String!
    author:String!
}
(base) xxx@xxxui-MacBookAir tweetify % amplify push
//yes
? Choose the code generation language target javascript		//API의 mutations, queries, subscriptions를 위해서 Amplify로 하여금 JS 코드 생성

(base) xxx@xxxui-MacBookAir tweetify % amplify console api		//GraphQL 콘솔 열기

//AWS Amplify에 의해 자동생성된 mutations, queries, subscriptions 확인 가능

(base) xxx@xxxui-MacBookAir tweetify % npm install aws-amplify		//Amplify와 리액트 연결하기 위해 AWS Amplify를 프로젝트에 설치
//src > index.js파일

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

//Amplify와 key로 생성된 파일 import
import {Amplify} from "aws-amplify";
import awsExports from "./aws-exports";
Amplify.configure(awsExports);

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
<!-- public > index.html -->

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <!-- UI를 아름답게 하기 위한 picocss -->
    <link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <!--
      manifest.json provides metadata used when your web app is installed on a
      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
    -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <!--
      Notice the use of %PUBLIC_URL% in the tags above.
      It will be replaced with the URL of the `public` folder during the build.
      Only files inside the `public` folder can be referenced from the HTML.

      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
      work correctly both with client-side routing and a non-root public URL.
      Learn how to configure a non-root public URL by running `npm run build`.
    -->
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <!--
      This HTML file is a template.
      If you open it directly in the browser, you will see an empty page.

      You can add webfonts, meta tags, or analytics to this file.
      The build step will place the bundled scripts into the <body> tag.

      To begin the development, run `npm start` or `yarn start`.
      To create a production bundle, use `npm run build` or `yarn build`.
    —>
  </body>
</html>
// src > App.js

import logo from './logo.svg';
import './App.css';

import {useEffect, useState } from "react";
//API에서 트윗을 가져오기 위해 import
import {API, graphqlOperation} from "aws-amplify";
//API push했을 때 자동 생성된 queries, mutations, subscriptions을 가져옴
import {listTweets} from "./graphql/queries";
import {createTweet} from "./graphql/mutations";
import {onCreateTweet} from "./graphql/subscriptions";

function App() {
  //트윗을 업로드하기 위한 form도 state에 있음
  const [formData, setFormData] = useState({
    author: "",
    text:"",
  });
  
  //input과 textarea에연결
  const onChange = (event)=>{
    const{
      target: {name, value},
    } = event;
    setFormData((prev)=>({...prev, [name]:value}));
  };
  
  //트윗은 state에 있음
  const [tweets, setTweets] = useState([]);
  
  //API에서 트윗을 가져올 함수
  const fetchTweets = async () => {
    const request = await API.graphql(graphqlOperation(listTweets));
    setTweets(request.data.listTweets.items);
  };
  
  //리얼타임으로 만들기 위해 해당 업데이트에 subscribe 하고 새로운 트윗이 들어오면 이걸 state에 둠
  const realtimeTweets = ()=>{
    API.graphql(graphqlOperation(onCreateTweet)).subscribe({
      next: ({value:{data}})=>
      setTweets((prev)=> [{...data.onCreateTweet},...prev]),
    });
  };
  
  //어플리케이션이 처음으로 로딩될 때 한 번 실행됨
  useEffect(()=>{
    fetchTweets();
    realtimeTweets();
  },[]);
  
  //입력폼이 제출될 때마다 해당 mutation 부르기
  const onSubmit = async (event) => {
    event.preventDefault();
    await API.graphql(graphqlOperation(createTweet,{input:formData}));
    setFormData((prev)=>({...prev, text:""}));
  }
  return (
    <main className='container'>
      <h1>Tweetify!</h1>
      <section>
        <h3>Tweet something!</h3>
        <form onSubmit={onSubmit}>
          <input type="text" name="author" placeholder='What is your name?' required onChange={onChange} value={formData.author}/>
          <textarea name='text' required placeholder='What is on your mind?' onChange={onChange} value={formData.text}></textarea>
          <button>Post</button>
        </form>
      </section>
      <hr/>
      <section>
        <h3>Timeline</h3>
        <div>
        	//array.map으로 트윗 render
          {tweets.map((tweet)=>(
            <article key={tweet.id}>
              <hgroup>
                <h4>{tweet.text}</h4>
                <h5>{tweet.author}</h5>
              </hgroup>
            </article>
          ))}
        </div>
      </section>
    </main>
  );
}

export default App;

'두두의 IT' 카테고리의 다른 글

[Windows] Ubuntu에 java 설치하기  (0) 2022.06.20
MAC + UTM + Ubuntu 설치하기  (0) 2022.06.17
CI(Continuous Integration)/CD(Continuous Delivery/Deployment)란?  (0) 2022.06.15
[DB] Data Storage  (0) 2022.06.15
GraphQL이란?  (0) 2022.05.30