20200224のGoに関する記事は9件です。

PyPortal で TinyGo プログラミングを始めよう

この記事では、以下の環境で Windows 10 環境で TinyGo + Pyportal を試した時のメモをまとめます。

  • Windows 10 Home / Pro 64bit
  • TinyGo 0.12 → docker の tinygo/tinygo-dev を使う事
  • PyPortal

個別に記載しない限りは Windows 10 を対象としたメモであることに注意。
また、基本的には PyPortal でしか確認していませんが、他のボードも大差ないと思います。

2020/02/25 追記)
以下の Windows 版 tinygo 0.12 だと PyPortal で float 演算をしようとするとフリーズする。
現時点では docker の tinygo/tinygo-dev を使用する事で回避できる。
以下の本文中の記載は、随時 tinygo/tinygo-dev での確認結果をベースとしたものに書き換えていきます。

  • tinygo version 0.12.0 windows/amd64 (using go version go1.13.1)

最初に

メモを書くきっかけ

TinyGo でマイコンプ遊びをしようと思ったがまとまった情報が少なかった。
基本的には TinyGo 専用ボードというのはないので、書き込み方法含め不明点が多かった。
同僚が Windows 10 + Adafruit Trinket M0 で TinyGo デビューしようとして躓いていた。
ボード毎に異なる部分もあり L チカまですんなり進むようにサポートしたいという思いがあった。

TinyGo とは

マイコンや WASM などの Small Places 向けの Go Compiler です。
ここでは Go の文法でマイコン開発ができるもの、という程度の認識でよいです。

PyPortal とは

Adafruit 社の 3.2 インチカラー液晶タッチディスプレイ (320x240) な IoT ディスプレイマイコンボード。
基本的には Arduino や CircuitPython での開発が想定されているが、 TinyGo でも 0.12 でサポートされた。
ESP-WROOM-32 が搭載されていて Wi-Fi 経由で何かをしたり、等も可能。

マイコンは Microchip 社の ATSAMD51J20 (Arm Cortex-M4 120MHz) が搭載されている。

2020/02/24 時点で、スイッチサイエンスの値段は 8,767 円で、在庫は残り 8 個となっている。

4116-00.jpeg

TinyGo 対応ボード

オフィシャルで対応が謳われているものについては以下に列挙されている。
AVR / RISC-V / Xtensa / ARM Cortex-M などがサポートされている。
現時点では ARM 系が開発の中心となっているので、新しく買うなら ARM 系のボードで試すのが良いはず。

なぜ Pyportal を選んだのか

PIC16F あたり?からデビューした世代なので、楽ができるオールインワンなボードが欲しかったから。

  • 本体だけでそれなりに遊べそう
    • ブレッドボードを使わなくてもいい
  • ネットワークにそのままつながる
  • TinyGo 0.12 で新規サポートされた
  • FOSDEM 2020 (2020/02) のデモ でも使われていた
    • 画面描画部分の TinyGo のソースが手に入る
  • CPU (ATSAMD51J20) が Adafruit Feather M4 等の他の TinyGo ターゲットでも使われている

とはいえ、好きなのを買うのが良いと思います。
引っかからずに進むためには、ドキュメントが多いボードを使うのが安全です。
引っかかるのも経験だし勉強になるのも、そういう考え方も OK です。

サンプルコード

最初にどういうコードをビルドして試せばよいか悩むと思います。
自分も悩みました。

とりあえず以下を書き込むことで、基板上の LED を点滅させることができます。
動作確認が出来たら、反転周期を切り替えてみる等をしてみると良いです。

以下のソースコードは、 TinyGo のオフィシャルにあるサンプルになります。
PyPortal 環境では、液晶の裏側の赤 LED が machine.LED として設定されています。
他のボードでも動く (ように machine.LED とかがボード毎に設定され続ける) と思います。

ビルド方法と書き込み方法は後述。

package main

import (
    "machine"
    "time"
)

func main() {
    led := machine.LED
    led.Configure(machine.PinConfig{Mode: machine.PinOutput})
    for {
        led.Low()
        time.Sleep(time.Millisecond * 1000)

        led.High()
        time.Sleep(time.Millisecond * 1000)
    }
}

