見出し画像

【Gatsby, Stripe, Lambda, Netlify】GatsbyでShop APIをサーバーレスにしたECサイト開発チュートリアル

どうもー、ドイツでフリーランスのエンジニアをしています、Arisaです。

今回は話題のGatsbyを導入したECサイト開発のチュートリアルです。

Gatsbyは話題になっているGraphQLでデータベースも構築できること、フロントエンドもReactコンポーネントで完結してしまうことなど、JSやReactがわかるのであれば非常に便利で、夢のような機能を1つに兼ね備えたPWAです。

データベースをこれから取り扱う予定がなくても、Reactコンポーネントを書く感覚(というかほぼReactを書いているんですが)で、ささっとフロントエンドが整う & スタイルも非常に簡単です。

この辺はcreate-react-appで作るか、Gatsbyかの好みに分かれると思いますが、バックエンドやデータベース、GraphQLもさらに勉強したい私からすれば、今回はGatsbyを採用しました。

これからデータベースも取り扱うかわからないという場合でも、可能性を残しておくことができるので、今後データベース設置が必要かどうかを抜きにしても取り入れて損はないかな?と個人的に思います。

特にECサイトの場合、支払い取引は避けて通れないので、手数料がPayPalよりも少なく、サイト導入のカスタマイズや方法が豊富なStripeの決済方法を最近は取り入れることが多いかもしれません。

決済が伴うのでサイトのSSL化が大前提ですが、GatsbyはStripeとも相性が良く、Stripeの頻繁に使用する決済方法の1つ、checkoutをプラグインでも用意してくれているほどです。

私がGatsbyを気に入った理由はもう1つあって、純Gatsbyだけで構成するサイトの開発の仕方から、Stripeとの組み合わせ & shop APIをサーバーレスにする開発、様々なサーバー使用方法など、公式ドキュメントでのチュートリアルがパッケージのインストールから非常に丁寧に解説してあって充実していること。

正直、初めてGatsbyをお仕事でも使いましたが、Gatsbyの公式ドキュメントにほぼお世話になれば良いだけだったので、非常に開発を進める上で正しい知識が短時間で身につけられたように思います。

唯一の欠点と言えば、英語ソースがメインなので、日本語ソースが少ないことと、まだ勉強するためのオンラインコースが充実していないことでしょうか。
日本語ソースがまだまだ少ないので、英語ソース苦手…という方の補助になれば嬉しいです。
公式ドキュメントは結構ボリュームがあるので、ECサイト構築の手順一連を抜粋してまとめたチュートリアル記事にしてみました。

純粋なフロントエンドのみの開発であれば、無料の範囲で公開しているので、用途に合わせて有料範囲、無料範囲でお選びいただけるようにしています。

というわけで、前置きが長くなりましたが、今回の記事はGatsby, Stripe, Lambda(AWS), Netlifyのコンビネーションで開発したECサイトチュートリアルです。

(※ まずはJavaScriptとReactを理解していることが前提となってくるので、この記事はJS, Reactを使ったことがある人向けになります。)


Gatsbyでフロントエンド周りを整える


開発環境構築

Gatsbyがどういったものかについては、公式ドキュメントにあるのでそちらを参照してください。
この記事ではECサイト構築の流れをできるだけ詳しく書いていきます。

まずは開発するにあたっての環境を準備します。
前提として、Node.jsとnpmがインストールされているかどうかの確認が必要です。
Nodeがインストールされていればnpmも一緒にされていることがほとんどです。

それぞれ 

$ node --version 
$ npm --version

とルートディレクトリでコマンドを書いてバージョンの番号が出てくるかを確認します。
Gitもダウンロードされていなければ、こちらのページからGitをダウンロードします。

上記3つが全て揃ったら、Gatsby CLIというツールをインストールします。

$ npm install --global gatsby-cli

--global フラッグで大丈夫です。

Gatsby CLIは、Gatsbyのコマンドを使用する上で欠かせない存在です。
念のため、Gatsby CLIがきちんとインストールされたのかと、基本的なGatsby CLIのコマンド一覧を見ます。

$ gatsby --version
$ gatsby --help

コマンド一覧が出てくるので、参考程度に見ておくとあとで実際にGatsbyのコマンドを書くときに役立ちます。

早速Gatsbyのスターターを引っ張ってきて、サイト構築の準備をします。

$ gatsby new 作りたいリポジトリ/ディレクトリ名 https://github.com/gatsbyjs/gatsby-starter-hello-world

これでGatsbyで提供されているスターターリポジトリより、自分のパソコン内でこれから作成するGatsbyを使ったECサイトの雛形は手に入りました。

