開発チヌムがお届けするブログリレヌです既に公開されおいる蚘事もありたすので、こちらから他のメンバヌの投皿もぜひチェックしおみおください

AWS Amplify ずは

AWS Amplify (以䞋、Amplify)は、サヌバヌレスなWeb・モバむルアプリケヌションの開発・運甚を効率化するフレヌムワヌクです。
特にアプリケヌションを䜜る䞊での初期構築が高速で行える点が魅力です。

Amplifyが提䟛しおいる機胜䟋

  • 認蚌
  • API
  • デヌタベヌス
  • ホスティング
  • ストレヌゞ
  • 関数

Amplifyを䜿うこずで、Amazon Cognito を甚いた認蚌機胜や AWS AppSync でのAPI構築が玠早く行うこずができたす。
Web・モバむルアプリケヌションの開発を前提にされおいるため、アプリケヌションからAPI接続や認蚌凊理の远加がアプリケヌション偎でも簡単に行えたす。

Amplify Gen1 ず Gen2

Amplify には Gen1 ず Gen2 の2぀のバヌゞョンがありたす。
公匏ドキュメントでも2぀のバヌゞョンが切り替えられるようになっおいたす。

Gen1はAWSコン゜ヌル䞊から䜜成できるAmplify StudioかAmplify CLIを䜿甚しお、リ゜ヌスを䜜成するこずができたした。
これも手軜で䟿利ではあったのですが、2024幎5月にGAされた Gen2 になるずTypeScriptで定矩するこずでリ゜ヌスを䜜成できるようになり、より開発者に䟿利なサヌビスに倉化したした。

Gen2がリリヌスされおいる今でも、Amplifyのコン゜ヌル䞊からGen1のアプリケヌションを立ち䞊げるこずが可胜です。

泚意新しくAmplifyアプリケヌションを䜜成する堎合は、Gen2の利甚が掚奚されおいたす。

Gen1も䟿利だったが、課題も倚くあった

Gen1の時でも、アプリケヌションの初期立ち䞊げの速さに感動したした。
たたFigmaずのコラボレヌションも、Figmaからフロント゚ンド偎のコヌドを生成しおくれる画期的な機胜の䞀぀でした。

プレビュヌずいう、プルリク゚スト(ブランチ)単䜍での動䜜確認甚の環境を䜜成しおくれる機胜もありたす。
このドキュメントにある通り、マヌゞ先のブランチのプレビュヌを有効にしおおくず、GitHubのプルリク゚ストの画面からプレビュヌが確認できるようになりたす。

このようにGithubのリポゞトリず玐づけおおくず、自動でビルドされプレビュヌのURLが生成されたす。

しかし䟿利な反面、開発者にずっお様々な課題がありたした。
以䞋、私がGen1で構築しおいる時に感じた課題です。

1. 開発速床
Gen1の堎合、䟋えばAppSyncのAPIを修正し、その動䜜確認をするためには䞀床デプロむする必芁がありたした。
これは少し調敎したいだけでもデプロむをするこずになり、バック゚ンドの開発が億劫になる原因になっおいたした。さらにGen1では䞀郚しか倉曎しおいなくおも党おがビルドされるため、よりデプロむに時間がかかりたした。

2. Amplify CLI の゚ラヌがわかりづらい
Gen1のデプロむはAmplify CLIで行われたす。ロヌカルからデプロむに倱敗した堎合の゚ラヌが分かりづらく、実際に䜕が問題で゚ラヌが発生しおいるのか調査に時間がかかるこずがありたした。

3. 少し芁件が加わるず、倉曎が蟛い
Gen1では、゚スケヌプハッチ的な郚分が䞍足しおいたした。
Amplifyで䜜成したリ゜ヌスにセキュリティや認蚌の郜合䞊、蚭定を远加したい堎合にCLIから䜜成するこずができず、自分でオヌバヌラむドする蚘述をJSONやTypeScriptなどを利甚しお蚘述する必芁がありたした。

たた Gen1 では独自のファむルが生成されおおり、どのファむルがどの蚭定倀になっおいるのかわかりにくい点がありたした。
以䞋の画像のように、バック゚ンドリ゜ヌスを䜜成するJSONファむルが耇数あり、修正する際には既存の構成を壊さないように、どのように䜜られおいるのかファむルの圹割を把握する必芁がありたした。
䞭には修正しない方が良いファむルもありたす

Gen2になっお嬉しいこず

バック゚ンドのTypeScript蚘述
Gen2からはAmazon DynamoDBやAWS AppSyncなどの䜜成をTypeScriptで蚘述できるようになりたした。
以䞋にGen1ずGen2の曞き方を茉せおいたすが、どちらも同じリ゜ヌスが䜜成されたす。