TinyGo の始め方

TinyGo のインストール

2020/02/21 時点の最新版である tinygo0.12.0.windows-amd64.zip をダウンロード&解凍し C:\tinygo 以下に配置します。

その後、環境変数 PATH に C:\tinygo\bin を追加します。

$ set PATH=C:\tinygo\bin;%PATH%%

実際にはファイルの場所はどこでも良いので適宜好きな場所に読み替えても OK です。
とにかく tinygo の実行体 (Windows だと tinygo.exe) に PATH が通ってればよいです。

なお、上記では Windows Native 版を紹介しましたが Docker ベースでも開発可能です。

2020/02/25 追記)
ビルドした実行体に何か問題がある場合は Docker の tinygo/tinygo や、より新しい開発版である tinygo/tinygo-dev を使う事。

ビルドの前準備

ビルドに必要な依存ライブラリ等は事前に vendoring しておきます。
この時の Go は Go1.13 ではなく、また Go1.12 の最新版ではなく少し古めのものである必要があります。

ここでは、 Go の 1.12.14 をインストールします。
注意) 以下を実施する前に Go 1.13 等をインストールしておく必要があります)

go get golang.org/dl/go1.12.14
go1.12.14 download

その後、開発ディレクトリにて go mod vendor を実行します。

set GO111MODULE=on
go1.12.14 mod init
go1.12.14 mod vendor

正しく実行できると、 import している依存ライブラリが ./vendor 以下に配置されます。
例えばあるプロジェクトだと以下のようになります。
vendor 以下に tinygo.org/x/drivers 以下のファイルが追加されているのが分かります。

./go.mod
./go.sum
./touch.go
./vendor/modules.txt
./vendor/tinygo.org/x/drivers/ili9341/ili9341.go
./vendor/tinygo.org/x/drivers/ili9341/parallel_atsamd51.go
./vendor/tinygo.org/x/drivers/ili9341/README.md
./vendor/tinygo.org/x/drivers/ili9341/registers.go
./vendor/tinygo.org/x/drivers/LICENSE
./vendor/tinygo.org/x/drivers/touch/point.go
./vendor/tinygo.org/x/drivers/touch/resistive/fourwire.go

ビルド方法

Windows Native 版の TinyGo を使っても良いですし、 docker 版を使っても良いです。
それぞれの実行方法は以下の通り。

ビルド方法 (Windows Native 版 TinyGo)

tinygo build -o app.uf2 -target pyportal [PATH TO YOUR PROGRAM]

ビルド方法 (docker 版 tinygo/tinygo)

TinyGo Tutorial - GolangRdyJp に色々記載があるので参照すると良いです。

簡単に書くと以下でビルドします。
Windows 10 Home 等で Docker Toolbox on Windows を使っていて、 Docker Quickstart Terminal (bash) で実行する分には以下が実行可能です。

docker run -it --rm -v $PWD:/go/src/github.com/user/repo \
-w /go/src/github.com/user/repo \
-e GOPATH=/go \
tinygo/tinygo tinygo build -o app.hex -target pyportal .

ただし、 Windows 10 Pro + Docker Desktop + cmd.exe だったりすると以下のようになります。
※カレントディレクトリが %GOAPTH%/src/github/com/user/repo である場合

docker run -it --rm -v %GOPATH%/src/github.com/user/repo:/go/src/github.com/user/repo \
-w /go/src/github.com/user/repo \
-e GOPATH=/go \
tinygo/tinygo tinygo build -o app.hex -target pyportal .

更には、 Docker Toolbox on Windows を使っているけど cmd.exe で実行したい場合は上記だとうまく動かず下記のように実行する必要があります。
試した感じでは Docker Toolbox on Windows の docker の場合は /c/Users のように / 始まりかつ小文字のドライブレターにする必要があります。

docker run -it --rm -v /c/Users/USER/go/src/github.com/user/repo:/go/src/github.com/user/repo \
-w /go/src/github.com/user/repo \
-e GOPATH=/go \
tinygo/tinygo tinygo build -o app.hex -target pyportal .

