月別: 2019年10月

Kotlin/JSのAWS Lambda関数でJsonを返してみる

f:id:seeds-std:20191010160615p:plain
こんにちは, Web事業部の西村です
私の前回の記事 Promiseを利用して非同期に処理するようにしてみました
今回はこのLambda関数で kotlinx.serialization を用いてJsonを返すようにしてみたいと思います

目次

過去の記事

なぜ kotlinx.serialization?

まず kotlinx.serialization を用いる理由です
ここまでの記事を読んでくださっている方々であれば “わざわざないでしょ” と思っている方もいると思います
その通りで, json()JSON.stringifiy() 関数を用いればJsonを返すことができます
しかし, kotlinx.serialization を用いることにより, Client側でも同じクラスを利用することができ, 開発する際に便利であるといえます
またマルチプラットフォームであるため様々な環境で利用できるというのもメリットです

注意事項

この記事では kotlinx.serialization に関する詳しい解説は行いません
詳しく知りたい方は下記のリポジトリをご覧ください
github.com

開発環境

この記事では下記の環境で開発を行っています

  • AdoptOpenJDK 1.8.0_222-b10
  • IntelliJ IDEA Community 2019.2.2
  • Kotlin 1.3.50

プロジェクト

前回の記事 まで作成したプロジェクトを利用します
プロジェクトの構成は下記のようになっています

KotlinLambda
├─.gradle/
├─.idea/
├─build/
├─gradle/
├─src/
│ └─main/
│   └─kotlin/
│     └─jp.co.seeds_std.lambda.kotlin/
│       └─handler.kt
├─build.gradle.kts
├─compress.zip
├─gradlew
├─gradlew.bat
└─settings.gradle.kts

また, handler.ktは下記のようになっています

package jp.co.seeds_std.lambda.kotlin
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.delay
import kotlinx.coroutines.promise
import kotlin.js.Json
import kotlin.js.json
@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
val tasks = (1..10).map {
async {
delay(1000)
it
}
}
val results = tasks.awaitAll()
return@promise Response(body = "Result: ${results.sum()} - Coroutines")
}
data class Response(
val statusCode: Int = 200,
val body: String = "{}",
val isBase64Encoded: Boolean = false,
val headers: Json = json(),
val multiValueHeaders: Json = json()
)

Jsonを返すようにする

目標

今回は下記のようなJsonを返すようにしてみます

{
"id": 0, // ID
"text": "", // 文字列
"random_numbers": [5, 38, 24] // 適当な数値
}

依存関係を追加する

kotlinx.serialization は外部ライブラリですので依存関係を追加する必要があります
また, 専用のプラグインも必要であるためプラグインの追加も行います

build.gradle.kts / pluginsブロック

plugins {
kotlin("js") version "1.3.50"
kotlin("plugin.serialization") version "1.3.50"
}

依存関係の追加

build.gradle.kts / dependenciesブロック

sourceSets["main"].dependencies {
implementation(kotlin("stdlib-js"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:0.13.0") // 追加
}

リポジトリに jcenter を追加する必要があるので追加します

build.gradle.kts / repositories

repositories {
mavenCentral()
jcenter() // 追加
}

クライアント側に返すクラスを作成する

作成するクラスが今回のJsonに変換するクラスとなるので各種アノテーションも付与します
今回は Responseクラス の下に作成します(本当は別ファイルにするほうがいいです)

handler.kt

@Serializable
data class ResponseBody(
@SerialName("id")
val id: Int = 0,
@SerialName("text")
val text: String = "",
@SerialName("random_numbers")
val randomNumbers: List<Int> = emptyList()
)
  • @Serializable これがついているクラスがシリアライズ/デシリアライズすることができます
  • @SerialName(String) 引数で決められた文字列がkeyとなるようになります, ない場合は変数名が利用されるようになるのでなくても問題ないです

Jsonを返す準備をする

まずは前回までに書いていたコードの一部を削除しスッキリさせます

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
return@promise Response(body = "")
}

続いて, 先ほど作ったクラスを文字列に変換するために kotlinxのJsonオブジェクト を作成します

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
val json = kotlinx.serialization.json.Json(JsonConfiguration.Stable) // 追加
return@promise Response(body = "")
}

⚠注意1
今回の記事ではすでにkotlinが実装している Jsonクラス をインポートしているため同じ名前であるkotlinxの Jsonクラス をインポートできません
kotlinのJsonkotlinxのJson とを間違わないよう注意してください

⚠注意2
JsonConfiguration には Stable 以外の設定もありますが, 実験的機能となっていますので利用はお勧めしません

Jsonを返す

まずは先ほど作成した ResponseBodyクラス のオブジェクトを作成します

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
val json = kotlinx.serialization.json.Json(JsonConfiguration.Stable)
val responseBody = ResponseBody(1, "Lambda Json!!!", List(3) { Random.nextInt(100) }) // 追加
return@promise Response(body = "")
}

最後に stringify関数 を用いてクラスを文字列に変換し レスポンスのbody に設定します

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
val json = kotlinx.serialization.json.Json(JsonConfiguration.Stable)
val responseBody = ResponseBody(1, "Lambda Json!!!", List(3) { Random.nextInt(100) })
return@promise Response(body = json.stringify(ResponseBody.serializer(), responseBody)) // 変更
}
  • ResponseBody.serializer() この関数は @Serializable アノテーションがついているクラスの場合コンパイラが自動的に作成してくれます

動作確認

関数をデプロイし, API GatewayのURLにアクセスし {"id":1,"text":"Lambda Json!!!","random_numbers":[ランダムな数字が3つ]} 表示されれば成功です

最後に

いかがでしたでしょうか
LambdaでJsonを返すのはありがちです
これを利用することによりKotlinで作成するマルチプラットフォームなアプリケーションではかなり強力になりうると考えます
また, ここまで4つの記事に分け Kotlin/JS をもちいて AWS Lambda関数 を作って便利にしてみました
これがベストプラクティスかどうかはプロジェクトによると思いますが、1つの参考になるとうれしい限りです
ここまで読んでいただきありがとうございました


蛇足

JSON.stringify() を使ってJsonを返してみる

JavaScriptにもとから存在する, JSON.stringify を用いてもJsonを返すことができます

handler.js

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
val responseBody = ResponseBody(1, "Lambda Json!!!", listOf(0, 1, 2))
return@promise Response(body = JSON.stringify(responseBody))
}

