Amplify Gen2がGAとなり、CLIのコマンドが変更になりました

2024.05.07

NTT東日本の中村です。

プレビュー版であるAmplify Gen2のバージョンがGAとなり、コマンドの変更など、いくつかの大きな変更が発生しているようです。

変更の概要

@aws-amplify/backendのモジュールからbetaの文字が無くなり、1.0.0にバージョンが上がっています。

% npm info @aws-amplify/backend
@aws-amplify/backend@1.0.0 | Apache-2.0 | deps: 13 | versions: 70
This package is the entry point for customers to define their Amplify backend using `defineBackend`. It also pulls in functions for defining other feature verticals.

dist
.tarball: https://registry.npmjs.org/@aws-amplify/backend/-/backend-1.0.0.tgz
.shasum: da74d13159db782191684964dd3e9b3ddb958714
.integrity: sha512-QKLdTFtXnff4VUHmZBs+XK3xeXe0TZAZkR4Ke2kwWo6engaYahZ3UQO7Ndkt1D/xcq08e4QayGgRB+XGr7B8Wg==
.unpackedSize: 174.4 kB

dependencies:
@aws-amplify/backend-auth: ^1.0.0           @aws-amplify/client-config: ^1.0.0          
@aws-amplify/backend-data: ^1.0.0           @aws-amplify/data-schema: ^1.0.0            
@aws-amplify/backend-function: ^1.0.0       @aws-amplify/platform-core: ^1.0.0          
@aws-amplify/backend-output-schemas: ^1.0.0 @aws-amplify/plugin-types: ^1.0.0           
@aws-amplify/backend-output-storage: ^1.0.0 @aws-sdk/client-amplify: ^3.465.0           
@aws-amplify/backend-secret: ^1.0.0         lodash.snakecase: ^4.1.1                    
@aws-amplify/backend-storage: ^1.0.0        

maintainers:
- amplify-data-dev-npm <amplify-data-dev+npm@amazon.com>
- amplify-studio-uibuilder <aws-amplify-uibuilder@amazon.com>
- amplify-codegen <amplify-codegen+npm@amazon.com>
- amzn-oss <osa-3p@amazon.com>
- undefobj <rthrelkeld1980@gmail.com>
- aws-amplify-ops <aws-amplify@amazon.com>
- manuel.iglesias <manuel.iglesias@gmail.com>
- thaddmt <thaddmt@gmail.com>
- mattsb42-aws <bullocm@amazon.com>

dist-tags:
alpha: 0.1.1-alpha.0             latest: 1.0.0                    
beta: 0.13.0-beta.20             test: 0.0.0-test-20240327212405  

published 13 hours ago by aws-amplify-ops <aws-amplify@amazon.com>
diff --git a/package.json b/package.json
index 38ed219..8a7878f 100644
--- a/package.json
+++ b/package.json
-    "@aws-amplify/backend": "^0.13.0-beta.14",
-    "@aws-amplify/backend-cli": "^0.12.0-beta.16",
+    "@aws-amplify/backend": "^1.0.0",
+    "@aws-amplify/backend-cli": "^1.0.1",

参考までに、5/2時点で チュートリアルに従い、NextJS(Server Components)で、npm create amplify@latestを実行した時の package.jsonです。

{
  "name": "next-amplify-gen2",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "aws-amplify": "^6.2.0",
    "next": "14.1.0",
    "react": "^18",
    "react-dom": "^18"
  },
  "devDependencies": {
    "@aws-amplify/backend": "^1.0.0",
    "@aws-amplify/backend-cli": "^1.0.1",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "aws-cdk": "^2.139.1",
    "aws-cdk-lib": "^2.139.1",
    "constructs": "^10.3.0",
    "esbuild": "^0.20.2",
    "eslint": "^8",
    "eslint-config-next": "14.1.0",
    "tsx": "^4.8.2",
    "typescript": "^5.4.5"
  }
}

変更点

amplify→ampxコマンドに変更

実行コマンドがampxに変更になりました。amplifyって長くて打つのが大変でしたよね。私は大変でした。

Gyazo

amplifyの設定ファイルが、amplify_outputs.jsonに変更

昔はaws-exports.js、V6ではamplifyconfiguration.jsonという名前だった設定ファイルが、 amplify_outputs.jsonに変更になりました。

amplify_outputs.jsonの生成と、プログラム内でamplifyconfiguration.jsonを読み出している部分が幾つかあるため、ファイル名の置き換えが必要になります。

 

その他確認できた修正点

UIメニューが刷新

執筆のタイミングでUIが移行中だったようで、本日時点でUIが新しくなり、カスタムドメインも使えるようになりました。 詳細はこちらの記事でまとめられています。

StorageAccessLevelがDeprecatedとなりました

つい先日書いたばかりのStorage機能ですが、accessLevelでのアップロードが非推奨となりました。

aws-amplify@6.2.0では、accessLevelではなく、pathオプションでアップロード先を指定するように求められています。

ドキュメントの更新

5/2に順次各種ドキュメントのアップデートがされていますが、一部amplifyコマンドが残っているなどもあり、置き換えが必要そうです。

既存のアプリケーションをアップデートしてみた

新しいpackage.jsonに従い、モジュールを入れ替えただけでは動作しないので、一部ソースの修正を行う必要があります。 NextJS Server Componentsのアプリをアップデートしてみました。 先日のStorage機能がベースとなっています。

新しい設定ファイルの取得

存在しない設定ファイルを参照しようとしてエラーになるので、generate configコマンドを実行し、amplify-output.jsonを作成します。 なお、階層構造が異なるので、amplifyconfigration.jsonをリネームすればよい、というわけではありません。