あくまでも超基本的な雛形なので、ここから大幅に自分で書いていく必要はありますが、面倒な環境構築はcreate-react-appのようにすでにGatsby側でしてくれているものを引っ張ってくるだけなので、便利ですね。

早速、ローカル環境に落とし込んだこれから作成するECサイトプロジェクトに手を加えていきます。

まずは基本的な使い方から慣れて、次の章からコンポーネントに慣れていきましょう。

今回は先ほど作成した 作りたいリポジトリ/ディレクトリ名 を gatsby_ec_practice というプロジェクト名にして話を進めていきます。

まず gastby_ec_practice のディレクトリに移動します。

先ほどのスターターリポジトリを引っ張ってきた場所にもよりますが、上記と同じコードであればルートにあるので、

$ cd gastby_ec_practice

で該当ディレクトリに移動。

$ gatsby develop

で、これから作成するECサイトのプロジェクトディレクトリを開発モードの develop で立ち上げます。

コマンドが走ってひと段落したら、http://localhost:8000でブラウザを確認すると現状のサイトが見れます。

スターターリポジトリを引っ張ってきただけなので、Hello, world!ぐらいしかないですが、これから大幅に改良していきます。


Gatsbyスターターを使って、コンポーネントに慣れる

テキストエディタで gatsby_ec_practice ディレクトリを開きます。
/src ディレクトリを開くと /pages/index.js があるのが確認できるので開きます。

超基礎的なReactコードがあるので、反映チェックも兼ねて、 Hello, world! を何か別の文面に変えてブラウザで反映されているかを確認します。

import React from "react"

// 以下をHello world!以外の文面に変更 -> ブラウザで確認
export default () => <div>Hello, world!</div>

hot relodingをGatsbyでは使用しているので、ブラウザをリロードすることなくすぐ反映されます。

では、プラグインを導入しなくても簡単にCSSを使える方法でスタイルを適応させてみます。

import React from "react"

export default () => (
 <div style={{ color: `blue`, fontSize: 25 }}>
   <h1>Gatsby ECサイト</h1>
   <p>プラグインなしでもCSSでスタイル付けできます。</p>
 </div>
)

コンポーネントに関しては、Reactとほぼ同じです。

about.js という別ページを作ってみます。
以下のように書いて、 http://localhost:8000 に /about を追加してブラウザで確認できればOK。

/src/pages/about.js
import React from "react"

export default () => (
  <h1>I am an about.</h1>
  <p>blah blah blah...</p>
)

今度はサブコンポーネントと一緒に、プラグインを使った共通スタイルの設定と、効率の良いCSSのスタイルの書き方を実践します。


サブコンポーネントとTypography.js

サブコンポーネントを使って、ヘッダーを作ってみようと思います。
まず、/src直下でpagesと同じ階層に、componentsというディレクトリを作成します。

componentsの中に、それぞれのページパーツに該当するサブコンポーネントを作成していくので、header.jsという名前のファイルを作ります。
内容は簡単に以下のものを書いてみます。

/src/components/header.js
import React from "react"

export default ({ children }) => (
  <div>
    <h1>I'm a header.</h1>
    {children}
  </div>
)

サブコンポーネントであるヘッダーを、index.jsのメインページにページパーツとして読み込みます。
サブコンポーネントには今はなくても問題ないかもしれませんが、後々childrenの記述がないとエラーが起こるので、注意。

/src/pages/index.js
import React from "react"
import Header from "../components/header"

export default () => (
  <Header />
  <div style={{ color: `blue`, fontSize: 25 }}>
    <h1>Gatsby ECサイト</h1>
    <p>プラグインなしでもCSSでスタイル付けできます。</p>
  </div>
)

ページリンクに飛ばす方法もよく使うので、私は今回使っていませんが、チュートリアルには含めます。
先ほど用意したaboutのページをリンクで紐付けします。

<Link />コンポーネントを読み込んで以下の書き方をするだけで実現可能です。

/src/pages/index.js
import React from "react"
import { Link } from "gatsby"
import Header from "../components/header"

export default () => (
  <Header />
  <Link to="/about/">ABOUT</Link>
  <div style={{ color: `blue`, fontSize: 25 }}>
    <h1>Gatsby ECサイト</h1>
    <p>プラグインなしでもCSSでスタイル付けできます。</p>
  </div>
)

to属性にすることで、http://localhost:8000/about とパスを指定できます。
でもこれだとABOUTのページリンクに飛ぶと...404エラーが出ます。
勘の良い方は気がつかれたと思うのですが、ABOUTのページ自体には、トップページであるindex.jsページへの相互リンクがまだできていないですよね。