実行結果

{"id":1,"text":"Lambda Json!!!","randomNumbers":[0,1,2]}

しかしこれではJsonのKeyは指定できないので変数をすべて private に変更すると結果が変わるので注意が必要です

privateに変更したときの実行結果

{"id_0":1,"text_0":"Lambda Json!!!","randomNumbers_0":[0,1,2]}

こういうケースもあるため kotlinx.serialization を用いることをお勧めします

json() と JSON.stringify() を使ってJsonを返してみる

一番オーソドックスでわかりやすい返し方だと私は思います

handler.js

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
val responseBody = json(
"id" to 0,
"text" to "Lambda Json!!!",
"random_numbers" to listOf(0, 1, 2)
)
return@promise Response(body = JSON.stringify(responseBody))
}

実行結果

{"id":1,"text":"Lambda Json!!!","random_numbers":[0,1,2]}

蛇足まで読んでいただきありがとうございました

open-wcでWeb Componentsをつくる

f:id:seeds-std:20191024163712p:plain

こんにちは、プログラマーの衣笠です。
Web Componentsの各ブラウザでの実装がそろってきたのでそろそろ触ってみようと調べていたら、open-wcというものを見つけました。ツールを用意してくれていたので今回はこれを使って簡単なコンポーネントをひとつ作ってみたいと思います。

open-wc とは

Web Componentsを作成、共有する上での推奨事項をまとめてそれをツールとして提供することを目的とした集まりです。

open-wc.org

推奨事項は

  • Developing
  • Linting
  • Testing
  • Building
  • Demoing
  • Publishing
  • Automating

と章をわけてガイドを提供してくれています。
そこで推奨しているパッケージや設定を用意してくれていてツールで生成できるようになっています。

open-wcのツールで開発環境構築

ツールを使うと簡単に開発環境を用意してくれます。
npmが使えてプロジェクトのディレクトリを置きたい場所で

npm init @open-wc

とすると勝手にツールをダウンロードしてきて実行されます。
ツールが実行されると色々質問されます。作成されるものはその回答によって変わります。
今回は簡単は単一のコンポーネントのプロジェクトを作成したいと思うので以下のように回答すると

What would you like to do today? › Scaffold a new project
What would you like to scaffold? › Web Component
What would you like to add? › (選択なし)
What is the tag name of your application/web component? … password-input
Do you want to write this file structure to disk? › Yes
Do you want to install dependencies? › Yes, with npm  

password-input ディレクトリを以下のような構成で作成してくれます。

.
├── LICENSE
├── README.md
├── demo
│   └── index.html
├── index.js
├── package-lock.json
├── package.json
├── password-input.js
└── src
└── PasswordInput.js

テストやビルドの環境などをあとで追加したい場合、もう一度ツールを使って追加できます。

開発サーバー

ツールで生成されたディレクトリで npm run start をすると開発サーバーが立ち上がってブラウザで 自動でdemo/index.html を開きます。
開発サーバーは es-dev-server というopen-wc お手製のパッケージが使われています。
open-wcはできるだけWeb標準に近づくことで長期投資をする方針で、開発も最新のブラウザでES Modulesを活用して進めることを推しています。なので es-dev-server はビルドツールを使わない前提の仕様になっています。
ビルドの待ち時間がないっていうのはすごい魅力的ですね。
また、node_modules のパッケージもいい感じに読み込んでくれます。

WebComponentの実装

今回は最近よくある入力したパスワードの内容を見えるように切り替えられるinput要素 password-input を作ってみました。
作成したものをGlitchで埋め込んでおきます。View Appボタンでデモページに切り替えられます。

実装は src/PasswordInput.js にしていきます。demo/index.html はデモページです。
open-wcはLitElementとlit-htmlを使った実装を推奨していて、プロジェクト生成時点で使えるようになっています。
ここからはLitElementでの実装方法を説明していきます。

カスタム要素の定義

カスタム要素は通常HTMLElementクラスを継承したクラスを定義しますが、LitElementではLitElementクラスを継承して定義します。
タグ名とクラスの紐付けは password-input.js で既にされているので触る必要がありません。

要素のプロパティ、属性

LitElementではゲッター properties で返すオブジェクトで要素のプロパティを定義します。

  ...
static get properties() {
return {
value: {type: String},
visibility: {type: Boolean}
};
}
constructor() {
super();
this.value = "";
this.visibility = false;
}
...

オブジェクトのプロパティに定義したいプロパティの名前、その値のオブジェクトに設定を指定します。
基本的に定義したプロパティと同じ名前の属性も一緒に定義されます。
typeBoolean にすると disabled 属性みたいな扱いになります。
初期値はコンストラクタで設定できます。

要素のコンテンツ

Web Componentsはカスタム要素のコンテンツをShadowDOMによって定義します。
LitElementでは renderメソッドに定義していきます。

  ...
_toggleVisibility() {
this.visibility = !this.visibility
}
render() {
return html`
<input type=${this.visibility ? 'text' : 'password'}
value=${this.value}
>
<span
class="toggle"
@click=${this._toggleVisibility}
>
....
</span>
`;
}
...

render メソッドはlit-elementが用意しているタグ付きテンプレートリテラルの html を使ってコンテンツを定義します。
イベント名に接頭辞 @ を付けた属性にイベントハンドラをバインドできます。

要素のスタイル

要素のスタイルの定義は styles ゲッターに定義します。LitElementが用意している css タグ付きテンプレートリテラルを使います。
コンテンツのスタイルはShadowDOMの中に定義されてカプセル化されるので外の要素に影響しません。Vue.jsのscoped CSSと同じです。
CSSの管理が楽になるのでありがたいです。

  ...
static get styles() {
return css`
:host {
--icon-size: 24px;
display: inline-flex;
...
}
...
input {
line-height: 1em;
...
}
...
.icon {
width: var(--icon-size);
height: var(--icon-size);
}
...
`;
}
...

:host セレクタでカスタム要素のスタイルを定義します。カスタム要素のスタイルは外から変更可能です。
対してそれ以外のShadowDOMのスタイルは外から直接変更できません。
外から変更する方法のひとつにCSSカスタムプロパティを使った方法があります。
ここでは --icon-size を定義して外からパスワードの変更を切り替えるボタンのアイコンのサイズを変更できるようにしています。
他にも Shadow Parts という part 属性と ::part() セレクタを使った方法があります。

