OpenJS Architect를 사용하여 서버 없는 전체 영화 추적기를 구축하는 방법 - 제1부분

30698 단어

우리 뭐 짓고 있어?


본고에서 저는 AWS 서버 없는 서비스를 사용하는 완전한 응용 프로그램의 시작을 소개할 것입니다. 이 응용 프로그램은 완전한 데이터베이스, 세션 지원, GitHub OAuth 로그인을 갖추고 개발할 때 점진적인 강화를 고려할 것입니다.이 프로그램은 로그인한 사용자에게 영화 목록을 제공합니다.모든 영화가 관람되었는지 여부를 밝히기 위해 검사를 받을 수 있다.그래서 네가 본 모든 Nic Cage 영화를 추적할 수 있어.

우리가 필요로 하는 도구


이 프로그램은 노드를 요구할 것입니다.js, OpenJS Architect, 당신이 가장 좋아하는 텍스트 편집기, 기본적인 자바스크립트 지식, 그리고 Git를 어떻게 사용하는지.오, GitHub 계정이 하나 더 있어요.
Architect는 AWS에서 서버 웹 응용 프로그램이 없는 소스 배포 프레임워크입니다.Lambda 함수, API 게이트웨이, DynamoDB를 설정할 때 복잡성을 많이 숨깁니다.

새 설계자 프로젝트를 만들고 시작할 때 CI/CD를 설정합니다.


시작하려면 아래 버튼을 클릭하여 15초 이내에 배포하십시오.

GitHub 자격 증명에 로그인하여 사용하기 시작하면 계정에 새 재구매 계약이 만들어집니다.당신의 CI/CD가 완성되었습니다!기본 분기에 제출할 때마다 staging 환경이 새로 생성됩니다.
로컬에서 시작하려면 복제 재구매 및 실행 npm i을 실행하십시오.

코드, 응용 프로그램의 기초 구조로 삼다.원호형 줄

app.arc 파일을 보고 다음과 같이 수정합니다.
@app
example-movie-tracker

@static

@http
get /
get /login
post /logout
post /watched

@tables
data
  scopeID *String
  dataID **String
  ttl TTL
app.arc 파일을 수정한 후 명령줄에서 arc init을 실행하여 함수를 구축합니다.

GitHub OAuth 및 환경 변수


이제 GitHub OAuth를 실현해 봅시다.우리는 환경 변수를 설정하고 일부 파일을 수정해야 한다.
환경 변수를 사용하면 타사 API 키와 URL 같은 민감한 상태를 응용 프로그램 코드에 하드코딩하지 않고도 매개 변수화할 수 있습니다.
우선, follow these instructions에 새 OAuth 프로그램을 등록하십시오.다음을 확인해야 합니다.

프로젝트 루트 디렉토리의 GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRETGITHUB_REDIRECT 파일에 저장해야 합니다.구조자는 파일을 읽고 런타임 시 환경 변수를 Lambda에 로드합니다.파일은 다음과 같습니다.
#prefs.arc

@env
testing
  GITHUB_CLIENT_ID <your-client-id>
  GITHUB_CLIENT_SECRET <your-client-secret>
  GITHUB_REDIRECT http://localhost:3333/login
이것은 prefs.arc을 실행하여 현지에서 일할 수 있도록 합니다.배포된 어플리케이션에서 실행하려면 npm startstaging에 새 OAuth 어플리케이션을 만들고 Begin 콘솔에서 새로운 환경 변수 세트를 업데이트해야 합니다.

OAuth 로그인 흐름 구현


이제 GitHub의 OAuth 로그인 흐름을 처리하기 위해 코드를 작성할 수 있습니다.
우선, 우리는 production 함수를 작성할 것이다.
// src/http/get-login/index.js

const arc = require('@architect/functions')
const github = require('./github')

exports.handler = arc.http.async(login)

