AWS AmplifyをNode.js / TypeScriptから操作する

AWS Amplifyを触ってみた系の記事はそこそこ出てきているので、あえてせっかく用意されたコンソールを使わずにやってみましょう。 AWS re:invent 2018 Advent Calendar 2018の19日 […]

広告ここから
広告ここまで

目次

    AWS Amplifyを触ってみた系の記事はそこそこ出てきているので、あえてせっかく用意されたコンソールを使わずにやってみましょう。

    AWS re:invent 2018 Advent Calendar 2018の19日分です。

    前提条件

    すでにAWS Amplifyコンソールからアプリを作成済みであるとします。また、リポジトリにはCodeCommitを使用しています。

    CodeCommitをリポジトリにできるのですが、createAppメソッドがOAuthトークン必須なのでめんどくさかった・・・

    だれかCode CommitをソースにしてcreateAppメソッド実行した記事お願いします。

    作成済みアプリのデータを取得する

    何はともあれ作成済みアプリのデータを取るところから始めましょう。

    import {Amplify} from 'aws-sdk';
    
    const amplify = new Amplify()
    
    export const getMyApplication = async (): Promise<Amplify.Types.GetAppResult> => {
        const data = await amplify.getApp({
            appId: 'YOUR_APP_ID'
        }).promise()
        console.log(data)
        return data
    }

    レスポンスがこんな感じです。公開サイトのスクショURLやビルド設定などもアプリケーションの情報として持っている様子ですね。

    
    { app: 
       { appId: 'YOUR_APP_ID',
         appArn: 'arn:aws:amplify:us-east-1:999999:apps/YOUR_APP_ID',
         name: 'my-first-react',
         tags: {},
         description: null,
         repository: 'YOUR_REPO',
         platform: 'WEB',
         createTime: 2018-12-13T10:56:57.246Z,
         updateTime: 2018-12-13T11:06:34.750Z,
         iamServiceRoleArn: 'arn:aws:iam::99999:role/service-role/AWSAmplifyExecutionRole-YOUR_APP_ID',
         environmentVariables: {},
         defaultDomain: 'YOUR_APP_ID.amplifyapp.com',
         enableBranchAutoBuild: false,
         enableBasicAuth: false,
         basicAuthCredentials: null,
         customRules: [ [Object], [Object], [Object] ],
         productionBranch: 
          { lastDeployTime: 2018-12-13T11:00:04.211Z,
            status: 'SUCCEED',
            thumbnailUrl: 'https://aws-amplify-prod-us-east-1-artifacts.s3.amazonaws.com/YOUR_APP_ID/master/SCREENSHOTS/thumbnail.png?X-Amz-Security-Token=XXXXXXX',
            branchName: 'master' },
         buildSpec: 'version: 0.1\nfrontend:\n  phases:\n    preBuild:\n      commands:\n        - yarn install\n    build:\n      commands:\n        - yarn run build\n  artifacts:\n    baseDirectory: build\n    files:\n      - \'**/*\'\n  cache:\n    paths:\n      - node_modules/**/*\n' } }

    customeRulesには、リダイレクトルールが設定されています。

    [ { source: 'www.example.com',
        target: 'https://example.com',
        status: '301',
        condition: null },
      { source: '/<*>',
        target: '/index.html',
        status: '404',
        condition: null } ]

    SPAでルーター組んだ時に必要なindex.htmlへのリダイレクトもデフォルトでついていますね。これ、逆に考えるとSSGで作ったサイトをデプロイするときは要注意かもです。

    手動でアプリをリリースする

    startJobで任意のタイミングでアプリのリリースを行うことができます。

    import {Amplify} from 'aws-sdk';
    const amplify = new Amplify()
    
    const branchName: string = 'master'
    const appId: string = 'YOUR_APP_ID'
    
    export const startNewRelease = async (): Promise<Amplify.Types.ListJobsResult> => {
        await amplify.startJob({
            appId,
            branchName,
            jobType: 'RELEASE'
        }).promise()
        const data = await amplify.listJobs({
            appId,
            branchName
        }).promise()
        return data
    }

    実行すると新しいジョブが追加されています。

    { jobSummaries: 
       [ { jobArn: 'arn:aws:amplify:us-east-1:999999:apps/YOUR_APP_ID/branches/master/jobs/0000000002',
           jobId: '2',
           commitId: 'HEAD',
           commitMessage: null,
           commitTime: 2018-12-19T02:52:14.606Z,
           startTime: 2018-12-19T02:52:14.984Z,
           status: 'RUNNING',
           endTime: null,
           jobType: null },
    ...

    jobIdを使うことで、retryも可能です。

    import {Amplify} from 'aws-sdk';
    const amplify = new Amplify()
    
    const branchName: string = 'master'
    const appId: string = 'YOUR_APP_ID'
    
    export const startNewRelease = async (): Promise<Amplify.Types.ListJobsResult> => {
        await amplify.startJob({
            appId,
            branchName,
            jobType: 'RETRY',
            jobId: '2',
        }).promise()
        const data = await amplify.listJobs({
            appId,
            branchName
        }).promise()
        return data
    }

    また、すでにそのブランチでjobが進行中の場合、エラーが発生します。

    { 
      message: 'The requested branch arn:aws:amplify:us-east-1:99999:apps/YOUR_APP_ID/branches/master already have pending or running jobs',
      code: 'LimitExceededException',
      time: 2018-12-19T02:54:28.440Z,
      requestId: '668c23d6-0339-11e9-9cf4-39a99096c993',
      statusCode: 429,
      retryable: false,
      retryDelay: 41.97412555483295 }

    GatsbyにWP API連携させて動的にコンテンツを取得したい場合など、定期的にビルドジョブを走らせたい時が稀によくあります。そういうときはこのstartJobをCloudWatch Event -> Lambdaで実行してやるとよいでしょう。

    アプリの設定を更新する

    ビルドやリダイレクトなどの設定はだいたい、アプリについています。なのでupdateAppでだいたい更新可能です。

    import {Amplify} from 'aws-sdk';
    const amplify = new Amplify()
    
    const appId: string = 'YOUR_APP_ID'
    
    export const updateApplication = async (): Promise<Amplify.Types.UpdateAppResult> => {
        const { app } = await amplify.getApp({
            appId
        }).promise()
        const {
            basicAuthCredentials,
            buildSpec,
            customRules,
            enableBasicAuth,
            enableBranchAutoBuild,
            environmentVariables,
            iamServiceRoleArn,
            name,
            platform
        } = app
        const param = {
            appId,
            basicAuthCredentials,
            buildSpec,
            customRules,
            description: 'This is example app to update from aws-sdk',
            enableBasicAuth,
            enableBranchAutoBuild,
            environmentVariables,
            iamServiceRoleArn,
            name,
            platform
        }
        const data = await amplify.updateApp(param).promise()
        return data
    }

    getAppの戻り値をそのまま突っ込むとUnexpected key ~で怒られるので、横着はやめましょう。

    応用:サイト全体にBASIC認証をかける

    basicAuthCredentialsenableBasicAuthでBASIC認証をかけれます。

    credentialsの方はBASE64でエンコードした値を入れるのがポイントです。

    import {Amplify} from 'aws-sdk';
    
    const amplify = new Amplify()
    const appId: string = 'YOUR_APP_ID'
    
    const generateCredentials = (username: string, password: string): string => {
        return Buffer.from(`${username}:${password}`).toString('base64')
    }
    
    export const setBasicAuth = async (): Promise<Amplify.Types.UpdateAppResult> => {
        const { app } = await amplify.getApp({
            appId
        }).promise()
        const {
            buildSpec,
            customRules,
            description,
            enableBranchAutoBuild,
            environmentVariables,
            iamServiceRoleArn,
            name,
            platform
        } = app
        const basicAuthCredentials = generateCredentials('admin', 'adminadmin')
        const param = {
            appId,
            basicAuthCredentials,
            buildSpec,
            customRules,
            description,
            enableBasicAuth: true,
            enableBranchAutoBuild,
            environmentVariables,
            iamServiceRoleArn,
            name,
            platform
        }
        const data = await amplify.updateApp(param).promise()
        return data
    }

    解除はbasicAuthCredentials=''かつenableBasicAuth=falseにしてやればOKです。

    ブランチ単位で設定を変える

    BASIC認証など、一部はブランチ単位で設定を変えれます。

    import {Amplify} from 'aws-sdk';
    
    const amplify = new Amplify()
    
    const branchName: string = 'master'
    const appId: string = 'YOUR_APP_ID'
    
    const generateCredentials = (username: string, password: string): string => {
        return Buffer.from(`${username}:${password}`).toString('base64')
    }
    
    export const setBranchBasicAuth = async (): Promise<Amplify.Types.UpdateBranchResult> => {
        const { branch } = await amplify.getBranch({
            appId,
            branchName
        }).promise()
        const {
            buildSpec,
            description,
            enableAutoBuild,
            enableNotification,
            environmentVariables,
            framework,
            stage,
            ttl
        } = branch
    
        const data = await amplify.updateBranch({
            appId,
            buildSpec,
            description,
            enableAutoBuild,
            enableNotification,
            environmentVariables,
            framework,
            stage,
            ttl,
            basicAuthCredentials: generateCredentials('admin', 'adminadmin'),
            enableBasicAuth: true,
            branchName
        }).promise()
        return data
    }

    やっていることは同じですね。こちらも更新したい値だけいじってそのまま突っ込むとエラーになる様子なので、要注意です。

    おわりに

    AWS Amplifyですが、アプリを作るところでOAuth token必須になっていること以外はすごくAPI / SDKからも扱いやすいです。

    他にもいろいろなAPIがありますので、ぜひ触ってみてください。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark