AlexaスキルでGo

前回([Alexa-hostedスキルを使用してAlexaスキルを作ってみる](https://qiita.com/ikegam1/items/9bac317f9263860a3a9c))、Go言語でAlexaスキルで作ろうと思って始めたものの、途中から脱線してAlexa-hostedスキルの方に流れてしまいました。
改めてGo言語で。前回作ったやつのバックエンド部分は捨てる想定です。
なので作るスキルは一緒。

## Go言語をLambdaにデプロイする

しかし、やはりというかなんというか、すでにやっている方おられますね。
[AlexaスキルをGoとServerlessで書いてみた](https://qiita.com/yamaryu0508/items/57c0aea47f97a6b76335)

このままやったらだいたいできるんじゃないかしら。
進めていて詰まる所があったら記します。なければこの記事には公開の意義ないかもしれん。

まずはこちらを参考に進める

https://serverless.com/blog/framework-example-golang-lambda-support/

```bash
$ serverless create -u https://github.com/serverless/serverless-golang/ -p alexa-kamefood-go
$ cd alexa-kamefood-go
$ vi serverless.yml
$ diff serverless.yml serverless.yml.orig 
25,26c25,26
<   stage: dev
<   region: ap-northeast-1
---
> #  stage: dev
> #  region: us-east-1
57,59d56
<     memorySize: 128
<     events:
<       - alexaSkill
$ go get github.com/aws/aws-lambda-go/lambda
```

で、おおよそ[こちら](https://github.com/yamaryu0508/alexa-skills-kit-color-expert-go)のレポジトリの内容でdeployしたらうまくいきました。

```bash
$ sls deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Warning! You are using an old syntax for alexaSkill which doesn't restrict the invocation solely to your skill. Please refer to the documentation for additional information.
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.....
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service alexa-kamefood-go.zip file to S3 (10.04 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...................
Serverless: Stack update finished...
Service Information
service: alexa-kamefood-go
stage: dev
region: ap-northeast-1
stack: alexa-kamefood-go-dev
resources: 6
api keys:
  None
endpoints:
  None
functions:
  hello: alexa-kamefood-go-dev-hello
layers:
  None
```

で、```alexa-kamefood-go-dev-hello``` というfunctionができております。（functionの名称どうでも良かったのでhelloのままです。。）

![image.png](https://qiita-image-store.s3.amazonaws.com/0/308709/9bff2bf9-fdb7-a63e-2551-2df9fe7075e0.png)

テストしても普通に使える。
結局、すんなりといきました。

## コードを書く

その後、[こちら](https://github.com/yamaryu0508/alexa-skills-kit-color-expert-go)をインスパイアしつつ、コードを仕上げていきます。
なお、json読みこむようにしたので```serverless.yml``` 少し変えました

```yml:serverless.yml
package:
 exclude:
   - ./**
 include:
   - ./bin/**
   - ./jsons/**
```

jsonのあたりのコードはこんな感じです。

```main.go
var (
        // ErrInvalidIntent is error-object
        ErrInvalidIntent = errors.New("Invalid intent")
        FoodJsonFile string = "./jsons/foods.json"
)

.....

        // JSONファイル読み込み
        foods := make(map[string]string)
        bytes, err := ioutil.ReadFile(FoodJsonFile)
        if err != nil {
            log.Fatal(err)
        }
        // JSONデコード
        if err := json.Unmarshal(bytes, &foods); err != nil {
            log.Fatal(err)
        }

        if food, ok := intent.Slots["foodSlot"]; ok {
            if speech, ok := foods[food.Value]; ok {
                speechOutput = speech
            }else{
                speechOutput = "すみません。" + food.Value + "についてはわかりませんでした。他の食べ物の名前を聞いてみてくださいね。ではまた。"
            }
        } else {
            speechOutput = "すみません。わかりませんでした。他の食べ物の名前を聞いてみてくださいね。ではまた。"
        }

```

```encoding/json``` を使っています。
なお、コードについては参照元のライセンス表記がなく、ちょっと公開するのがグレーなので公開は控えておきます。

## 申請

実はAlexa-hostedのままで申請をしていたのですが、取り下げつつ、Goのlambda functionのものと差し替えてみました。

で、切り替え後のテスト

![82.png](https://qiita-image-store.s3.amazonaws.com/0/308709/087a9bd0-ebb3-aecb-4b4a-1a698fff0e6f.png)

うん、大丈夫そう。
Go言語の方のLambda functionで申請してみます。

## おまけ

で、これで終わったらちょっとつまんないので少し遊ぶ。
git hubに上げたら勝手にdeployするようにしたいです。
aws codestarを使ってみます。

### 開いてロール作成
![83.png](https://qiita-image-store.s3.amazonaws.com/0/308709/09674d32-25db-427f-46a8-4002bb042263.png)

### Go言語を選択し、GitHubアカウントに連携します
![84.png](https://qiita-image-store.s3.amazonaws.com/0/308709/104b44bc-286d-63fd-0566-22a8157fb8b3.png)

### buildspec.ymlとtemplate.yml編集
けっこう適当なので余計な部分とかあるかもですが。

```yml:buildspec.yml
version: 0.2

phases:

  install:
    commands:

      # AWS Codebuild Go images use /go for the $GOPATH so let's symlink our
      # application source code into that directory structure.
      #- ln -s "${CODEBUILD_SRC_DIR}" "/go/src/handler"

  pre_build:
    commands:

      # Make sure we're in the project directory within our GOPATH
      #- cd "/go/src/handler"

      # Fetch all dependencies
      - go get github.com/aws/aws-lambda-go/lambda
      - go get encoding/json
      - go get io/ioutil

  build:
    commands:
      # Build our go application
      - go build -o bin/main main.go
      #- serverless deploy -v
      # Copy static assets to S3, and package application with AWS CloudFormation/SAM
      - aws cloudformation package --template template.yml --s3-bucket $S3_BUCKET --output-template template-export.yml

  post_build:
    commands:
      # Do not remove this statement. This command is required for AWS CodeStar projects.
      # Update the AWS Partition, AWS Region, account ID and project ID in the project ARN on template-configuration.json file so AWS CloudFormation can tag project resources.
      - sed -i.bak 's/\$PARTITION\$/'${PARTITION}'/g;s/\$AWS_REGION\$/'${AWS_REGION}'/g;s/\$ACCOUNT_ID\$/'${ACCOUNT_ID}'/g;s/\$PROJECT_ID\$/'${PROJECT_ID}'/g' template-configuration.json

artifacts:
  type: zip
  files:
    - template-export.yml
    - template-configuration.json
```

```yml:template.yml
AWSTemplateFormatVersion: 2010-09-09
Transform:
- AWS::Serverless-2016-10-31
- AWS::CodeStar

Parameters:
  ProjectId:
    Type: String
    Description: AWS CodeStar projectID used to associate new resources to team members
  CodeDeployRole:
    Type: String
    Description: IAM role to allow AWS CodeDeploy to manage deployment of AWS Lambda functions
  Stage:
    Type: String
    Description: The name for a project pipeline stage, such as Staging or Prod, for which resources are provisioned and deployed.
    Default: ''

Globals:
  Function:
    AutoPublishAlias: live
    DeploymentPreference:
      Enabled: true
      Type: Canary10Percent5Minutes
      Role: !Ref CodeDeployRole

Resources:
  hello:
    Type: AWS::Serverless::Function
    Properties:
      Handler: bin/main
      Runtime: go1.x
      Role:
        Fn::GetAtt:
        - LambdaExecutionRole
        - Arn
      Events:
        AlexaSkillEvent:
          Type: AlexaSkill
  LambdaExecutionRole:
    Description: Creating service role in IAM for AWS Lambda
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub 'CodeStar-${ProjectId}-Execution${Stage}'
      AssumeRolePolicyDocument:
        Statement:
        - Effect: Allow
          Principal:
            Service: [lambda.amazonaws.com]
          Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        -  arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/CodeStar_${ProjectId}_PermissionsBoundary'
```

### いらないファイルを削ったり、ソースを置いたり

publicとか、main-test.goとか消しました。
あとはソースを上書き。

### githubにpush

で勝手にlambda関数が作られます。
ちゃんと動きました。

![85.png](https://qiita-image-store.s3.amazonaws.com/0/308709/83cdd9be-7bdc-9070-52d8-23b9b83d1622.png)

CodeStar使って、Codepipelineの一式(CodeCommit or GitHub, CodeBuild, CodeDeploy)がまるっと作られた感じです。
あら、便利。

というか、CodeBuild内でSeverless FrameWorkのコマンド書いちゃえばCode Buildだけでもできそう。