async function login(req) {
  let account
  if (req.query.code) {
    try {
      account = await github(req)
    } catch (err) {
      return {
        statusCode: err.code,
        body: err.message
      }
    }
    return {
      session: { account },
      location: '/'
    }
  } else {
    return {
      location: '/'
    }
  }
}
get-login 함수는 GitHub 응용 프로그램이 성공적으로 검증된 후 리디렉션된 위치입니다.
만약 우리가 성공적으로 신분 검증을 진행한다면, 되돌아오는 코드를 사용하여 GitHub의 API에서 계정 데이터를 검색할 수 있습니다.
  • get-login
  • 및 코드를 사용하여 GitHub API
  • 에서 사용자 계정 검색
  • 마지막으로 계좌가 있으면 돌려드리겠습니다.
  • 또한 GitHub의 특정 논리를 포함하는 req.query.code 모듈을 만듭니다.이 github.js은 GitHub에서 계정 데이터를 검색하는 데 사용됩니다.
  • 우선 GitHub OAuth 서비스에 인증 코드를 사용하여 액세스 토큰
  • 을 검색합니다.
  • 그리고 저희는 권한 수여 헤더로 설정된 방문 영패를 사용하여 계정 데이터를 검색합니다.
  • 마지막으로 계정 데이터나 받은 오류를 반환합니다.
  • // src/http/get-login/github.js
    
    const tiny = require('tiny-json-http')
    
    module.exports = async function github(req) {
      try {
        let result = await tiny.post({
          url: 'https://github.com/login/oauth/access_token',
          headers: { Accept: 'application/json' },
          data: {
            code: req.query.code,
            client_id: process.env.GITHUB_CLIENT_ID,
            client_secret: process.env.GITHUB_CLIENT_SECRET,
            redirect_url: process.env.GITHUB_REDIRECT
          }
        })
        let token = result.body.access_token
        let user = await tiny.get({
          url: `https://api.github.com/user`,
          headers: {
            Authorization: `token ${token}`,
            Accept: 'application/json'
          }
        })
        return {
          token,
          name: user.body.name,
          login: user.body.login,
          id: user.body.id,
          url: user.body.url,
          avatar: user.body.avatar_url
        }
      } catch (err) {
        return {
          error: err.message
        }
      }
    }
    
    다음에, 우리는 github.js 함수에auth 구성 요소를 만들 것이다
    // src/http/get-index/index.js
    
    const arc = require('@architect/functions')
    
    exports.handler = arc.http.async(http)
    
    function authControl(account) {
      if (account && account.name) {
        return `
        Welcome back ${account.name}
        <form action=/logout method="post">
        <button>Logout</button>
        </form>`
      } else {
        let clientID = process.env.GITHUB_CLIENT_ID
        let redirectURL = process.env.GITHUB_REDIRECT
        let href = `https://github.com/login/oauth/authorize?client_id=${clientID}&redirect_url=${redirectURL}`
        return `
        <a href='${href}'>Login with GitHub</a>
        `
      }
    }
    
    async function http (req) {
    
      return {
        html: `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Praise Cage</title>
    </head>
    <body>
    <h1>Praise Cage</h1>
    
    ${ authControl(req.session.account) }
    
    </body>
    </html>
    `
      }
    }
    
    현재 우리는 세션 대상을 지우고 사용자를 취소할 수 있는 get-index 프로세서를 만들 수 있습니다.
    // src/http/post-logout/index.js
    
    let arc = require('@architect/functions')
    
    async function logout(req) {
      return {
        session: {},
        location: '/'
      }
    }
    
    exports.handler = arc.http.async(logout)
    

    테스트 인증


    현재 우리는 post-logout을 실행하여 현지에서 우리의 응용 프로그램을 테스트할 수 있다.GitHub 자격 증명을 사용하여 로그인할 수 있는 링크가 표시되어야 합니다.

    우리 npm 가동 노선 구축


    이제 UI를 계속 구축할 때입니다.우리는 데이터베이스에 있는 모든 단점에서 데이터를 얻을 것이다.
    // src/http/get-index/index.js
    
    let arc = require('@architect/functions')
    let data = require('@begin/data')
    
    exports.handler = arc.http.async(http)
    
    function authControl(account) {
      if (account && account.name) {
        return `
        Welcome back ${account.name}
        <form action=/logout method="post">
        <button>Logout</button>
        </form>`
      } else {
        let clientID = process.env.GITHUB_CLIENT_ID
        let redirectURL = process.env.GITHUB_REDIRECT
        let href = `https://github.com/login/oauth/authorize?client_id=${clientID}&redirect_url=${redirectURL}`
        return `
        <a href='${href}'>Login with GitHub to see a list of movies</a>
        `
      }
    }
    
    function movie({ key, watched, title }) {
      return `<form action="/watched" method="post">
        <input type="hidden" name="movieId" value="${key}">
        <input type="checkbox" name=watched ${ watched? 'checked' : ''}>
        ${title}
        <button>Save</button>
      </form>`
    }
    
    async function getMovies(account) {
      let movies = [
        {key: '001', title: 'Raising Arizona'},
        {key: '002', title: 'Con Air'},
        {key: '003', title: 'National Treasure'},
      ]
      if (account) {
        let accountMovies = await data.get({
          table: `${account.id}-movies`
        })
        console.log('found account movies', accountMovies)
        let result = ''
        for (let mov of movies) {
          let found = !!(accountMovies.find(m=> m.key === mov.key))
          result += movie({key: mov.key, title: mov.title, watched: found })
        }
        return result
      }
      return ''
    }
    
    async function http (req) {
    
      return {
        html: `
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Praise Cage</title>
    </head>
    <body>
    <h1>Praise Cage</h1>
    
    ${ authControl(req.session.account) }
    ${ await getMovies(req.session.account) }
    
    <script src=/_static/index.js type=module></script>
    </body>
    </html>
    `
      }
    }
    
    우리는 두 가지 함수를 추가했다. 그것이 바로 get-indexget-index이다.이러한 함수는 일부 매개변수를 적용하고 HTML 문자열을 반환합니다.이러한 기능 구성 요소를 사용하여 더 큰 프레임워크 없이 UI를 구축할 수 있습니다.

    getMovies를 사용하여 본 영화를 DynamoDB에 저장


    우리는 movies을 DynamoDB 클라이언트로 사용하여 본 영화를 모든 사용자의 계정에 저장합니다.
    // src/http/post-watched/index.js
    
    const arc = require('@architect/functions')
    const data = require('@begin/data')
    
    exports.handler = arc.http.async(route)
    
    async function route(req) {
      console.log('post-watched:', req.body)
      let account = req.session.account.id
    
      if (req.body.watched) {
        await data.set({
          table: `${account}-movies`,
          key: req.body.movieId
        })
      } else {
        await data.destroy({
          table: `${account}-movies`,
          key: req.body.movieId
        })
      }
    
      return {
        location: '/'
      }
    }
    
    다음 섹션에서는 클라이언트 자바스크립트를 사용하는 방법에 대해 설명합니다.이 웹 사이트는 JavaScript가 비활성화된 경우에도 작동하도록 단계적으로 강화할 것입니다.

    좋은 웹페이지 즐겨찾기