ampxコマンド以外の所は従来と同様で、CloudFormationのスタック名を確認し、パラメータに含めればOKです。

npx ampx generate config --stack amplify-hogehoge-master-branch-9c38f4b63a

新しい設定ファイルをimportするように修正

設定ファイルの読み込みを全て修正します。

diff --git a/components/ConfigureAmplify.tsx b/components/ConfigureAmplify.tsx
index 792c2ef..a39cbe0 100644
--- a/components/ConfigureAmplify.tsx
+++ b/components/ConfigureAmplify.tsx
@@ -2,10 +2,10 @@

import { Amplify } from "aws-amplify";

-import config from "@/amplifyconfiguration.json";
+import outputs from "../amplify_outputs.json";

-Amplify.configure(config, { ssr: true });
+Amplify.configure(outputs, { ssr: true });

export default function ConfigureAmplifyClientSide() {
return null;
-}
+}

Dataのモデルのauthorizationの定義方法を修正

関数として定義するようになりました。  カスタムクエリも同様です。

diff --git a/amplify/data/resource.ts b/amplify/data/resource.ts
index 6ff2cf6..d2227f5 100644
--- a/amplify/data/resource.ts
+++ b/amplify/data/resource.ts
@@ -17,7 +17,7 @@ const schema = a.schema({
       priority: a.enum(["low", "medium", "high"]),
     })
     .identifier(["tag", "createDate"])
-    .authorization([a.allow.owner()]),
+    .authorization((allow) => [allow.owner()]),

StorageのGroupの定義方法を修正

groupの定義を配列で行うように修正しました。

diff --git a/amplify/storage/resource.ts b/amplify/storage/resource.ts
index 6ff2cf6..d2227f5 100644
--- a/amplify/storage/resource.ts
+++ b/amplify/storage/resource.ts
@@ -6,7 +6,7 @@   name: "myProjectFiles",
  access: (allow) => ({
-    "admin/*": [allow.group("admin").to(["read", "write", "delete"])],
+    "admin/*": [allow.groups(["admin"]).to(["read", "write", "delete"])],

createServerRunnerのパラメータを修正

DocではcreateServerRunnerのパラメータが{outputs}となっていますが、{config:outputs}で動作しました。

utils/amplifyServerUtils.ts

import { createServerRunner } from "@aws-amplify/adapter-nextjs";
import outputs from "@/amplify_outputs.json";

export const { runWithAmplifyServerContext } = createServerRunner({
  config: outputs,
});

Amplify UIのStorageコンポーネントの呼び出しを修正

Amplify V6、及びAmplify UIも、accessLevelではなく、pathを使うように修正されています。

app/page.tsx

"use client";
import { useEffect, useState } from "react";
import { Amplify } from "aws-amplify";
import type { StorageAccessLevel } from "@aws-amplify/core";
import { getCurrentUser } from "aws-amplify/auth";
import { list, downloadData } from "aws-amplify/storage";
import { StorageImage, StorageManager } from "@aws-amplify/ui-react-storage";

import "@aws-amplify/ui-react/styles.css";
import outputs from "@/amplify_outputs.json";


const ACCESS_LEVEL: string = "admin"

const download = async (key: string) => {
  const task = downloadData({
    path: ({ identityId }) => `${getPath(identityId, ACCESS_LEVEL)}${key}`
  });
  const { body } = await task.result;
  const blob = new Blob([await body.blob()]);
  const link = document.createElement("a");
  link.download = key;
  link.href = URL.createObjectURL(blob);
  link.click();
  URL.revokeObjectURL(link.href);
};

const getPath = (identityId: string | undefined, ACCESS_LEVEL: string): string => {
  if (ACCESS_LEVEL === "admin") {
    return "admin/";
  } else if (ACCESS_LEVEL === "protected") {
    return `content/${identityId ?? ""}/`;
  } else {
    return `content/${identityId ?? ""}/`;
  }
}

export function App() {
  const [user, setUser] = useState("");
  const [fileList, setFileList] = useState<string[]>([]);

  useEffect(() => {
    (async () =>
      setUser((await getCurrentUser()).signInDetails?.loginId ?? ""))();
  }, []);

  useEffect(() => {
    (async () => {
      const response = await list({
        path: ({ identityId }) => getPath(identityId, ACCESS_LEVEL)
      })
      setFileList(response.items.map((item) => item.path.split("/").pop() ?? ""))
    })()
  }, []);

  return (
    <div style={{ padding: "2rem" }}>
      <span>{user}</span>
      <h2>accessLevel:{ACCESS_LEVEL}(custom)</h2>
      <div style={{ margin: "0 2rem" }}>
        <StorageManager
          acceptedFileTypes={["image/*"]}
          path={({ identityId }) => getPath(identityId, ACCESS_LEVEL)}
          maxFileCount={1}
        />
      </div>

      <h2>{ACCESS_LEVEL} file list</h2>
      <ul style={{ margin: "0 2rem" }}>
        {fileList.map((key, _i) => (
          <li key={_i}>
            {key}&nbsp;
            <button onClick={() => download(key)}>download</button>
            <StorageImage
              alt={key}
              path={({ identityId }) => `${getPath(identityId, ACCESS_LEVEL)}${key}`}
            />
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

問題なくストレージアクセスまで完了しました。 amplify v5からv6に変更するほどの手間は無さそうです。

まとめ

Amplify Gen2のGAにより、betaの文字が無くなり、コマンドの変更、設定ファイルの名称変更など、大きな修正が加えられました。

更新された機能についても、細かなアップデートを行っていこうと思います。