ということで、/src/pages/about.jsに以下の記述をします。

/src/pages/about.js
import React from "react"
import { Link } from "gatsby"

export default () => (
  <Link to="/">HOME</Link>
  <h1>I am an about.</h1>
  <p>blah blah blah...</p>
)

これで相互リンクがうまく両方のページで紐付けできたので、404エラーは消えました。
ページを確認するとうまく表示がされています。

さて、プラグインを使ったCSSでスタイルをつけていくまでの前置きはここまでです。
いよいよプラグインを使ってさらに効率よくスタイルをつけていきます。

ここでまずインストールするプラグインは、スタイルの統一設定をしてくれるTypography.jsです。
Typography.jsを先に入れておくことで、CSSで設定したい、例えばスタイルの共通の設定内容を反映させることができるようになります。

ページで統一したいfont-familyやfont-sizeなどには最適ですね。

では早速Typography.jsをインストールします。
今後そのほかのプラグインを適応する際にも同じことが言えますが、Gatsbyでプラグインをインストール -> 適応させるには、

1. npmでインストール
2. gatsby-config.jsファイルに追記

この2つを行います。

Typography.jsをインストールする手順を例に見ると、

$ npm install --save gatsby-plugin-typography react-typography typography

上記でインストールを終えたら、プロジェクトディレクトリのルートにconfigファイルを作成して、以下の記述をしてプラグインを読み込みます。

gatsby-config.js
module.exports = {
 plugins: [`gatsby-plugin-typography`],
}

$gatsby develop でhot reloadingをすると、ディベロッパーツール上にて、headタグ内にTypography.jsが読み込まれているのが確認できます。

では、Typography.jsも少し設定を書いていきます。
まず、src/utils というディレクトリを作り、typography.js というファイルを作成。

src/utils/typography.js
import Typography from "typography"

const typography = new Typography({ baseFontSize: "18px" })

export default typography

このファイルを読み込んで構成して欲しいので、gatsby-config.js ファイルを以下のように編集。

module.exports = {
 plugins: [
   {
     resolve: `gatsby-plugin-typography`,
     options: {
       pathToConfigModule: `src/utils/typography.js`,
     },
   },
 ],
}

新たにプラグインをインストールして読み込んで適応させたら、一度開発モードの $ gatsby developctrl + c (Mac)で切って、また開発モードにすると有効化されます。


ネストしたコンポーネント作成

Layoutのサブコンポーネントを用意することでも、全体のレイアウトをページ間で統一するスタイル設定を行うことができます。
ただ、今回はECサイト構築が目的なので、スタイルを詳しく学ぶには、特にLayoutに関しては公式ドキュメントを参照すると良いです。


CSSでスタイルを整える:CSS-in-JS

人気のCSSスタイルに、CSS-in-JSというライブラリがあります。
主には Glomour と Styled Componentsの2つがありますが、今回はStyled Componentsを簡単に使っていきたいと思います。

CSSモジュールもありますが、こちらはファイルを新たに用意して書くので、container.jsに相当するスタイルに適応するくらいで、あとはCSS-in-JSで書くのがコンパクトでオススメです。

CSSモジュールで用意するcontainer.jsは簡単に説明すると、CSSを書く時にはじめに書く初期化の設定内容などを主には書きます。

src/components という新しいディレクトリを作成して、以下のように構成します。

src/components/container.js
import React from "react"
import containerStyles from "./container.module.css"

export default ({ children }) => (
  <div className={containerStyles.container}>{children}</div>
)

containerコンポーネントに該当するCSSモジュールファイルもこんな感じで作成します。

src/components/container.module.css
.container {
  margin: 4rem auto;
  max-width: 600px;
}

今回は、あとのサブコンポーネントは、Styled Componentsのプラグインをインストールして書いていきます。
スタイルに関しては、Gatsbyは本当に様々な方法で書くことができるので、これは本当に好みによります。

まずはプラグインなので、インストールをしてから、configファイルに追記です。
個人的には、スタイルでいうと他に私はあとでlessも付け足しているので、その場合はこんな感じにconfigファイルは構成されます。