::part() – CSS: Cascading Style Sheets | MDN

まとめ

以上がopen-wcで簡単なWeb Componentをつくってみた内容になります。

今回はDevelopingのみを扱いましたが、簡単なものだったので紹介できていないこともあります。興味があればぜひ公式のガイドを読んでみてください。
文章では伝わらなかったと思いますがビルドの時間がないというのはすごく快適です。ES Modulesが普及してきたからこそだと思いますが、Web Componentsの開発環境だけではなく他の開発環境でもこのスタイルが広まればいいなと思いました。
open-wcも今年できたばかりで日本語の情報がほとんどありませんがこの記事がみなさんの触れるきっかけになれば幸いです。

ブラウザ上でJavaScriptを利用したクリップボードへのコピー機能の実装

エンジニアの中氏です。

ブラウザ上でクリップボードへのコピー機能の実装は便利なJSライブラリのzclipを従来利用していましたが、
Flash の機能を利用している為、将来的に Flash が完全廃止になった際に利用出来なくなることが予想されます。

よって、今回はピュアなJavaScriptのみでコピー機能を実装する方法をご紹介します。
具体的には document.execCommand を利用してコピーを行う方法です。
テキストの範囲選択して、document.execCommand('copy') を実行してコピーを行います。

ここでは、画面に表示されているテキストをコピーするという例で下記に関数の例を記載します。

/**
 * 指定した要素のテキストノードのテキストをコピー
 *
 * @param {string|HTMLElement} subject
 */
function copyByTextNode(subject) {
let textNode = $(subject).get(0).childNodes[0];
let range = document.createRange();
range.selectNode(textNode);
// 選択範囲解除
getSelection().removeAllRanges();
// 範囲選択 
getSelection().addRange(range);
// コピー実行
document.execCommand('copy');
// 選択範囲解除
getSelection().removeAllRanges();
}

copyByTextNode([セレクタ])
で使用します。

セレクタを指定するだけで、そのDOMのテキストノードをコピー出来ます。

AWSソリューションアーキテクトアソシエイト(SAA-C01)に合格しました

f:id:seeds-std:20191021181435p:plain

こんにちは。小國です。

社員の AWS 認定の取得が相次いでいるシーズです。私も 1ヶ月ほど前になりますが、AWSソリューションアーキテクトアソシエイト(SAA-C01)に無事に合格できました。

AWSソリューションアーキテクトアソシエイトを目指す方の参考になればと思い、その時の勉強方法などを紹介します。

まずは自己紹介

  • ソフトウェアエンジニア 12年(主に LAMP 環境で CakePHP、Laravel、他に Android もちょっとできます)
  • 応用情報技術者試験(AP)
  • LAMP や LEMP 程度なら構築できます(ネットワークは要勉強)
  • 過去に LPIC-1(LPIC-2 は前半だけ合格。。。)
  • とりあえず、なんでもやってみる人

勉強前の AWS の知識

AWS は EC2、VPC、RDS のチュートリアル*1を触ったことがある程度で、その他の各種サービスについては以下のような認識でした。

  • S3、聞いたことある
  • ACM、???
  • CloudFront、聞いたことある
  • ELB、聞いたことある
  • リージョン・AZ・エッジロケーション、微妙。。。
  • Lambda、ランブラ?(後にラムダと読むことを知る)
  • DynamoDB、???

勉強方法

勉強期間は約 2週間で、以下の 2冊の本をやりきりました。

AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイト

AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイト

AWS認定資格試験テキスト AWS認定 ソリューションアーキテクト-アソシエイト

  • 作者: NRIネットコム株式会社,佐々木拓郎,林晋一郎,金澤圭
  • 出版社/メーカー: SBクリエイティブ
  • 発売日: 2019/04/20
  • メディア: 単行本
  • この商品を含むブログを見る

AWS の主要なサービスについて要点をがしっかりとまとまっていて、わかりやすくとてもためになりました。章末や模擬試験の解答の解説も丁寧で良かったと思います。

勉強方法はというと、一通り目を通し、章末や模擬試験をすべて正解するまで(間違っている箇所はどこが間違っているか分かるまで)やりました。

おそらく 4、5回はやったかと思います。

徹底攻略 AWS認定 ソリューションアーキテクト – アソシエイト教科書

徹底攻略 AWS認定 ソリューションアーキテクト ? アソシエイト教科書

徹底攻略 AWS認定 ソリューションアーキテクト ? アソシエイト教科書

  • 作者: ??部昭寛,宮?光平,菖蒲淳司,株式会社ソキウス・ジャパン
  • 出版社/メーカー: インプレス
  • 発売日: 2019/01/18
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

1冊では不安だったので、こちらも購入しました。

こちらは、問題を解いて間違えた箇所について、本で調べました。こちらの本も同様に、すべて正解するまでやりました。

先に購入した対策本で理解ができていなかった箇所がカバーできたのでよかったと思いますが、解答の解説が少なかったように思います。

模擬試験

本試験の 2日前ほどに受けました。思っていたより簡単で、結果も 84%ほどの正答率でした。

いよいよ本試験!

本試験ですが、模擬試験に比べ文章も長く・問題も単純なものが少なく、難しかったです。

40分ほど残して一通り解答し、残りの時間いっぱいを使って見直しをしました。終わったあとはすごく頭が痛かったです。頭がしっかり働く午前中に受験したのが幸いでした。

問題文は、VPC や ELB のネットワークの複合的な問題や、DynanoDB、暗号化についての問題が多かった印象です。

感想

とりあえずは、AWSソリューションアーキテクトアソシエイト(SAA-C01)を取得できよかったです。

ただし、実際に AWS を使いこなせるかは甚だ疑問で、実際に手を動かしてみて知識・技術の定着をして、業務に役に立てるようやっていきたいです。

また、相当の難易度だと聞く、プロフェッショナル取得を目指せるよう勉強したいなと。。。

余談ではありますが、弊社 CTO の、原口さんこと cs_sonar さんが、AWSソリューションアーキテクトプロフェッショナル(SAP-C01)に合格されてます。

プロフェッショナルを目指す方は、ご参考にしてはいかがでしょうか。

blog.seeds-std.co.jp

Slackの新機能!「ワークフロービルダー」やってみた

f:id:seeds-std:20191019041007p:plain
クラウド事業部の川勝です。

先日(2019年10月15日)弊社でも使用しているチャットツールSlackに新機能「ワークフロービルダー」がリリースされました!
https://slack.com/intl/ja-jp/features/workflow-automation

早速試してみましたのでご紹介したいと思います。

導入

ワークフローの自動化で作業をシンプルに
重要な仕事の妨げになるルーティン作業からチームを解放。Slack のワークフロービルダーを活用しましょう。

とキャッチフレーズがありまして簡単にいうとチャンネルに対してアクションを設定し、メッセージまたはフォーム表示できたりします。

アクションとは以下のタイミングで実行することができます。

  • ワークフローボタンから手動実行
  • チャンネルに新しい人がジョインしたとき
  • 特定の絵文字リアクションがついたとき

新しくプロジェクトにアサインした人に自動で必要情報を表示とか、毎朝のMTG内容をフォーム入力で投稿、、といったようなことができそうですね。

弊社ではスマートフォン等の検証機があり、その使用時に特定のチャンネルで通知する、というフローがあります。

f:id:seeds-std:20191019023204p:plain
端末使用時の様子

いままでは手動でこのように微妙に統一感がなく各自が投稿していましたので、今回はこちらの投稿フォームを作ってみたいと思います!

ワークフロー作成

f:id:seeds-std:20191019023537p:plain

左上のワークスペースのメニューに「Workflow Builder (NEW)」と使ってくれと言わんばかりの項目が増えています。
こちらをクリックします。

f:id:seeds-std:20191019023853p:plain

自分が作成したワークフローの管理ができます。(後述していますが、チームで作成されているすべてが無条件に表示されるわけではない)

新規作成してみましょう。

f:id:seeds-std:20191019024430p:plain

命名

f:id:seeds-std:20191019024623p:plain

次にどのチャンネルにワークフローを設定するか選択します。
ここで選択したチャンネルからのみアクションが実行されます。
short nameはワークフロー起動時に表示されている名称になります。

「Save」するとこんな感じに表示されます。

f:id:seeds-std:20191019024940p:plain

「Add Step」をクリックして、メッセージやフォームを作成してつなげていきます。
すると、、、

f:id:seeds-std:20191019024907p:plain

ちょっと飛ばしてこのようになりました。

今回だと

  • ワークフロー実行
  • フォーム入力項目設定
  • フォーム入力内容にもとづくメッセージ設定
  • メッセージについているボタンをクリックしたときのメッセージ設定

という順番になっています。

では項目設定の解説していきます。

まず「Add Step」をクリック。

f:id:seeds-std:20191019025603p:plain

すると「Send a message」 or 「Create a form」の選択がでてきます。

今回の場合だと最初は フォームがほしいので「Create a form」を選択します。

f:id:seeds-std:20191019030110p:plain

こちらはselect boxで選択肢の設定をしています。

他にも以下選択肢が設定可能です。

  • Short answer (改行NGの自由入力)
  • Long answer (改行OKの自由入力)
  • Select form list (画像のselect box)
  • Select a person (チームないのユーザを選択できるselect box)
  • Select a channel or DM (チームないのチャンネル or DMを選択できるselect box)

また確定したときDMで内容を送信したりもできます。

続いて通常のメッセージ

f:id:seeds-std:20191019030801p:plain

メッセージはどのチャンネルに送信するか選択できます。(ワークフローを起動したチャンネルと異なってもOK)
またフォームに続いてのメッセージの場合は Insert a variable でフォーム入力値の挿入ができます。
他にもアクションを起動した人、アクションを実行したチャンネルなどが挿入可能です。

あと面白いのがボタンをつけることができます。
ボタンをつけていると、次のStepでボタンをクリックしたら起動、ということが実現できます!

f:id:seeds-std:20191019031248p:plain

そうすると先に送信したメッセージのスレッドに投稿ということも可能になっています。

ここまででできたら右上の「Publish」で公開するとチャンネルからワークフローが実行可能です!

f:id:seeds-std:20191019031538p:plain

公開できたら実行してみましょう!

実行

f:id:seeds-std:20191019040321g:plain

こんな感じで実行できました!

感想

簡単に登録できてこれからどんどん活用したいなと思える機能でした。
ただ新機能ということもあってちょっとかゆいところに手が届かないなあという感じもあります。

以下は個人の感想です。

  • ワークフロービルダーで作成したものを他人が編集できるようにするにはCollaboratorsに追加しないといけないため、
    無条件でチームない共有されない。
  • 絵文字リアクションなんかは複数のチャンネルで同じワークフローを発火できたら面白そう、とおもったがそれはできない。
    ただし、アクション後のメッセージ投稿は任意のチャンネルに投稿できます。
  • アクションはチャンネルにだけ設定できる。自分用にDMに登録はできない。

今後もっと使いやすくなることに期待したいですね!

また面白い使い方が見つけたらブログにしたいと思います。

ちなみに以下にサンプルがあるので、最初はここからダウンロードしたものをインポートして作成すると作りやすいと思います。(現在英語だけみたいです…)
https://slack.com/intl/ja-jp/slack-tips/workflow-builder-examples

以上川勝でした。

Amazon QLDB 楽しいかもというお話

f:id:seeds-std:20191016131408p:plain

はじめに

みなさま、こんにちは。

WEB事業部の李です。 どうぞよろしくお願いいたします。
最近、タピオカにハマっています。
美味しいタピオカを探しております。

さて、Amazon QLDB(以降、単に「QLDB」)が東京リージョンに対応しました。
面白そうなので、ドキュメントを読みつつ、触ってみました。
本日は、QLDBの、この機能いいなと思った感想を書きたいと思います。
※機能面の詳細については、別の機会に書きたいと思います。

QLDBの紹介

まずは、QLDBってなんだ!というところですが、
ざっくり言うと、中央集権的な台帳サービスです。

例えば、データベースに履歴情報を格納して、アプリ側でそれを検索したり、
新たに登録や更新があれば、過去の改竄が無いようにデータを挿入していくといったことをしたい場合があるかと思います。

そんな時に、DB側でその保証を約束してくれるような構造になっていれば楽なのになと、毎回思ったりしますが、
QLDBは、まさにそれを実現してくれるソリューションとして登場したように感じます。

Q: Amazon Quantum Ledger Database とは何ですか?

