Qiitaの最新記事を教えてくれるアレクサスキルを作ろう　Alexa X Lambda X Golang　



# 1.はじめに

## 1.1目的
golangと、lambdaを使ってアレクサスキルと作りたくなったのでやってみる。

## 1.2環境

Windows(GitBash)
Go Version 1.22.0

## 1.3前提条件
-  Amazon 開発者アカウントの作成を事前に行う。下記リンクより、Amazon開発者アカウントの作成を元に準備してください

https://developer.amazon.com/en-US/blogs/alexa/post/31c9fd71-f34f-49fc-901f-d74f4f20e28d/alexatraining-firstskil.html
- 事前に[AWSアカウント](https://aws.amazon.com/jp/register-flow/)の作成を行ってください
- [AWSCLI](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html)が使える状態にする

# 2.Golangでソースを書き、Lambdaにデプロイしよう
アプリ名naviQiita(ナビキータ）で作成をしていきます。
以下の解説でアプリ名やリソース名などは自身が作成するものに適宜合わせてください。

## 2.1 コーディング



公式ドキュメントを参考に作成してみる

https://docs.aws.amazon.com/lambda/latest/dg/lambda-golang.html

1. goプロジェクトの準備を行います
適当な作業ディレクトリを作成しそのディレクトリ配下で下記コマンドを叩き、Go.modを作成しますmodule-pathは適宜自身の物に合わせてください(僕は、module-pathを"githun.com/keny-N/NaviQiita"にします)
    ```
    $ go mod init [module-path]
    go: creating new go.mod: module [module-path]
    ```
2. AWS Lambda go ADKのインストール
    ```
    $ go get github.com/aws/aws-lambda-go/lambda
    go: downloading github.com/aws/aws-lambda-go v1.46.0
    go: added github.com/aws/aws-lambda-go v1.46.0
    ```
3. ファイルを作成していく
- /cmd/alexa-skill/main.go
```main.go
package main

import (
	"context"

	"githun.com/keny-N/NaviQiita/internal/qiita"
	"githun.com/keny-N/NaviQiita/pkg/response"

	"github.com/aws/aws-lambda-go/lambda"
)

func Handler(ctx context.Context) (response.AlexaResponse, error) {
	items, err := qiita.FetchQiitaItems()
	if err != nil {
		return response.AlexaResponse{}, err
	}

	message := "最新のQiitaの記事を５つ紹介します。。: "
	for _, item := range items {
		message += item.Title + ", URL: " + item.URL + ". "
	}

	return response.CreateResponse(message), nil
}

func main() {
	lambda.Start(Handler)
}
```

- /internal/qiita/qiita.go
```qiita.go
package qiita

import (
	"encoding/json"
	"net/http"
)

type QiitaItem struct {
	Title string `json:"title"`
	URL   string `json:"url"`
}

func FetchQiitaItems() ([]QiitaItem, error) {
	resp, err := http.Get("https://qiita.com/api/v2/items?page=1&per_page=5")
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	var items []QiitaItem
	if err := json.NewDecoder(resp.Body).Decode(&items); err != nil {
		return nil, err
	}

	return items, nil
}

```

- /pkg/response/response.go
```response.go
package response

type AlexaResponse struct {
	Version           string   `json:"version"`
	SessionAttributes struct{} `json:"sessionAttributes"`
	Response          struct {
		OutputSpeech struct {
			Type string `json:"type"`
			Text string `json:"text"`
		} `json:"outputSpeech"`
	} `json:"response"`
}

func CreateResponse(message string) AlexaResponse {
	return AlexaResponse{
		Version: "1.0",
		Response: struct {
			OutputSpeech struct {
				Type string `json:"type"`
				Text string `json:"text"`
			} `json:"outputSpeech"`
		}{
			OutputSpeech: struct {
				Type string `json:"type"`
				Text string `json:"text"`
			}{
				Type: "PlainText",
				Text: message,
			},
		},
	}
}

```

```go.mod
module githun.com/keny-N/NaviQiita

go 1.22.0

require github.com/aws/aws-lambda-go v1.46.0 // indirect

```

```go.sum
github.com/aws/aws-lambda-go v1.46.0 h1:UWVnvh2h2gecOlFhHQfIPQcD8pL/f7pVCutmFl+oXU8=
github.com/aws/aws-lambda-go v1.46.0/go.mod h1:dpMpZgvWx5vuQJfBt0zqBha60q7Dd7RfgJv23DymV8A=
```


4.以下のコマンドを実行して、Linux向けの実行可能ファイルをビルドします
"main"という名前の実行ファイルが生成されます

    ```
    $ GOOS=linux GOARCH=amd64 go build -o bootstrap cmd/naviQiita/main.go  
    ```
5.mainファイルをzip形式に圧縮する  
**(注意)ここが一番ハマッタ**
windows環境で圧縮する場合は、[公式の手順通り](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/golang-package.html#golang-package-windows)行ってください。
WindowsでそのままZIPを作成したらパーミッションエラーで怒られます。
    
 ```bash
go install github.com/aws/aws-lambda-go/cmd/build-lambda-zip@latest
```

```powershell
# このコマンドだけpowershellでたたきました（他はGitbash）
$ $env:GOOS = "linux"
$ $env:GOARCH = "arm64"
$ $env:CGO_ENABLED = "0"
$ go build -tags lambda.norpc -o bootstrap cmd\naviQiita\main.go
$ ~\Go\Bin\build-lambda-zip.exe -o myFunction.zip bootstrap
```

6.最終的なフォルダ構成
githubにソースコードを挙げているので参考にしてください

https://github.com/keny-N/NaviQiita

```bash
└─NaviQiita
    │  bootstrap
    │  go.mod
    │  go.sum
    │  myFunction.zip
    │
    ├─cmd
    │  └─naviQiita
    │          main.go
    │
    ├─internal
    │  └─qiita
    │          qiita.go
    │
    └─pkg
        └─response
                response.go
```

## 2.2 Lambdaの準備
東京リージョンにリソースを作成します（AWSCLIの設定であらかじめ東京リージョンにデフォルトで繋がるようにしています）

1. Lambdaのロールを作成
    ```
    $ aws iam create-role --role-name navi-qiita --assume-role-policy-document '{"Version": "2012-10-17","Statement": [{ "Effect": "Allow", "Principal": {"Service": "lambda.amazonaws.com"}, "Action": "sts:AssumeRole"}]}'
    {
        "Role": {
            "Path": "/",
            "RoleName": "navi-qiita",
            "RoleId": "AROA4MTWKLOMIZOLHCBGP",
            "Arn": "｛ここに作成したロールのArnが記載される｝",
            "CreateDate": "2024-03-29T17:43:18+00:00",
            "AssumeRolePolicyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                    {
                        "Effect": "Allow",
                        "Principal": {
                            "Service": "lambda.amazonaws.com"
                        },
                        "Action": "sts:AssumeRole"
                    }
                ]
            }
        }
    }

    ```
1. Lambda関数を作成する
Arnにはロールを作成したときに返ってきたArnを入力する
    ```
    $ aws lambda create-function --function-name "NaviQiita" --runtime provided.al2023 --handler bootstrap --zip-file fileb://myFunction.zip --role arn:aws:iam::xxxxxxxx --architectures arm64
    ```
1. 作成されたことを確認する
AWSのLambdaの画面を開き、リソースが作成されていることを確認する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/dbd098ed-b6fe-2281-78ef-59fbfd0204ba.png)




# 3.アレクサスキルを作成しよう


Alexa公式ページの第1回: 初めてのスキル開発を参考にアレクサスキルを作成していきましょう
※記事が古いので一部UIが違う部分もあるので注意

参考 ↓ 

https://developer.amazon.com/en-US/blogs/alexa/post/31c9fd71-f34f-49fc-901f-d74f4f20e28d/alexatraining-firstskil.html

## 3.1 アレクサスキルの作成

1. [トップメニュー](https://developer.amazon.com/ja)よりAlexaを押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/2e789a13-a4ed-09f8-ccb2-c4dcaa511783.png)

1. Alexaスキル開発を押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/d4f21077-972a-a70d-645f-e7cd672b8f99.png)

1. コンソールを押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/c04d5352-7001-3f2c-12eb-486d484b5392.png)

1. [Alexa開発者コンソール](https://developer.amazon.com/alexa/console/ask)が開かれるので、スキルの作成を押下する  
作成したスキルはこの画面で後ほど確認することもできます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/2ebc7acd-b957-8c31-0d45-3db8d73f490b.png)

1. 各項目を入力し、次へを押下する
スキル名：Alexaスキルの名前（好きなものを入力しよう）
プライマリロケール：僕は日本語しかできないので日本語を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/08e3db7c-5e44-15d8-1285-89adf7689b05.png)

