Azure Static Web Appsを使ってみる(2)Reactアプリ+Azure Functionsの構成でアプリを動かす

はじめに

先日からAzure Static Web Appsを使ってみています。単なるHTMLだけではなく、ReactやVueなどで作られたページもホスティングでき、APIとしてAzure Functionsも動かすことができるというものということで、実際に試してみています。

前回はReactのチュートリアルであった三目並べを動かしてみました。

miyohide.hatenablog.com

今回はAzure Functionsとの連携を試してみたいと思います。

Azure Static Web AppsでのAzure Functions

Azure Static Web AppsでのAzure Functionsは、以下のドキュメントが示すように二種類の利用方法があります。

  • マネージド関数
  • 独自の関数の持ち込み

docs.microsoft.com

色々と自由度が高いのは「独自の関数の持ち込み」ですが、今回はお手軽に試すために「マネージド関数」を使って実装したいと思います。

なお2021年11月の時点で、マネージド関数のデプロイ先は以下の画像のように「Central US」「East US 2」「East Asia」「west Europe」「West US 2」の5つに限られていました。時が解決するとは思いますが、Japan Eastへのデプロイが必要な場合は「独自の関数の持ち込み」を利用する必要がありそうです。

f:id:miyohide:20211128114651p:plain

マネージド関数を使ってAPIを実装する

マネージド関数を使ってAPIを実装します。以下のドキュメントにチュートリアルが書かれていますので、これを参考にして作っていきます。

docs.microsoft.com

以下のように、JSONデータを返す簡単なAPIにしました。

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');
    context.res = {
        headers: {
            "Content-Type": "application/json"
        },
        body: [
            {id: 1, title: "title1", body: "body1"},
            {id: 2, title: "title2", body: "body2"},
            {id: 3, title: "title3", body: "body3"},
        ]
    }
};

Reactアプリを作る

APIを呼び出すReactアプリを作ります。以下のサイトを参考に実装していきました。

qiita.com

CSSは私が慣れているReact Bootstrapを利用しました。

react-bootstrap.github.io

APIの呼び出し部分の実装は以下の通りです。API/api/postとしているので、このAPIaxiosを使って呼び出します。

import React, {useEffect, useState} from 'react';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import BodyCard from './BodyCard';
import axios from 'axios';

function Content() {
  // Reactのステートフックを利用してstate変数であるpostを初期化し、
  // 更新するsetPosts関数を取得する。
  // ここでは、postを[]で初期化する
  const [post, setPosts] = useState([])

  // useEffectを利用してJSONデータを取得してsetPostsでstate変数である
  // postを更新する
  useEffect(() => {
    axios.get('/api/post')
    .then(res => {
      setPosts(res.data)
    })
  }, [])

  // 名前付き関数(アロー関数式を使った記述)
  const getCardContent = getObj => {
    return (
      <Col key={getObj.id}>
        {/* スプレッド構文。getObjのすべての要素をBodyCardのproperty(props)に渡す */}
        <BodyCard {...getObj} />
      </Col>
    );
  };
  return (
    <Container>
      <Row xs={1} md={3} className="g-2">
        {/* map() は与えられた関数を配列の全ての要素に対して呼び出し、
            その結果からなる新しい配列を生成する
        */}
        {post.map(contentObj => getCardContent(contentObj))}
      </Row>
    </Container>
  );
}

export default Content;

データ表示を行なっているBodyCardは以下のような実装です。

import React from 'react';
import Card from 'react-bootstrap/Card';

function BodyCard(props) {
  // 分割代入。オブジェクト(props)の各プロパティに対応した
  // 変数に代入する。
  // see. https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
  const { title, body } = props;

  return (
    <Card>
      <Card.Body>
        <Card.Title>{title}</Card.Title>
        <Card.Text>
          {body}
        </Card.Text>
      </Card.Body>
    </Card>
  );
}

export default BodyCard;

全体実装は、末尾に載せているGitHubリポジトリを参照してください。

デプロイ

Azure Static Web AppsへのデプロイはGitHub ActionsかAzure DevOpsを利用する必要があります。前回はWebアプリだけをデプロイしましたが、そこからの差分はapi_locationを追加しただけです。以下のような実装になりました。

name: Azure Static Web Apps CI/CD

on:
  push:
    branches:
      - main

jobs:
  build_and_deploy_job:
    runs-on: ubuntu-latest
    name: Build and Deploy Job
    steps:
      - uses: actions/checkout@v2
      - name: Build and Deploy
        id: builddeploy
        uses: Azure/static-web-apps-deploy@v1
        with:
          azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN }}
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          action: "upload"
          app_location: "posts"
          api_location: "api"
          output_location: "build"

動作確認

デプロイした後にAzure Static Web AppsのURLにアクセスすると無事動いていることが確認できました。

f:id:miyohide:20211128114452p:plain

Azure Portal上でAzure Static Web Appsの「設定」-「関数」をみると、今回デプロイした「post」が表示されていました。ただ、これは表示されているだけで、クリックしても何も動作しませんでした。

f:id:miyohide:20211128114832p:plain

現在のソース

github.com