Amazon Quantum Ledger Database (QLDB) は、台帳管理専用データベースです。
アプリケーションのデータに生じたすべての変更に関する、完全で暗号的に検証可能な履歴を提供します。

よくある質問 – Amazon QLDB | AWS

また、開発者ドキュメントのチュートリアルでは、
自動車とその所有者の所有履歴を管理する台帳を例で挙げられていました。
世の中履歴データだらけなので、自動車以外にも対象はかなり多そうです。

docs.aws.amazon.com

ユースケースとして、金融や小売での利用が紹介されてました。

・金融

銀行では多くの場合、顧客の銀行口座間のクレジットカードおよびデビットカードによる取引などの重要データの追跡に一元管理台帳的なアプリケーションが必要になります。
複雑な監査機能を持つカスタム台帳を構築する代わりに、QLDB ですべての金融トランザクションの正確かつ完全な記録を簡単に保存できます。

・小売 & サプライチェーン

小売業では、製品原産地や出荷製品の品目数、出荷先、出荷担当者など、製品サプライチェーンのあらゆる段階に関する情報にアクセスしなければならないことが多々あります。
QLDB を使用すると、製品がどの物流局面にあっても在庫および物流に関する完全な履歴を確認し追跡できます。

↑どちらも有用そうです。

特徴

さて、QLDBは下記のような、特徴があります。
・フルマネージドであること。かつ、サーバーレス(->自動スケーリング)。
・すべての変更が透過的で、イミュータブルであること。
・トランザクションログが、暗号的に検証可能であること。

aws.amazon.com

アプリ開発の時には、JAVAのドライバーが用意されていますので、下記のチュートリアルをご参考ください。

docs.aws.amazon.com

この機能いいなと思った感想

さて、色々便利そうで、素敵な機能があるのですが、
その中で、個人的にこりゃ便利だなと思った機能を二点あげたいなと思います。

改竄出来ないDBであること

新規だろうが、更新だろうが、削除だろうが、全て履歴に残してくれます。
また、その時々のメタ情報を残してくれますので、アプリ側で云々する必要が無いです。
ちなみにミスった操作も、全て保存され、かつ検証可能です。
※誤操作や誤情報を登録しないようなフローや制限などはアプリ側で考慮は必要です。それらも全て記録されますので、その辺は仕様によります。

PartiQLでクエリ可能であること

sqlチックな言語で、保存されたデータをクエリできちゃいます。
ネストされたデータをクエリできるのは、素敵だなと思います。
※2019/10/17現在、すべての PartiQL オペレーションをサポートしているわけでは無いらしいです。

おわりに

クロスリージョンレプリケーションはサポートされていないなど、
出始めのサービスなので、まだまだ成長段階かと思いますが、
ポテンシャルはめちゃくちゃ大きいような気がします。(=楽できる。 )

Kotlin/JSのAWS Lambda関数でPromiseを使うようにする

f:id:seeds-std:20191010160615p:plain
こんにちは, Web事業部の西村です
私の前回の記事 では dyanmic の利用をなくすようにしました
そして今回は, Callbackの呼び出しをやめて, JavaScriptの非同期処理( Promise )になるよう変更したいと思います
また, Promiseスタンダード なものと Coroutines のものの2種類がありますので, この記事ではその両方を紹介したいと思います

目次

過去の記事

なぜ非同期に?

非同期処理することにより複数の処理を同時に実行することができます
例えば, 複数のファイルを受け取り, S3に保存する といったことを考えてみます
非同期処理ではない場合, 1ずつしかファイルのアップロードができません
非同期処理の場合, 複数のファイルを同時にアップロードできるようになるので時間の短縮が図れます

注意事項

この記事では Promise の詳しい解説は行いません
詳しく知りたい方は下記の記事を参考にしてください
qiita.com

開発環境

この記事では下記の環境で開発を行っています

  • AdoptOpenJDK 1.8.0_222-b10
  • IntelliJ IDEA Community 2019.2.2
  • Kotlin 1.3.50

プロジェクト

前回の記事 まで作成したプロジェクトを利用します
プロジェクトの構成は下記のようになっています

KotlinLambda
├─.gradle/
├─.idea/
├─build/
├─gradle/
├─src/
│ └─main/
│   └─kotlin/
│     └─jp.co.seeds_std.lambda.kotlin/
│       └─handler.kt
├─build.gradle.kts
├─compress.zip
├─gradlew
├─gradlew.bat
└─settings.gradle.kts

また, handler.ktは下記のようになっています

package jp.co.seeds_std.lambda.kotlin
import kotlin.js.Json
import kotlin.js.Promise
import kotlin.js.json
@JsExport
@JsName("handler")
fun handler(event: Json, context: Json, callback: (Error?, Response?) -> Unit) {
val response = Response(body = "Hello from Kotlin Class Lambda!")
callback(null, response)
}
data class Response(
val statusCode: Int = 200,
val body: String = "{}",
val isBase64Encoded: Boolean = false,
val headers: Json = json(),
val multiValueHeaders: Json = json()
)

スタンダードなPromise

まずはkotlin-stdlibに実装されている Promise を利用してみます

関数の書き換え

handler 関数を変更します

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json, callback: (Error?, Response?) -> Unit) {
val response = Response(body = "Hello from Kotlin Class Lambda!")
callback(null, response)
}

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = Promise<Response> { executor, reject ->
executor(Response(body = "Hello from Kotlin Async Lambda!"))
}
  • executor は処理成功時に実行する関数で, 引数はジェネリクスで指定したクラス (この記事では Response ) となります
  • reject は処理失敗時に実行する関数で, 引数は Throwable クラスのオブジェクトとなります

動作確認

関数をデプロイし, API GatewayのURLにアクセスし Hello from Kotlin Async Lambda! と表示されれば成功です

もう少し恩恵を受けてみる(スタンダード)

今度はNode.jsの setTimeout を利用して本当に非同期に処理されているかを確認したいと思います
その前に, Kotlin/JSにはNode.jsの setTimeout は定義されていないので追加します
今回追加する場所はコードの最下部に追加します

handler.kt

external fun setTimeout(callback: dynamic, delay: Int, vararg args: Any?): Int
external fun clearTimeout(timeout: Int)
  • external : 外部の関数/変数を利用するために記述します。トランスパイルした場合にそのまま残るようになります
  • callback の部分が dynamic となっていますが, 関数の引数が固定値ではないためやむを得ず dynamic としています