$ npm install --save gatsby-plugin-styled-components styled-components babel-plugin-styled-components
module.exports = {
  siteMetadata: {
    title: "Gatsby Default Starter",
  },
  plugins: [
    {
      resolve: `gatsby-plugin-typography`,
      options: {
        pathToConfigModule: `src/utils/typography.js`,
      },
    },
    `gatsby-plugin-styled-components`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-stripe-checkout`,
    `gatsby-plugin-stripe-elements`,
    {
      resolve: `gatsby-plugin-less`,
      options: {
        javascriptEnabled: true,
        modifyVars: {
          'primary-color': '#2ed1d1',
          'font-family': '"YuGothic", "遊ゴシック", "Open Sans", "Helvetica Neue"',
          'text-color': '#626262'
        }
      },
    },
  ]
}

あとで出てきますが、Stripeのcheckoutのプラグインや、helmetというHTMLでいうheadタグに該当するプラグインも読み込んでいます。

ここで私が気がつかなかったミスは、特にエラーログは出なかったのですが、configファイルの書き方が若干間違っていた点。
はじめの頃は、何を思ったのか、全てのプラグインごとにresolveを書いていましたが、バッククオートだけでよいとわかったので、正しい表記に直しました。

さて、いよいよStyled Componentsの書き方です。
サブコンポーネントに以下のように書いていきます。

src/components/main.js
import React from "react"
import styled from "styled-components"

const MainComponent = styled.div`
  margin: 6.25rem 0;
`

const Title = styled.h1`
  text-align: center;
  font-weight: 100;
  padding: 2.5rem 0 0 0;
`

const Lorem = styled.p`
  text-align: center;
  font-size: 1.1rem;
  padding: 0.75rem 0;
`

export default ({ children }) => (
  <MainComponent>
    <Title>APPLY NOW!</Title>
    <Lorem>
      Lorem ipsum...
    </Lorem>
    {children}
  </MainComponent>
)

こんな感じでその他サブコンポーネントも用意をしたら、サブコンポーネントを呼び出したいページ(先ほど作成したpages/index.jspages/about.js)に読み込みます。

import React from "react"
import Helmet from "react-helmet"
import Favicon from "../components/fav.png"
import Container from "../components/container"
import Layout from "../components/layout"
import Top from "../components/top"
import Main from "../components/main"
import Price from "../components/price"
import Footer from "../components/footer"

const IndexPage = () => (
 <Layout>
   <Helmet link={[
     { rel: 'shortcut icon', type: 'image/png', href: `${Favicon}` }
   ]}>
     <meta property="og:type" content="website" />
     <meta property="og:url" content="https://xxx-xxxxx.com" />
     <meta property="og:title" content="Gatsby ECサイトdemo" />
     <meta property="og:description" content="Gatsby ECサイトdemoです。" />
     <meta property="og:image" content="https://xxx-xxxxx.com/images/sample.png" />
     <meta property="fb:app_id" content="123456789101112" />
     <meta name="twitter:card" content="summary_large_image" />
     <meta name="twitter:title" content="Gatsby ECサイトdemo" />
     <meta name="twitter:description" content="Gatsby ECサイトdemoです。" />
     <meta name="twitter:image" content="https://xxx-xxxxx.com/images/sample.png" />
     <title>Gatsby ECサイトdemo</title>
   </Helmet>
   <Container>
     <Top />
     <Main />
     <Price />
     <Footer />
   </Container>
 </Layout>
)
export default IndexPage

Gatsbyにあるプラグインは、公式ドキュメントより検索可能で、インストールのコマンドも丁寧にほぼ全てのプラグインに書かれているので、そちらを確認してください。


Stripeの決済機能checkoutを取り入れる


gatsby-plugin-stripe-checkoutを入れる

Gatsbyでフロントエンド周りが整ったので、いよいよECサイトの決済機能を実装していきます。

まずはGatsby側ですでに用意してくれているStripe Checkoutのプラグインをインストールして有効化します。(もちろんプロジェクト上のディレクトリで行います)

$ npm install gatsby-plugin-stripe-checkout

先ほどのgastby-config.jsに、インストールしたプラグインを追記をして有効化 -> 開発モードを切ってもう一度 $ gatsby develop


</html>タグの直後にStripeのscriptタグ内容を記述

さて、実はここが私が最もハマったポイントです。
実際の決済ボタンをアウトプットさせるのに絶対欠かせない工程。
でも公式ドキュメントでは、ここがかなりあっさり書かれていたので、気がつかずにいたため、ハマりました。

</html>タグ、もしくは<body>の終わりに以下を記述します。

<script src="https://checkout.stripe.com/checkout.js"></script>

どこに書くかは、人それぞれのプロジェクトで異なりますが、一般的にはHTMLファイルはpublicフォルダにあるので、そこの</html>直後に私の場合は書き加えています。

この記述がないと、StripeのAPIが呼びだせず、404のエラーがディベロッパーツール上に大量に吐き出される状態になります。
ログ自体も、サブコンポーネントが読み込まれていない、と大量に警告を送ってきていますが、実際はStripeのAPIが読み込まれていないので、呼び出せないということがあるので注意。

※ ただし、コマンドライン上ではうまくコンパイルできていて、何もエラーログは吐き出されないです。

公式ドキュメントには、ここだけかなりあっさり書いてあったので、強調しておきます。


決済ボタンのコンポーネント作成

決済のサブコンポーネントの作成ですが、基本的にはStripeの方でほぼ作ってくれているので、Gatsby公式ドキュメントにあるソースコードをお借りして書くだけで実装可能です。

スタイルもすでにStripeが用意してくれたもので、はるかにPayPalよりは良いものが用意されていて、スタイルに関してはデフォルトでも十分なので、ほぼ何もしなくても良いほどです。

決済工程に使われている関数の理解はしておく必要があるので、Stripeのドキュメントと一緒に、以下の関数による工程を確認します。

- ページ読み込み -> 関数configure()
- 一定時間が経ったら...
- ユーザーがボタンをクリック -> 関数open()

ポイントとなる関数、メソッドを工程と一緒にチェックしたら、checkout.js ファイルを作成します。


src/components/checkout.js
import React from "react"
// hardcoded amount (in US cents) to charge users
// you could set this variable dynamically to charge different amounts
const amount = 2500
const cardStyles = {
 display: "flex",
 flexDirection: "column",
 justifyContent: "space-around",
 alignItems: "flex-start",
 padding: "3rem",
 boxShadow: "5px 5px 25px 0 rgba(46,61,73,.2)",
 backgroundColor: "#fff",
 borderRadius: "6px",
 maxWidth: "400px",
}
const buttonStyles = {
 fontSize: "13px",
 textAlign: "center",
 color: "#fff",
 outline: "none",
 padding: "12px 60px",
 boxShadow: "2px 5px 10px rgba(0,0,0,.1)",
 backgroundColor: "rgb(255, 178, 56)",
 borderRadius: "6px",
 letterSpacing: "1.5px",
}
// Below is where the checkout component is defined.
// It has several functions and some default state variables.
const Checkout = class extends React.Component {
 state = {
   disabled: false,
   buttonText: "BUY NOW",
   paymentMessage: "",
 }
 resetButton() {
   this.setState({ disabled: false, buttonText: "BUY NOW" })
 }
 componentDidMount() {
   this.stripeHandler = window.StripeCheckout.configure({
     // You’ll need to add your own Stripe public key to the `checkout.js` file.
     // key: 'pk_test_STRIPE_PUBLISHABLE_KEY',
     key: "pk_test_testAPItestAPItestAPItesAPI",
     closed: () => {
       this.resetButton()
     },
   })
 }
 openStripeCheckout(event) {
   event.preventDefault()
   this.setState({ disabled: true, buttonText: "WAITING..." })
   this.stripeHandler.open({
     name: "Demo Product",
     amount: amount,
     description: "A product well worth your time",
     token: token => {
       fetch(`AWS_LAMBDA_URL`, {
         method: "POST",
         mode: "no-cors",
         body: JSON.stringify({
           token,
           amount,
         }),
         headers: new Headers({
           "Content-Type": "application/json",
         }),
       })
         .then(res => {
           console.log("Transaction processed successfully")
           this.resetButton()
           this.setState({ paymentMessage: "Payment Successful!" })
           return res
         })
         .catch(error => {
           console.error("Error:", error)
           this.setState({ paymentMessage: "Payment Failed" })
         })
     },
   })
 }
 render() {
   return (
     <div style={cardStyles}>
       <h4>Spend your Money!</h4>
       <p>
         Use any email, 4242 4242 4242 4242 as the credit card number, any 3
         digit number, and any future date of expiration.
       </p>
       <button
         style={buttonStyles}
         onClick={event => this.openStripeCheckout(event)}
         disabled={this.state.disabled}
       >
         {this.state.buttonText}
       </button>
       {this.state.paymentMessage}
     </div>
   )
 }
}
export default Checkout


上記の、

 componentDidMount() {
   this.stripeHandler = window.StripeCheckout.configure({
     // You’ll need to add your own Stripe public key to the `checkout.js` file.
     // key: 'pk_test_STRIPE_PUBLISHABLE_KEY',
     key: "pk_test_testAPItestAPItestAPItesAPI",
     closed: () => {
       this.resetButton()
     },
   })
 }

こちらのコード上で、key: の値をStripeアカウントの管理画面からテスト用のAPIキーが取得できるので、公開用のテストAPIキーを pk_test_STRIPE_PUBLISHABLE_KEY となっている箇所に記述します。


ルートとなるページにボタン箇所読み込み

Stripe Checkoutの機能の実装は上記で完了しました。
テスト用のAPIキーも取得して置き換えが完了していますし、あとはサブコンポーネントとして、src/pages/index.js に読み込みを行えばバッチリです。

決済のボタンを押すと、きちんと以下のようにopen()メソッドが立ち上がって、支払い工程前に必要な記述のポップアップが立ち上がるようにもなります。

今の状態は、先ほど置き換えをしたテスト用のAPIキーでの実装なので、サブコンポーネントを読み込むと、上記画像のように、テストモードのCheckout状態になります。

本番環境はこのあと行います。

では、サブコンポーネントとして、index.jsファイルに読み込みましょう。


src/pages/index.js
import React from "react"
import Helmet from "react-helmet"
import Favicon from "../components/fav.png"
import Container from "../components/container"
import Layout from "../components/layout"
import Top from "../components/top"
import Main from "../components/main"
import Checkout from "../components/checkout"
import Price from "../components/price"
import Footer from "../components/footer"

const IndexPage = () => (
 <Layout>
   <Helmet link={[
     { rel: 'shortcut icon', type: 'image/png', href: `${Favicon}` }
   ]}>
     <meta property="og:type" content="website" />
     <meta property="og:url" content="https://xxx-xxxxx.com" />
     <meta property="og:title" content="Gatsby ECサイトdemo" />
     <meta property="og:description" content="Gatsby ECサイトdemoです。" />
     <meta property="og:image" content="https://xxx-xxxxx.com/images/sample.png" />
     <meta property="fb:app_id" content="123456789101112" />
     <meta name="twitter:card" content="summary_large_image" />
     <meta name="twitter:title" content="Gatsby ECサイトdemo" />
     <meta name="twitter:description" content="Gatsby ECサイトdemoです。" />
     <meta name="twitter:image" content="https://xxx-xxxxx.com/images/sample.png" />
     <title>Gatsby ECサイトdemo</title>
   </Helmet>
   <Container>
     <Top />
     <Main />
     <div>
       <Checkout />
     </div>
     <Price />
     <Footer />
   </Container>
 </Layout>
)
export default IndexPage


ここで気がつかれた方もいるかもしれません。

サブコンポーネントの呼び出しが、<div>タグで囲まれていますね。
これはStripeより<div>タグの中に呼び出すよう指定があるためです。

他のサブコンポーネントと同様に<div>タグなしで読み込むと、エラーになる可能性があるので、気をつけましょう。

スタイルは、checkout.jsファイルより調整、編集可能なので、自由にカスタマイズしてもいいですね。


AWS Lambdaを取り入れてShop APIをサーバーレスにする


新しい別のリポジトリ/ディレクトリを作成

先ほどの gatsby_ec_practice のディレクトリとは別に、新たにサーバーレス決済工程用コードのディレクトリを作成します。

こちらのGithubリポジトリをcloneして作成。

$ git clone https://github.com/gillkyle/gatsby-stripe-serverless-backend.git
$ cd gatsby-stripe-serverless-backend


$ npm install とさらにコマンドを打ち込みます。

$ npm install で、Lambdaにアップロードするためのnode_moduleを作成し、ライブラリをAWS上にも上げます。
そうすることで、決済に関する工程が発生した時にもスムーズに切り替えができ、決済工程で発生するサーバーへの負担を大幅に軽減できるので、サーバーレスとなるわけです。


secrets.jsonファイルに名前を変更

重要な手順の1つです。
secrets.example.json というファイルがあるので、このファイルをsecrets.json と名前を変更します。

Gitコマンドにて、このファイルを追跡させないために、ファイル名を変更しました。
バージョン管理などにアップロードする必要がある際には、必ず、このリポジトリはプライベートリポジトリにするか、バージョン管理にはアップロードしないことを勧めます。

なぜかというと、このsecret.jsonファイルには、シークレットキーを含める必要があるからです。

sktestSTRIPESECRETKEY と記述があるので、そこに今はテスト用のAPIキーに置き換えます。
ここを後で本番モードのシークレットキーに置き換える必要があるので、このファイル自体の追跡をさせないようにする必要があるのですね。

このLambdaにアップロードする用のリポジトリにも、checkout.js ファイルがありますが、こちらのファイルは何も編集しなくて大丈夫です。
詳しいこのファイルのコードの役割や動きを知りたいという場合は、Gatsbyの公式ドキュメントにあります。


サーバーレスフレームワークをグローバルにインストール

まずは、サーバーレスのフレームワークをローカル環境にインストールします。

$ npm install -g serverless


AWSでまずはユーザー作成

AWSのコンソールをルートユーザーで使うのはリスクがあることから、ユーザーを作成して、そのユーザーとしてサーバーレスの決済工程を構築します。

これはこれで丁寧に書けば1つの記事ができそうなので、詳しくは以下のソース記事を参考にしていただいて、詳しい設定内容は割愛します。

以下のソース記事に全て詳しく書いてあるので、そのまま設定すればできます。

serverless公式サイト:https://serverless.com/framework/docs/providers/aws/guide/credentials/#creating-aws-access-keys

ユーザー作成の工程でkeyとsecret keyが取得できます。

これからコマンドで使用するので、漏洩しないよう大事に保管しましょう。(AWSでもユーザーを作成した時の一度しか提示してくれません)


AWSの証明書とサーバーレスの構成

準備が整ったので、サーバーレスの構成をしていきましょう。

置き換えが必要になる箇所がコマンドに含まれるので、まずメモ帳など、どこか別のターミナルではない場所で置き換えてから100%確実にコマンドを打ち込むのがオススメです。

以下に書きますが、keyやsecret keyなどAWSユーザー作成によって得られた、ユーザーと紐づいたセンシティブな情報が含まれるので、これを誤ったkeyやsecret keyでコマンドラインのEnterキーを誤って叩いてしまった場合、泣きたくなります←

ちょっと盛りましたが、泣きたくまではならなくても、設定し直しが面倒なので、未然に防げることはしておいたほうが良いですね。

話が逸れましたが、肝心のコマンドは以下です。
必要箇所を置き換えてもらえれば大丈夫です。

$ serverless config credentials --provider aws --key TESTTESTTEST --secret TESTTESTTESTTESTTEST


ただし、場合によってはこのコマンドを叩くと、「すでにデフォルトのプロフィールはある」と怒られることがあります。


その場合は、以下のコマンドで上書きするとうまくいきます。

$ serverless config credentials --provider aws --key esttesttest --secret testtesttest --profile custom-profile --overwrite


デプロイする

今度は、先ほどサーバーレスの工程のためだけに用意をした別リポジトリ、gatsby-stripe-serverless-backend にデプロイをしていきます。
gatsby-stripe-serverless-backend のリポジトリに移動して、以下のコマンドを書きます。

$ serverless deploy

先ほどインストールしたサーバーレスのフレームワークがCLIなので、早速ここで活躍します。

以下のようなログが出れば成功です。

Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service .zip file to S3 (143.3 KB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.................................
Serverless: Stack update finished...
Service Information
service: gatsby-serverless-stripe
stage: dev
region: somewhere on the earth
stack: gatsby-serverless-stripe-dev
api keys:
None
endpoints:
POST - https://xxxxxxxxxxx.com/xxxxx/xxxxxxx
functions:
checkout: gatsby-serverless-stripe-dev-checkout

エンドポイントのURLをコピーして、ECサイトのリポジトリ、gatsby_ec_practice の src/components/checkout.js ファイル内で「AWS_LAMBDA_URL」と表記がある箇所にペースとして置き換えます。

これで、サーバーレスの設定完了です!
あとはテスト環境でログのチェックです。


支払いテストをログで確認

まずはテストモードで支払いが実行されるかどうかを確認します。
この時に大事なのが、Stripeの管理画面にて、支払受け取り先設定をすでに済ませて、本番モードにも切り替えができるようになっていることです。

この設定がなくてもブラウザ上ではエラーログが吐き出されず、うまくいった条件分岐での反応が返されるので表面上はうまくいっていることがわかりますが、支払いのプロセスがうまくいっているかどうかは、ログをコマンドで吐き出させるか、Stripeの管理画面で上記設定を済ませてからテストモードでの支払い機能が稼働しているかをチェックする必要があります。

クライアントからの依頼であれば、自分のスケジュールでStripeの本番環境設定ができないので、ログで見るのが早いです。

ログで確認するには、ブラウザ上でカードナンバー4242 4242 4242 4242に、適当なメールアドレスと3桁の適当なCVC番号を入力して決済ボタンを押した後に、以下のコマンドを書きます。

$ serverless logs -f <function-name> -t

サーバーレスの工程用に用意したリポジトリにある、serverless.yml というファイル内を何も編集していなければ、ログはこんな感じのものが見れると思います。

$ serverless logs -f checkout -t

<function-name> が呼び出されている関数に置き換わるので、支払い工程を担う関数の checkout が呼ばれています。

残すところは、サーバー上にアップロードと本番モードへの切り替えだけになりました!


Netlifyでサーバー設置


Gitを使ってリポジトリと紐付けしたホスティングをする

GatsbyはNetlifyだけでなく、様々なサーバーとの連携がスムーズに行えます。
AWSが好きな人はs3でも良いですし、そのほかであれば以下の選択肢もあります。

- CloudFront
- Aerobatic
- Heroku
- Now
- Gitlab Pages
- Path Prefix

私はサーバー自体のホスティングも無料で、独自ドメインも取得可能 & SSL化も超簡単に設定できて、Gitlab/Github/Bitbucketにpushするだけで連動して更新してくれるNetlifyを推してます。

Gatsbyの公式ドキュメントにもほぼ全ての選択肢でチュートリアルがあるので、そのほかの選択肢を希望する場合は、こちらのGatsby公式ドキュメントページを参考にすると設定しやすいかと思います。
Netlifyのホスティングに関しては、Gatsby公式ドキュメントのこちらにも、もちろん英語のみですが解説があります。

Netlifyには2つのホスティング方法がありますが、開発者側としてはGitlab/Github/Bitbucketと紐付けされたホスティング方法を選ぶと圧倒的に便利です。

もう1つの方法は、Netlifyの管理画面にドラッグ&ドロップでpublicディレクトリをそのままアップロードしてしまう方法ですが、これは編集や変更があった時にまたアップロードし直すのだろうと思うので、何かと不便です。

今回はプライベートリポジトリで上げたいので、Gitlabでホスティングする方法を紹介します。

先にGitlab上のプライベートリポジトリに今まで構築してきたECサイトのリポジトリをpushしておくと便利です。
(サーバーレスのリポジトリはLambdaに上がっているので、ここでは上げない。)

Gitlabのリポジトリにpushするのは、今まで開発モードで行ってきたディレクトリ全てではなく、以下のコマンドでデプロイした後のpublicフォルダのみです。

$ gatsby build

buildが済んだら、publicフォルダをGitlabにpushします。

Netlifyにログインをし、「New site from git」 のボタンを選択し、好みのGitを選びます。
今回はGitlabを選択します。

そうすると、Gitlab上に存在する個人でpushしたリポジトリが出ているので、ECサイトのリポジトリを選択。

項目が以下の内容で出てくるので、それぞれ記入をします。

ブランチの指定:デフォルトはmaster。

Build Command:npm run buildで。

Publish Directory:デフォルトはpublic。

これらの記入が終わったら「Deploy site」のボタンを押します。
ランダムなドメインが割り当てられて、サーバーへのホスティングが完了します。

独自ドメインを取得したい場合は、そのままNetlifyの管理画面にてドメインの項目に行くと、希望のドメイン取得をサーチする画面になります。

取得できる独自ドメインが見つかれば、$9.99/年コストはかかりますが、いつでも必要なくなれば独自ドメインを外してフリーのランダムなドメインに戻せるので、必要な時だけ取得をして紐付けをすることも可能です。

支払い情報を記載したら、SSL化の設定をします。

こちらも非常に簡単で、SSL化の項目が管理画面にあるので、移動をして書いてある指示に従って設定を行うと、数分で反映されます。
ここで画面がsuccessになかなか切り替わらない場合は、ブラウザをリロードをするとSSL化が完了していることが多いです。

ここまで10分ほどで全てGitとの紐付け、サーバーへのホスティング、独自ドメイン取得、SSL化が完了してしまいました。

残すところ、あとは本番モードに切り替えるだけとなりました。


Stripeを本番環境モードにする

本番モードにStripeを切り替えるには、Stripeの管理画面にて、支払い受け取り先の情報(銀行)を設定して、本番環境モードが有効化する必要があります。

有効化ができれば、ECサイト開発中(ディレクトリ:gastby_ec_practice)に記入をしたテスト用APIキーを本番用APIキーに置き換えるのと、Lambdaに上げたサーバーレスのディレクトリにある、secret.jsonにも記入したテスト用APIキーを本番用APIキーに置き換えをします。

これで完成です!

お疲れ様でした。


まとめ

どうでしたか?

Gatsbyを使用したweb開発のソースはまだまだ英語しかなく、ECサイト開発を含めた情報や、オンラインコースなどもまだまだ英語、もしくは多言語での提供で少数しかされていないので、本記事が少しでも皆さんの理解に役立つことができれば幸いです。

ReactやJS (ES6) を学習されている人であれば、理解できることが非常に多いので、ぜひ今後の開発に役立ててみてください。

では、Tschüss :)


この記事が気に入ったらサポートをしてみませんか?