正直覚えにくいし面倒だと思いましたので、 tinygo-docker というヘルパーコマンドを作りました。
良かったら使ってみてください。
Windows Native 版 TinyGo と限りなく同じやり方で tinygotinygo-docker に変更すればビルドできます。
ただし docker 経由なので flash は出来ません。

tinygo-docker build -o app.uf2 -target pyportal .

tinygo-docker.gif

2020/02/25 追記)
上記では、 tinygo/tinygo を使いましたが、 tinygo/tinygo-dev を指定することで最新の開発版を使うことができます。
手元の環境において Windows TinyGo 0.12 + PyPortal だと float 演算でマイコンがフリーズしてしまいますが、 tinygo/tinygo-dev だと動きました。
以下のようしてビルドを実行します。

docker run -it --rm -v $PWD:/go/src/github.com/user/repo \
-w /go/src/github.com/user/repo \
-e GOPATH=/go \
tinygo/tinygo-dev tinygo build -o app.hex -target pyportal .

tinygo-docker では以下のように設定できます。
引数 --docker-image の位置は tinygo-docker の直後に指定する事。

tinygo-docker --docker-image tinygo/tinygo-dev build -o app.uf2 -target pyportal .

マイコンへの書き込み方

Windows の場合のみ、 PyPortal に書き込む前に都度 書き込み可能モード に切り替える必要があります。
液晶裏側のリセットをダブルタップすることで 書き込み可能モード に入ります。
(Windows 以外の場合は、 オフィシャルドキュメント を読む限り何もしなくてもよさそう)

その後、

  • Windows Native 版 TinyGo を使って書き込む
  • マウントされたドライブ (PORTALBOOT) に作成した *.uf2 ファイルをコピー

のいずれかの方法で書き込みます。

【備考】
自分は最初に UF2 をアップデートしたのですが、おそらく出荷時バージョンで問題ないかと思います (未確認)。
上記を試してみても書き込み出来ない場合は、 UF2 を update してみてください。

Windows Native 版 TinyGo を使って書き込む

上記のマイコンボード毎のドキュメントの記載にないですが、実際には -port の指定が必須です。
-port で指定するポートは、デバイスマネージャー (Win-R > devmgmt.msc) から確認できます。
後述の画像の例だと COM4 を指定する必要があります。

以下の例では、再ビルドしてマイコンへの書き込みまで実施します。

tinygo flash -port COM4 -target=pyportal [PATH TO YOUR PROGRAM]

devmgmt.png

マウントされたドライブに *.uf2 ファイルをコピーして書き込む

マウントされたドライブに作成した *.uf2 ファイルをコピーすることで書き込みができます。
書き込み後は自動的にリセットして、書き込んだファイルの動作を行います。
例えば以下のようなコマンドで書き込みすることができます。

$ copy app.uf2 D:

参照資料等

マイコンボード毎の TinyGo のドキュメント

以下にあります。

PyPortal については以下にあります。

周辺デバイスのドライバ

TinyGo 全般用として、様々な周辺デバイス用のドライバが以下あります。

例えば PyPortal の液晶は ILI9341 TFT Display なので以下を使うと簡単に画面描画できます。

PyPortal 用のものについてのまとめは以下。

日本語情報リンク

雑多なメモ/困りごと/制限事項など

  • math.Abs() 関数を使うとフリーズする
    • 2020/02/25 加筆) Windows Native 0.12 および docker の tinygo/tinygo だとフリーズする
    • 2020/02/25 加筆) tinygo/tinygo-dev であればフリーズしない
  • float64 を返す関数を使うとフリーズする
    • 2020/02/25 加筆) docker の tinygo/tinygo-dev であればフリーズしない
  • goroutine は LLVM coroutine を使ってエミュレートしている
  • goroutine は GOMAXPROX = 1 時の動きに近い
    • time.Sleep() や chan 操作時などに異なる goroutine に切り替わる
  • Windows 10 だと USB-CDC が動いてなさそう
    • 本来は print() とか println() とかからシリアルポートに書き込める感じ
    • デバイスマネージャーで COM ポートとして認識しない
    • ここが解決したら ResetProcessor() が動くようになってリセットボタンのダブルタップが不要になりそう
  • tinygo flash する時、 taget に従ったファイルが読み込まれる (target/pyportal.json) が、 flash-method が msd なので本当は flash-1200-bsp-reset は false が正しいはず
    • この部分が (少なくとも windows 環境に対しては) 間違っているので公式ドキュメント通りに書き込めず -port 指定が必要となっている
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今日からGO言語 入門 〜Part2 Import 〜