続いて handler 関数を変更します

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = Promise<Response> { executor, reject ->
val results = (1..10).map {
Promise<Int> { childExecutor, _ ->
setTimeout({childExecutor(it)}, 1000)
}
}
Promise.all(results.toTypedArray()).then {
executor(Response(body = "Result: ${it.sum()} - Standard"))
}
}

このコードでは 1秒待ってから数字を返す というコードを10回繰り返すものとなっています

動作確認

関数をデプロイし, API GatewayのURLにアクセスし約1秒後に Result: 55 - Standard と表示されれば成功です
※初回の実行では2-3秒ほどかかる場合もあります

通常の処理であれば 1秒待って数字を返す を10回行えば10秒かかるはずですが, 非同期に実行されているため約1秒で完了します

CoroutinesのPromise

標準実装の Promise では見にくく感じませんでしたか?(私は少なからず見にくいなと感じました)
非同期処理を書くのであれば, Node.jsみたいに async で書きたいところです
そこで使うのが kotlinx.coroutines です

依存関係を追加する

kotlinx.coroutines は外部ライブラリなので build.gradle.kts に依存関係を追加する必要があります

build.gradle.kts

implementation(kotlin("stdlib-js"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core-js:1.3.2") // 追加

コードを書き換える

まずはただの文字列を返すように handelr 関数を変更します

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
return@promise Response(body = "Hello from Kotlin Coroutines Lambda!")
}

先ほどのコードと比較するとかなり単調なものになりました
※エラーを返す際は throw NullPointerException() のように throw するだけとなります

動作確認

関数をデプロイし, API GatewayのURLにアクセスし Hello from Kotlin Coroutines Lambda! と表示されれば成功です

もう少し恩恵を受けてみる(Coroutines)

先ほどと同じ関数を実装してみます

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json) = GlobalScope.promise {
val tasks = (1..10).map {
async {
delay(1000)
it
}
}
val results = tasks.awaitAll()
return@promise Response(body = "Result: ${results.sum()} - Coroutines")
}

先ほどとは異なり, CoroutineScope 内で実行できるため, async 関数を利用できます

動作確認

関数をデプロイし, API GatewayのURLにアクセスし約1秒後に Result: 55 - Coroutines と表示されれば成功です
※初回の実行では2-3秒ほどかかる場合もあります

最後に

いかがでしたでしょうか
非同期処理が行えるとよりできることの幅が増えるかと思います
また、Coroutinesの Promise と標準実装の Promise は互換性があるため外部ライブラリが非同期処理を行う場合にも使え,
よりKotlinらしい書き方ができるようになっていくと思います
次回は kotlinx.serialization を用いてJsonのレスポンスを行う記事を書きたいと思います
ここまで読んでいただきありございました

Kotlin/JSのAWS Lambda関数でJsonを返してみる

開発者やデザイナーは要注意?!シーズ社員達がMac OSをCatalinaへアップデートした体験談。

f:id:seeds-std:20191011110224p:plain

はじめまして!WEB事業部の小川です。

新しいMac OS(Catalina)が登場し、シーズの新しい物好きな社員達(自分を含む)はアップデートしてみました。

更新した感想等を書いていこうと思いますので、アップデートを検討されている方の参考になればと思います。

とりあえず Sidecarが便利

iPadユーザーには朗報であったSidecarが便利で、今まで有料のアプリやハードを使わないと出来なかったiPadのサブディスプレイ化が手軽に出来るのはいいですね!

f:id:seeds-std:20191011110625j:plain
シーズの社員も早速使いこなしておりました
※トレーダーではありません

やっぱりあった Catalinaの問題点とは?

特に開発者に問題がありそうだったのが、Catalina + Google Chromeで発生しているであろう問題点を中心に書いていきたいと思います。

1. input type=”number” のstepが実際のstepの2倍になる問題

stepの指定はしていませんが、Catalina + Google Chromeの方は増やしていくと2ずつ増えていきます。問題ない場合は1ずつ増えていきます。


※Chrome Canaryでは修正されて?発生しない様子。

Chromeの対応待ちですかね。

2. ヒラギノ角ゴPro/ProNが無くなった?

Catalina + Google Chromeではヒラギノ角ゴPro/ProN(Sans Serif)が明朝体で表示されてしまう問題が発生しています。
Apple公開しているmacOS 10.15 Catalinaの組み込みフォントリストには存在しているので「ヒラギノ角ゴPro/ProNが無くなった」と言うことでは無さそうです。
デザイナーやフロントエンドエンジニア の方は要注意ですね。

f:id:seeds-std:20191011112730p:plainf:id:seeds-std:20191011112737p:plain
左がChrome 右がSafari

これもChromeの対応待ちですかね。。

3.Gitが使えなくなった?問題

Catalinaにして、エディターを開いてみると。。

xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun

こんなエラーが出ていました。
エラー文言でググればすぐ解決法はありました。

こちらのコマンドで対応出来ました。

xcode-select --install

4. zipファイルが解凍出来なくなった問題

f:id:seeds-std:20191011115340p:plain

zipファイルが解凍出来ない問題があるようです。
解凍出来ないパターンとして最初に考えられたのは

・日本語ファイルがダメ?
・暗号化されているとダメ?
・日本語のファイル名が含まれてても文字コードがUTF-8ならOK?
 と言うことが考えられました。

圧縮時の文字コードはUTF-8にしている場合が多いと思いますが、Windowsを想定している場合はSJIS-WINに変更している可能性もありますね。

回避策として

「ファイル名をアルファベットにしておく」が1番安全

と言うことになりそうです。

最後に

セキュリティの面やSidecarが便利すぎる点では更新した方がいいのでしょうが、新しいが故の問題点もあるので、注意は必要ですね。

この手のアップデートは時間がかかります。

かったりーな・・・

最後まで読んでいただきありがとうございました。 小川

AWSソリューションアーキテクトプロフェッショナル(SAP-C01) に合格しました

f:id:seeds-std:20191010165532p:plain

クラウド事業部の原口です。

AWSソリューションアーキテクトプロフェッショナル試験を受けてきて一度不合格となった末に合格しました。
合格点は750/1000点と結構お高め…
難しかったです。 勉強を初めてから1ヶ月半ほどかかりました。

一度不合格となってますし偉そうな事は言えないのですが、こんな勉強をしました、という事を書いてみたいと思います。

