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認証をかける
basicAuthCredentials
とenableBasicAuth
で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がありますので、ぜひ触ってみてください。