1. 各項目を選択し次へを押下する
エクスペリエンスタイプ：ニュース（作るスキルに合わせて好きに選択してください）
モデル：カスタム
ホスティングサービス：独自のプロビジョニング
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/4b648b74-b0eb-630a-17bc-fdf2cf369ee4.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/5c79ff40-cb4d-83bc-5f3a-ff5176316f8e.png)

1. スクラッチで作成を選択し、次へを押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/f9e68410-b9e7-cd5c-90a8-fd5989f121e7.png)

1. 入力内容を確認し、スキルを作成するを押下する
ボタン押下後、時間がたつと自動で画面が切り替わります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/dcc24d0b-8f2c-05eb-aa03-3d99f7605eec.png)

1. 下記画面の通りになっていればOKです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/4a4f10ed-c0bc-21af-fbb0-2dbfed04295d.png)

1. スキルの呼び出し名を変更する
今回はアレクサスキル名と同じにしていますが、呼び出し名の要件や、実際にアレクサにスキルを起動してもらうときに言いやすい、覚えやすい呼び出し名にすることをおすすめします。
呼び出し名を変更後、画面右上のスキルをビルドを押下してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/8a5b20fe-bbb2-dab1-eb49-416b090a7415.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/9a73cd8d-640a-e224-3764-3c890f6b28af.png)