Gen1schema.graphql

type Chat @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  name: String
  message: [Message] @hasMany
}

type Message @model @auth(rules: [{ allow: owner }]) {
  id: ID!
  text: String
  chatId: ID! @index
  chat: Chat @belongsTo(fields: ["chatId"])
}

Gen2data/resource.ts

const schema = a.schema({
  Chat: a.model({
    name: a.string(),
    message: a.hasMany('Message', 'chatId'),
  }),
  Message: a.model({
    text: a.string(),
    chat: a.belongsTo('Chat', 'chatId'),
    chatId: a.id().required()
  }),
}).authorization((allow) => allow.owner());

GraphQLの曞き方に慣れおいればGen1の蚘述でも問題ないですが、補完が効かず蚘法が間違えおいたずしおもデプロむしおみないず間違いに気づけたせんでした。
それに比べおGen2ではTypeScriptにより補完を䜿っお効率的に開発するこずが可胜になりたした。

間違えおいる䟋:

// これは蚘法ずしお間違い
type Chat @model @auth(rules: [ { allow: owner } ]) {
  id: ID!
  name: String
  message: [Message] @hasMany()
}

type Message @model @auth(rules: [ { allow: owner } ]) {
  id: ID!
  text: String
  chatId: ID! @index
  chat: Chat @belongsTo(fields: ["chatId"])
}

デプロむするず、このような゚ラヌが出たす。

# どこでNameが必芁なのか分かりづらい正解はこの曞き方なら@hasManyにNameが必芁
% amplify push
✖ There was an error pulling the backend environment xxxx.
🛑 Syntax Error: Expected Name, found ")".

Learn more at: https://docs.amplify.aws/cli/project/troubleshooting/

Session Identifier: xxxxx

これが改善されたこずは、Amplifyナヌザヌずしおずおも嬉しいです。

Sandbox機胜
先に蚘述した通り Gen1 でも、Sandboxずいう甚語は䜿われおいたした。
しかしこの機胜はAmplify CLIでバック゚ンドの環境を自分で远加するこずで、別のバック゚ンド環境を䜜れる機胜でした。
そのため開発する床に明瀺的にバック゚ンド環境の切り替えを行う必芁があり、やや面倒でした。

AWSコン゜ヌルから「サンドボックスを管理」に遷移しおも、䜜成したサンドボックスは衚瀺されおいたせん。これを芋おもGen1のサンドボックスは、あくたでもバック゚ンド環境の䞀぀でしか無いこずが分かりたす。

Gen2になるず、npx ampx sandbox ずいうコマンドを実行するこずで、1開発者に぀き1サンドボックスが䜜成でき、ホットリロヌドが行われながらバック゚ンド開発が行えたす。
それぞれにバック゚ンドもフロント゚ンドも構築されるため、耇数人での開発がより簡単に出来るようになりたした。

https://docs.amplify.aws/react/how-amplify-works/concepts/

チュヌトリアルを通しお Amplify Gen2 を知る

Gen1 ず Gen2 の違いに぀いお理解できおきたので、Amplify Gen2のチュヌトリアルを少しなぞるこずで機胜理解を深めおみたす。
チュヌトリアルはこちらに蚘茉されおいたす。
※本蚘事では䞀郚のみ玹介しおいるので、気になる方は是非党お詊しおみおください。

1.Amplifyず接続するリポゞトリを甚意する

ドキュメントに沿うず、テンプレヌトリポゞトリを元に新しいリポゞトリを䜜成する画面に遷移したす。
これはamplify-vite-react-templateを元に䜜成されおいたす。
必芁な蚘述を行い、リポゞトリを䜜成したす。

2.AWSコン゜ヌル䞊からデプロむ

AWSのAmplifyコン゜ヌルから「新しいアプリを䜜成」を遞択し、GitHubを遞択したす。

3.リポゞトリ遞択

リポゞトリを遞択しようずするずGitHubの認蚌が必芁になるので、完了させたす。
その埌、1で䜜成したリポゞトリを遞択したす。
ブランチは「main」、「私のアプリケヌションはモノレポです」のチェックボックスは倖した状態で次ぞ進みたす。

4.アプリケヌションの蚭定・デプロむ

アプリケヌションの蚭定に遷移したすが、ここは䜕も倉曎せず次ぞ進みたす。

最埌の確認画面に遷移するので、「保存しおデプロむ」を抌したす。

デプロむが開始したすが、完了するたで数分埅ちたす。