試験の概要

AWS 認定ソリューションアーキテクト – プロフェッショナル
AWS プラットフォームでの分散アプリケーションおよびシステムを設計するための
高度な技術的スキルと専門知識を認定します。
AWS でのクラウドアーキテクチャの設計およびデプロイに関する 2 年以上の実務経験を持つ方が対象です。
この試験で評価する能力は次のとおりです。
• AWS における、動的なスケーラビリティ、高可用性、フォールトトレランス、
信頼性を備えたアプリケーションの設計およびデプロイ
• 与えられた要件に基づいてアプリケーションを設計およびデプロイするための、適切な AWSサービスの選択
• AWS における複雑な多層アプリケーションの移行
• AWS におけるエンタープライズ全体のスケーラブルな運用の設計およびデプロイ
• コストコントロール戦略の導入

かなりのボリュームの試験です。
AWS 認定ソリューションアーキテクト – アソシエイト の上位版に位置する問題となります。

試験結果は 100~1000 点の範囲のスコアでレポートされます。最低合格スコアは 750 点です。スコ
アによって、試験での全体的な成績と合否がわかります。スケールドスコアモデルは、難易度にわず
かな違いのある複数の試験形式のスコアを平均化するために使用されます。

100点から?という単純な疑問とスケールドスコアモデルというものがわからなかったので調べてみましたが、
あまりよくわからなかったのですが「難易度が異なる試験問題をいい感じに調整」するモデルと解釈しました。
つまり問題によって配点が違ってくる、という事ですかね?

試験時間は170分。問題数は75問ですので1問あたり2~3分程度で解く必要があります。
試験合格の有効期限は3年みたいです。

その他詳細な試験ガイドは以下となります(公式)
試験ガイド

試験勉強

私はAWSを初めて触ってからもう5年くらいは経っていると思うのですが、
業務で触れるサービスが中心となってしまい、どうしてもよくわからないサービスというのは存在しました。
そのため、いったい自分は何が苦手なのか、を把握する事からはじめました

模擬試験

模擬試験を受けて再学習が必要な領域を特定と試験の感じの把握からはじめました
サンプル問題でもわかりますが、言い回しが独特でとにかく文章が長い、という印象です

公式ドキュメントの「よくある質問」

よくある質問を読み込むのを中心に行いました。
サービスの制限など実運用を検討する方へのドキュメントである為、
サービスのネックや落とし穴となりやす部分が集約されているものと感じました。

ホワイトペーパー

DR関連のものとストレージサービス関連のものはよく読みました。
AWS Well-Architectedなどはななめ読みしたくらいです。

blackbelt

よく知らないサービスはblackbeltを見ました。
スライドをぽちぽちーとしてたんですが、ちゃんと動画で見ると理解度が段違いだったのでできれば動画がいいと思います

AWS クラウドサービス活用資料集 | サービス別資料

心構え

膨大な文章量と170分

とにかく文章が長いので単純に疲弊してきます。
集中力を長持ちさせる自分なりの方法を見つける必要がありました
疲れてくると読んでるだけで頭に入ってない事が多くてそういう時に集中しなおせる方法を持ってるといいです
秘訣について「170分くじけない心が必要」と聞いて笑ってたんですが
本当に重要ではないかと思いました

正常性バイアスとの戦い

疲労してくると「正常正バイアス」がかかりやすくなる気がしました。
問題の選択肢はすべてその問題を解決できるものであったり、もっともらしい書き方をされていて
知識が不足していると簡単に迷います。
その状態で出てくるのが以下のような考え。

・実務ではこんなやり方はしないだろう
・こういう時は枯れた技術で望むべき
・問題文に定義されてないからこういう意味に違いない

これらが出てきた時は大体知識不足が原因で明確な説明ができない以上は知識不足であると自分に言い聞かせました。
わりとここで問題の深読みまでしだすと精神的にもハマるし時間も浪費します。

サービスや機能の特性を単語で関連付ける

ストリーミングデータの処理といえばKinesis。
といった形で、仮想的だけど実務的なRFPからAWSにおける提案例を連想できるようにしました。
実際実務として提案を心がけている事もありこの方法は自分に合った勉強法でした。

短期集中で行う

長いスパンで考えるよりも2週間くらいでがーーっとやった方がよいです

その他

試験にはPSIとピアソンVUEがありますが、可能な限りピアソンVUEでの受験をおすすめします!
PSIでは監督員と遠隔でチャットをしながら、カメラで常時監視されながらの試験となり、
「キーボードから手を離してはいけない」などのプレッシャーが半端なかったです笑

ピアソンVUEでも監督員はもちろん居ますが、口元に手をあてたり、頭を掻いたりしても問題はないので
この点は心理的負担がだいぶ減ります!

感想

正直合格の文字を見た時は喜びよりほっとしました。2,3回確認しました。(笑)
社内での人権ができてよかったです。

自信もつき、試験を通じた勉強を行った事で、より深く!AWSの理解が深まったという実感があります。
これからはプロフェッショナル原口としてよりお客様にピッタリのクラウド最適化した提案ができると思います!
お困りの事がありましたら、是非ご相談下さい!!

DevOpsとかの他の試験も受けていくぞー!って思ってたのですが
本当に疲れたので、とりあえずはアイスボーンをやります。
社内でもどんどんAWS認定の取得者を増やしたいですね。
これから試験を受ける方は頑張って下さい!

宣伝枠

AWSの無料相談会というものを行っています!
www.seeds-std.co.jp

弊社ではAWSが大好きなエンジニアを募集しています!じょいなす!
recruit.seeds-std.co.jp

Kotlin/JSのAWS Lambda関数を便利にしてみる

f:id:seeds-std:20191010160615p:plain

こんにちは, Web事業部の西村です
私の前回の記事 ではKotlin/JSを用いてLambda関数を書いてみました
しかし, dynamic を利用していたため使いにくい部分もあったと思います
今回はその点を改良しより使いやすくなるよう変更したいと思います

目次

過去の記事

開発環境

この記事では下記の環境で開発を行っています

  • AdoptOpenJDK 1.8.0_222-b10
  • IntelliJ IDEA Community 2019.2.2
  • Kotlin 1.3.50

プロジェクト

前回の記事 で作成したプロジェクトを利用します
プロジェクトの構成は下記のようになっています