Go言語 Importについて

Importは、Goが標準で提供するライブラリ(またはパッケージ)をインポートするためのもの

例)
- fmt
- os
- time

などなど。
パッケージの一覧はこちら

Importの書き方

main.go
import "fmt"

複数インポートする場合は、

main.go
import (
  "fmt"
  "time"
  "os/user"
)

と書くことができる

go docを使用して、コンソールからライブラリ情報を閲覧する方法

[形式]

$ go doc ライブラリー名

[例]

$ go doc fmt
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

今日からGO言語 入門 〜Part1 Hello World 〜

Go言語(Golang)とは

Go言語は、「Go」や「golang」とも呼ばれています。
2009年にGoogleが開発したオープンソースの静的型付プログラミング言語であり、Google社内におけるソフトウェア開発の生産性や拡張性のために開発されました。
Go言語の特徴として、

  • 実行速度が速い
  • 並列処理に強い
  • 拡張性が高い
  • 消費リソースが少ない
  • シンプルな言語構造

などなど、日本ではまだまだ少ないですが、今後伸びてくる言語だと私は思っています。
Go言語についての詳細はこちら

Go言語の学習のため、投稿してアプトプットして行こうかなと思っています。

Go言語をインストールする

Go言語のインストール方法については、下記のリンクの公式サイトからファイルをダウンロードし、インストールしてください。
公式サイト

インストールが完了したら、Windowsならコマンドライン、Macならターミナルを起動し、以下のコマンドを入力してください。
Goのバージョンが表示されていれば、インストールが完了しています。

$ go version
go version go1.13.4 darwin/amd64

実際にプログラミングして動かしてみる

とりあえず、最初なのでHello Worldをコンソールに表示させたいと思います。

下記のソースをコピーしてファイルに貼り付けます。

そして、ファイルの名前をmain.goという名前で保存します。

main.go
package main

import "fmt"

func main(){
  fmt.Prilnt("Hello World")
}

下記のコマンドを実行すれば、Hello Worldがコンソールに表示されます。

少しだけ、説明すると、fmtというのは、Go言語が提供する標準のライブラリのようなもので、

今回の場合、コンソールに表示するために使用しています。

またGo言語は、C言語とかと同じように、func mainを書かないとエラーに

なってしまいます。

$ go run main.go
Hello World
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GoでValidationを実装してみる①

GoでValidationを実装してみる①

こんにちは、株式会社アクシス福岡オフィスのueharaです。
この記事は福岡支部にて定期的に行っている開発合宿での内容を記事にした物です。
開催された日時は「2020/01/25」と約1ヶ月前に行われたものとなり、大分投稿が遅くなってしまいましたが、色々と一旦落ち着いたのでやっとのことで投稿するに至りました。

私がこの開発合宿で記事を上げるのは2回目となり、基本的には共同開発しているSNSアプリのバックエンド回りの実装を記事にしています。
興味のある方は、前回の記事も読んで頂けると嬉しいです。

では、早速始めます!
今回はGoを使ってEmailのValidationを実装したいと思います。

要件

ユーザによる新規登録実施前にEmailの重複、及びリクエストされたEmailの文字列が正しい形となっているかをチェックする機能。

利用シーン(ユーザーストーリー)

  1. SNSアプリに初めてアクセスする
  2. 登録制のサイトなので「新規登録」ボタンをクリックする
  3. 新規登録画面に遷移する
  4. メールアドレスを入力して次へ

上記「手順4」にてユーザーが「次へ」ボタンをクリック後にフロントエンド 側でリクエストデータを詰めてバックエンド側で処理します。この時Emailのバリデーションを実施します。

設計

エンドポイント、インタフェース(リクエストデータやレスポンスデータ)を定義していきたいと思います。

Endpoint

POST /users/check_email

インタフェース

リクエストデータ

{
  "email": "xxx@xxx.com"
}