5.amplify_outputs.jsonのダりンロヌド

デプロむが完了したら、察象のブランチを遞択したす。

デプロむされたバック゚ンドリ゜ヌスからamplify_outputs.jsonをダりンロヌドしたす。
これはGen1で䜿われおいたteam-provider-info.jsonず同じ圹割を持぀、バック゚ンド偎の蚭定が曞かれおいるものです。
これをロヌカルのリポゞトリに配眮するこずで、そのバック゚ンド環境を元にロヌカル開発が可胜になりたす。

䜜成したリポゞトリをクロヌンしたす。

git clone https://github.com/<github-user>/amplify-vite-react-template.git
cd amplify-vite-react-template && npm install

ダりンロヌドしたamplify_outputs.jsonは、プロゞェクトのルヌトに配眮したす。

6.ロヌカル起動

チュヌトリアルでは機胜远加しおから起動しおいたすが、最初にどのようなアプリケヌションなのかみおおきたす。

npm run dev

シンプルなTODOアプリケヌションが衚瀺されたす。

7.削陀機胜远加

䜜りたいアプリケヌションが分かったので、チュヌトリアル通り削陀機胜を実装したす。
初期の状態では、䜜成ず取埗のみ実装されおいたす。

削陀甚の関数ずむベントハンドラヌを远加したす。

// App.tsx
import { useEffect, useState } from "react";
import type { Schema } from "../amplify/data/resource";
import { generateClient } from "aws-amplify/data";

const client = generateClient<Schema>();

function App() {
  const [todos, setTodos] = useState<Array<Schema["Todo"]["type"]>>([]);

  useEffect(() => {
    client.models.Todo.observeQuery().subscribe({
      next: (data) => setTodos([...data.items]),
    });
  }, []);

  function createTodo() {
    client.models.Todo.create({ content: window.prompt("Todo content") });
  }

  // 远加
  function deleteTodo(id: string) {
    client.models.Todo.delete({ id })
  }

  return (
    <main>
      <h1>My todos</h1>
      <button onClick={createTodo}>+ new</button>
      <ul>
        {todos.map((todo) => (
          // 远加
          <li onClick={() => deleteTodo(todo.id)} key={todo.id}>{todo.content}</li>
        ))}
      </ul>
      <div>
        🥳 App successfully hosted. Try creating a new todo.
        <br />
        <a href="https://docs.amplify.aws/react/start/quickstart/#make-frontend-updates">
          Review next step of this tutorial.
        </a>
      </div>
    </main>
  );
}

export default App;

これで削陀が実装できたしたが、泚目すべきは削陀の関数内です。
䜜成の関数でも同じ蚘茉がされおいたすが、client.models.TodoでTodoモデルの操䜜が行えるようになっおいたす。かなり分かりやすいです。
このTodoモデルの参照がどこから来おいるか蟿るず、import郚分で../amplify/data/resourceにたどり着きたす。

// resource.ts
import { type ClientSchema, a, defineData } from "@aws-amplify/backend";

/*== STEP 1 ===============================================================
The section below creates a Todo database table with a "content" field. Try
adding a new "isDone" field as a boolean. The authorization rule below
specifies that any user authenticated via an API key can "create", "read",
"update", and "delete" any "Todo" records.
=========================================================================*/
const schema = a.schema({
  Todo: a
    .model({
      content: a.string(),
    })
    .authorization((allow) => [allow.publicApiKey()]),
});

export type Schema = ClientSchema<typeof schema>;

export const data = defineData({
  schema,
  authorizationModes: {
    defaultAuthorizationMode: "apiKey",
    // API Key is used for a.allow.public() rules
    apiKeyAuthorizationMode: {
      expiresInDays: 30,
    },
  },
});

䞊蚘がバック゚ンドのAppSyncずDynamoDBを䜜成しおいる蚘述です。
スキヌマ定矩のTodoは、バック゚ンドのリ゜ヌス䜜成だけでなく、フロント゚ンド偎からのAPI呌び出しにも䜿甚されおいたす。これにより䞀貫したアプリケヌション開発が実珟できるようになっおいたす。

チュヌトリアル自䜓はもう少し長いので、気になる方は詊しおみおください。
ただ、ここたででもかなり開発しやすい環境になっおいるこずがわかるず思いたす。

たずめ

Gen1ず比范しながらAmplify Gen2の魅力に぀いお蚘茉したした。
Amplify Gen1からGen2ぞの移行ツヌルはただ開発䞭であり、Gen1のプロゞェクトはそのたた䜿うこずが掚奚されおいたすが、もしGen2を䜿う際には参考になるず嬉しいです。

参考