1. Lambdaと紐づけ

Lambda側でトリガーの追加
作成したLambda関数の詳細画面に移動し、トリガー -> トリガーを追加を押下する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/06b5920c-9ffb-b51b-4eff-06e04869582a.png)
AlexaのAlexaSkillsKitを選択し、スキルIDには作成しアレクサスキルのIDを入力する。入力後追加を押下する
SkillIDはAlexaスキルのエンドポイントの画面より確認できる（後述）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/8915888b-3647-6acf-c7c7-efcdd03cd2f4.png)
トリガーが追加されたことを確認する。
次の手順で関数のARNが必要になるのでコピーしておく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/b0c8b12d-7ff1-b5cd-14e2-bad96f7c372c.png)


エンドポイントを押下し、デフォルトの地域の欄に先ほど作成したLambdaのARNを入力します。
この画面で、スキルIDを取得できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/e664a58a-7d9c-ad23-ef31-f5029174c97f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/98d417d0-41fa-c975-6bcc-214eef2ab134.png)
保存ボタンを押下し、画面右下に緑のメッセージが表示されればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/24fce2c2-63e9-0fcc-b47e-62a8743c54eb.png)

## 3.2 スキルのテスト

1. 開発者コンソール画面上部のテストを押下する
1. スキルテストが有効になっているステージを開発中に変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/5ca57fb5-ed61-58df-a15b-2b32d60ebde2.png)

1. テスト実行
ナビキータ（スキル呼び出し名）を起動してと入力する
Qiitaの記事のタイトルとURLが返ってきたら成功😎
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3758322/0570dc26-4a6b-04cf-4249-1f81c85ecbbf.png)


# 4.感想

アレクサスキルをLambda,golangを混ぜて作成してみて楽しかった。
Qiitaの記事タイトルとURLを返すようにしているがここらへんをもう少し工夫してアレクサスキルで実用的になるようにできればいいなと思った。
記事の中身をよみあげるなどなど。



## ハマッタポイント

### Lambdaにファイルをアップしたらパーミッションエラーで怒られた

Windows環境で、ファイルに適切なパーミッションをつけて圧縮しても効果がないらしい。（詳しい人おしえてください）
なので、公式が案内している方法でzipファイルを作成する必要があった
```
#### エラー内容
Error: fork/exec /var/task/bootstrap: permission denied
```
#### 解決策

Windows での .zip ファイルの作成の手順通り圧縮すればいけた
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/golang-package.html#golang-package-windows