レスポンスデータ

{
    "status": HTTP STATUS
    "message": Successful Message or Failed Message
}
  • 成功
    • status: 200
    • message: successful!
  • リクエストメソッドがPOST以外
    • status: 400
    • message: request method type is need post
  • Content-Typeが”application/json”以外
    • status: 400
    • message: Content-Type entity header is need “application/json”
  • emailキーの値がvalidationに通らない
    • status: 400
    • message: validation target value format is wrong
  • Emailに重複がある
    • status: 422
    • message: already registered

実装方針

go-playground/validator」を利用していきます。
そのため、「emailキーの値がvalidationに通らない」はこのパッケージに全て任せちゃいます。

また、DB操作は jinzhu/gorm を利用します。

実装

今回は「go-playground/validator」を利用した実装とgormを利用したDatabase参照を必要とするvalidationは実装できていません。

そのため、今回の対象となるのは以下です。

  • POSTメソッドでない場合
    • statusが400
    • messageが「request method type is need post」であること
  • Content-Typeが”application/json”以外である場合
    • statusが400
    • messageが「Content-Type entity header is need “application/json”」であること

本来はJSONで返ってくる値のアサーションまでを行いたかったのですが、できませんでした。
なので、「意図した真偽値を返すこと」をテストするところまで実装してみました。
JSONをアサーションするにはエラーハンドリングとか考慮しないといけず、お恥ずかしい話勉強不足で上手く実装できませんでした。。。

main.go
package main

import (
    "package/validator"
    "log"
    "net/http"
)