KotlinLambda
├─.gradle/
├─.idea/
├─build/
├─gradle/
├─src/
│ └─main/
│   └─kotlin/
│     └─jp.co.seeds_std.lambda.kotlin/
│       └─handler.kt
├─build.gradle.kts
├─compress.zip
├─gradlew
├─gradlew.bat
└─settings.gradle.kts

Jsonを使って便利にしてみる

dynamicをなくす

Kotlin/JSには dynamic に似た Json があります
dynamic はJavaScriptのデータであったり, オブジェクトを格納することができますが, Json はKey-Value形式でのみ格納できるものとなっています
handler関数の引数, eventcontext はどちらもJavaScriptのJsonオブジェクトですのでKotlinの Json に変換できます
また, Callbackの第二引数もJsonオブジェクトを設定するためこちらも変更できます

handler.kt

fun handler(event: dynamic, context: dynamic, callback: (Error?, dynamic) -> Unit)

↑ が ↓ に変更できます

fun handler(event: Json, context: Json, callback: (Error?, Json?) -> Unit)

このJsonオブジェクトへのアクセスはMapのように利用してアクセスすることができます

event["body"] // こちらか
event.get("body") // こちらでデータの取得ができます

Callbackに渡すのJsonを関数で作れるようにする

API Gatewayでは下記のJsonを処理するようになっています *1

{
"isBase64Encoded": true|false,
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"multiValueHeaders": { "headerName": ["headerValue", "headerValue2", ...], ... },
"body": "..."
}

こちらをもとに引数が5つの関数を作成したいと思います
記述する場所はhandler関数の下になります

handler.kt

fun responseJson(statusCode: Int = 200, body: String = "{}", isBase64Encoded: Boolean = false, headers: Json = json(), multiValueHeaders: Json = json()) = json(
"statusCode" to statusCode,
"body" to body,
"isBase64Encoded" to isBase64Encoded,
"headers" to headers,
"multiValueHeaders" to multiValueHeaders
)
  • json() Jsonを作成する関数です/引数は vararg Pair<String, Any?> となっており json() と書くと空のJsonを作ることができます

Callbackに渡すよう変更する

現在handler関数は下記のようになっていると思います

handler.kt

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json, callback: (Error?, Json?) -> Unit) {
val response: dynamic = object {}
response["statusCode"] = 200
response.body = "Hello from Kotlin Lambda!"
callback(null, response)
}

この関数を先ほど作成した関数を用いた形に変更します

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json, callback: (Error?, Json?) -> Unit) {
val response = responseJson(body = "Hello from Kotlin Json Lambda!")
callback(null, response)
}

関数をデプロイする

前回と同様の手順を用いて関数をデプロイします
画面右側の Gradle タブを開き, kotlin_lambda -> Tasks -> other の順に開き, その中の compress をダブルクリックして実行します
ビルドに成功するとプロジェクトのディレクトリに compress.zip というファイルが更新されます
この生成されたファイルをコンソールからアップロードし, 保存します

動作確認

あらかじめ作成しておいたAPI GatewayのURLにアクセスし Hello from Kotlin Json Lambda! と表示されれば成功です

レスポンスをクラスに変更する

レスポンスはクラスを用いても影響が少ないためクラスに置き換えます
リクエストにクラスを利用しない理由については蛇足をご覧ください

まずは responseJson関数 を変更します

handler.kt

fun responseJson(statusCode: Int = 200, body: String = "{}", isBase64Encoded: Boolean = false, headers: Json = json(), multiValueHeaders: Json = json()) = json(
"statusCode" to statusCode,
"body" to body,
"isBase64Encoded" to isBase64Encoded,
"headers" to headers,
"multiValueHeaders" to multiValueHeaders
)

data class Response(
val statusCode: Int = 200,
val body: String = "{}",
val isBase64Encoded: Boolean = false,
val headers: Json = json(),
val multiValueHeaders: Json = json()
)

続いて, Callbackの引数を変更します

fun handler(event: dynamic, context: dynamic, callback: (Error?, Json?) -> Unit)

fun handler(event: Json, context: Json, callback: (Error?, Response?) -> Unit)

最後にレスポンスを変更します

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json, callback: (Error?, Json?) -> Unit) {
val response = responseJson(body = "Hello from Kotlin Json Lambda!")
callback(null, response)
}

@JsExport
@JsName("handler")
fun handler(event: Json, context: Json, callback: (Error?, Response?) -> Unit) {
val response = Response(body = "Hello from Kotlin Class Lambda!")
callback(null, response)
}

この変更ができたらデプロイし動作を確認します
Hello from Kotlin Class Lambda! と表示されれば成功です

最後に

いかがでしたでしょうか
Kotlinを用いていると dynamic では少し取り扱いにくく感じてしまいます
しかし Json にしてしまうことで,Mapのように利用でき, より使いやすいのではないかと思います
次回は非同期処理にする記事を書きたいと思います
ここまで読んでいただきありございました

Kotlin/JSのAWS Lambda関数でPromiseを使うようにする


蛇足

リクエストのほうもクラス使ったらだめなの?

注意事項はありますが、クラスを利用しても問題はないです

handler.kt

package jp.co.seeds_std.lambda.kotlin
import kotlin.js.Json
import kotlin.js.json
@JsExport
@JsName("handler")
fun handler(event: Event, context: Json, callback: (Error?, Response?) -> Unit) {
println("body: ${event.body} isBase64Encoded: ${event.isBase64Encoded}")
// event.copy() // Error!
val response = Response(body = "Hello from Kotlin Json Lambda!")
callback(null, response)
}
data class Event(val body: String?, val isBase64Encoded: Boolean)
data class Response(
val statusCode: Int = 200,
val body: String = "{}",
val isBase64Encoded: Boolean = false,
val headers: Json = json(),
val multiValueHeaders: Json = json()
)

この時ログに bodyisBase64Encoded の出力が行われます
その後 copy() を実行しようとした場合, 変数 eventEventクラスではなく Json となっていますので, 関数が見つからず実行時にエラーが出てしまいます
また, 注意点として private な変数はトランスパイルした際に変数名が変更されてしまうためうまく利用できません
そのため, リクエストの eventcontext はJsonで, レスポンスはKotlinのクラスを利用していくことがいいのかなと私は思います
蛇足も読んでいただきありございました

© SEEDS Co.,Ltd.