func main() {
    http.HandleFunc("/users/check_email", validator.CheckEmail)
    err := http.ListenAndServe(":9000", nil) //監視するポートを設定する。
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

※上記main.goについて一つ注意事項がございます。コードを載せていますが、main.goで読み込んでいる”package/validator”は自身のリポジトリでパッケージ化しているものとなるため、コードをそのまま載せても動作しません。その点のみご理解ください。

user.go
package validator

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

type HttpResult struct {
    Status int `json:"status"`
    Message string `json:"message"`
}

func newDefaultHttpResult() *HttpResult {
    result := new(HttpResult)
    result.Status = http.StatusOK
    result.Message = "successful"
    return result
}

func CheckEmail(w http.ResponseWriter, r *http.Request) {
    result := newDefaultHttpResult()

    if isPost := isPostMethod(r); !isPost {
        result.Status = http.StatusBadRequest
        result.Message = "request method type is need post"
    }

    if isJson := isApplicationJson(r); !isJson {
        result.Status = http.StatusBadRequest
        result.Message = "Content-Type entity header is need application/json"
    }

    if err := json.NewEncoder(w).Encode(result); err != nil {
        panic(err)
    }
}

func isApplicationJson(r *http.Request) bool {
    if r.Header.Get("Content-Type") != "application/json" {
        return false
    }
    return true
}

func isPostMethod(r *http.Request) bool {
    if r.Method != "POST" {
        return false
    }
    return true
}

TEST

上記でチェックしている「POSTメソッドでない場合」と「Content-Typeが”application/json”以外である場合」のテストを書きたいと思います。対象の関数は「isApplicationJson」と「isPostMethod」ですね。

user_test.go
package validator

import (
    "net/http"
    "testing"
)

// リクエストメソッドがPOSTであるためtrueが返ってくることを期待するテストです。
func TestIsPostMethodOK(t *testing.T) {
    request, _ := http.NewRequest("POST", "", nil)
    if result := isPostMethod(request); !result {
        t.Fatal("failed test")
    }
}

// リクエストメソッドがGETであるためfalseが返ってくることを期待するテストです。
func TestIsPostMethodNG(t *testing.T) {
    request, _ := http.NewRequest("GET", "", nil)
    if result := isPostMethod(request); result {
        t.Fatal("failed test")
    }
}

// Content-Typeがapplication/jsonであるためtrueが返ってくることを期待するテストです。
func TestIsApplicationJsonOK(t *testing.T) {
    request, _ := http.NewRequest("", "", nil)
    request.Header.Set("Content-Type", "application/json")
    if result := isApplicationJson(request); !result {
        t.Fatal("failed test")
    }
}

// Content-Typeがfailedであるためfalseが返ってくることを期待するテストです。
func TestIsApplicationJsonNG(t *testing.T) {
    request, _ := http.NewRequest("", "", nil)
    request.Header.Set("Content-Type", "failed")
    if result := isApplicationJson(request); result {
        t.Fatal("failed test")
    }
}

まとめ

実際に書いてみましたが、勉強不足で思うように実装できなかったです。
本腰入れてGoの勉強をすることにします。
忘れるといけないので現時点で「課題」だと思うものを列挙しとこうと思います。

  • そもそもJSONが返ってくるはずなのにそれに対するテストができていない
  • エラーハンドリングされていないのでresultが上書きされる
  • 真偽値のテストをしているが、最終的なデータをアサーションできないと意味ない

今回実装できなかったところ+上で挙げた課題を②で対応できたらなぁと考えています。
それでは〜

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golang: ピーターからの問題を解いてみた

問題

下記の記事で紹介されているパズルを、Goで解いてみた。

Ruby: Array#permutationでクイズを解いてみた
https://techracho.bpsinc.jp/hachi8833/2020_02_20/88192

Haskell: ピーターからの問題を解いてみた
https://techracho.bpsinc.jp/jhonda/2020_02_21/89044

回答

Go (go 1.12.1)
https://ideone.com/3AB5t2

package main

import "fmt"

func main() {
    n := 9
    ans := make([]int, n)
    for i := range ans {
        ans[i] = i + 1
    }

    evaluate := func(a []int) bool {
        div0 := a[1]*10 + a[2]
        div1 := a[4]*10 + a[5]
        div2 := a[7]*10 + a[8]
        return a[0]*div1*div2+a[3]*div0*div2+a[6]*div0*div1 == div0*div1*div2
    }

    // (開発用)生成したpermutationの総数を確認
    cnt := 0
    _ = cnt

    var permutate func(int)
    permutate = func(s int) {
        if s+2 < n {
            permutate(s + 1)
        } else {
            if evaluate(ans) {
                fmt.Println(ans)
            }
            cnt++
        }
        for i := s + 1; i < n; i++ {
            ans[s], ans[i] = ans[i], ans[s]
            permutate(s + 1)
            ans[s], ans[i] = ans[i], ans[s]
        }
    }

    permutate(0)
    // fmt.Println(cnt) // must be n!
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

aws sdk goでAPIスロットリングした時のリトライ回数を指定する

aws-sdk-go を利用してAPIから ThrottlingException: Rate exceeded が発生した際のデバッグ方法とリトライ試行回数の指定方法

package main

import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/awserr"
    "github.com/aws/aws-sdk-go/aws/request"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/cloudwatchlogs"
    "github.com/aws/aws-sdk-go/service/ec2"
)

func main() {
    mySession := session.Must(session.NewSession())
    loop := 10
    var wg sync.WaitGroup
    wg.Add(loop)

    // 意図的にスロットリングを発生させるために並列実行している
    for i := 0; i < loop; i++ {  
        go func() {
            getLogs(mySession)
            wg.Done()
        }()
    }
    wg.Wait()
}

func getLogs(sess *session.Session) {
    svc := cloudwatchlogs.New(sess, aws.NewConfig().WithMaxRetries(10)) // リトライ試行回数を指定
    t := time.Now().Add(-time.Hour).Unix() * 1000
    ctx := context.Background()
    for i := 0; i < 100; i++ {
        res, err := svc.FilterLogEventsWithContext(ctx, &cloudwatchlogs.FilterLogEventsInput{
            FilterPattern: aws.String(""),
            LogGroupName:  aws.String("/aws/apigateway/welcome"),
            StartTime:     aws.Int64(t),
        },
            request.WithLogLevel(aws.LogDebugWithRequestErrors),  // リクエストエラーのデバッグ表示(リトライの度に表示される)
        )
        if err != nil {
            e, ok := err.(awserr.Error)
            if ok {
                log.Printf("i=%d FilterLogEvents code:%s message:%s", i, e.Code(), e.Message())
                return
            }
            log.Printf("i=%d FilterLogEvents err:%s", i, err)
            return
        }

        if len(res.Events) > 0 {
            log.Printf("len(events)=%d", len(res.Events))
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

COTOHA アクセストークンの取得 (Golang)

COTOHA API Portal の使用例です。

次と同じことを Golang で行いました。

COTOHA アクセストークンの取得

ライブラリーのインストール

go get github.com/joho/godotenv
access_token.go
// ---------------------------------------------------------------
//
//  access_token.go
//
//                  Feb/24/2020
// ---------------------------------------------------------------
package main

import (
    "fmt"
    "os"
    "strings"
    "io/ioutil"
    "net/http"
    "encoding/json"
    "github.com/joho/godotenv"
)

// ---------------------------------------------------------------
func main() {

    fmt.Fprintf (os.Stderr,"*** 開始 ***\n")

    err := godotenv.Load()
    if err != nil {
        fmt.Println("Error loading .env file")
        }

    unit_aa := make (map[string]interface{})
    unit_aa["grantType"] = "client_credentials"
    unit_aa["clientId"] = os.Getenv("CLIENT_ID")
    unit_aa["clientSecret"] = os.Getenv("CLIENT_SECRET")
    str_json, _ := json.Marshal(unit_aa)

    url_target := os.Getenv("ACCESS_TOKEN_PUBLISH_URL")

    response, error := http.Post(url_target,"application/json",
        strings.NewReader(string(str_json)))
    if error != nil {
        fmt.Println("Request error:", error)
    }

    bb, err := ioutil.ReadAll(response.Body)
    if err == nil {
        fmt.Println(string(bb))
        }

    fmt.Fprintf (os.Stderr,"*** 終了 ***\n")
}

// ---------------------------------------------------------------

実行コマンド

go run access_token.go
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golang の http クライアントの使い方 (Post)

http_post.go
// ---------------------------------------------------------------
//
//  http_post.go
//
//                  Feb/24/2020
// ---------------------------------------------------------------
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "net/url"
)

// ---------------------------------------------------------------
func main() {
    fmt.Printf ("*** 開始 ***\n")
    url_target := "https://httpbin.org/post"
    args := url.Values{}
    args.Add("user","jiro")
    args.Add("password","123456")
    res, err := http.PostForm(url_target,args)
    if err != nil {
        fmt.Println("Request error:", err)
        return
    }
    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println("Request error:", err)
        return
    }

    str_json := string(body)
    fmt.Println(str_json)

    fmt.Printf ("*** 終了 ***\n")
}

// ---------------------------------------------------------------

実行結果

$ go run http_post.go
*** 開始 ***
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "password": "123456", 
    "user": "jiro"
  }, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Content-Length": "25", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "httpbin.org", 
    "User-Agent": "Go-http-client/2.0", 
    "X-Amzn-Trace-Id": "Root=1-5e532ac5-3fd72da01bd57240d7b094c8"
  }, 
  "json": null, 
  "origin": "163.49.213.57", 
  "url": "https://httpbin.org/post"
}

*** 終了 ***
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Golang の http クライアントの使い方 (Get)

http_get.go
// ---------------------------------------------------------------
//
//  http_get.go
//
//                  Feb/24/2020
// ---------------------------------------------------------------
package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
)

// ---------------------------------------------------------------
func main() {
    fmt.Printf ("*** 開始 ***\n")
    url_target := "https://httpbin.org/get"
    res, err := http.Get(url_target)
    if err != nil {
        fmt.Println("Request error:", err)
        return
    }
    defer res.Body.Close()

    body, err := ioutil.ReadAll(res.Body)
    if err != nil {
        fmt.Println("Request error:", err)
        return
    }

    str_json := string(body)
    fmt.Println(str_json)

    fmt.Printf ("*** 終了 ***\n")
}

// ---------------------------------------------------------------

実行結果

$ go run http_get.go
*** 開始 ***
{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Host": "httpbin.org", 
    "User-Agent": "Go-http-client/2.0", 
    "X-Amzn-Trace-Id": "Root=1-5e532a2d-03367851ed2afcb58a0a452d"
  }, 
  "origin": "163.49.213.57", 
  "url": "https://httpbin.org/get"
}

*** 終了 ***
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む