20190607のGoに関する記事は14件です。

go言語でSlackに投稿する

環境

go 1.12.5

コード

userName/webhookUrl/iconUrl は適宜調整してね。

type SlackMessage struct {
    Text        string                     `json:"text"`
    Channel     string                     `json:"channel"`
    Username    string                     `json:"username"`
    IconEmoji   string                     `json:"icon_emoji"`
    IconUrl     string                     `json:"icon_url"`
    Attachments *[]*SlackMessageAttachment `json:"attachments"`
}

type SlackMessageAttachment struct {
    Fallback   string                          `json:"fallback"`
    Color      string                          `json:"color"`
    Pretext    string                          `json:"pretext"`
    AuthorName string                          `json:"author_name"`
    AuthorLink string                          `json:"author_link"`
    AuthorIcon string                          `json:"author_icon"`
    Title      string                          `json:"title"`
    Text       string                          `json:"text"`
    Fields     *[]*SlackMessageAttachmentField `json:"fields"`
    ImageUrl   string                          `json:"image_url"`
    ThumbUrl   string                          `json:"thumb_url"`
    Footer     string                          `json:"footer"`
    FooterIcon string                          `json:"footer_icon"`
    TimeStamp  int64                           `json:"ts"`
}

type SlackMessageAttachmentField struct {
    Title string `json:"title"`
    Value string `json:"value"`
    Short bool   `json:"short"`
}

func NotifySlack(channel string, message string, attachments *[]*SlackMessageAttachment) {
    userName := "Admin Client"
    webhookUrl := "https://hooks.slack.com/services/abc/def/ghi"
    iconUrl := "https://example.com/icon.png"

    params, _ := json.Marshal(SlackMessage{
        message,
        channel,
        userName,
        "",
        iconUrl,
        attachments,
    })

    resp, _ := http.PostForm(
        webhookUrl,
        url.Values{"payload": {string(params)}},
    )

    ioutil.ReadAll(resp.Body)
    defer resp.Body.Close()
}

つかいかた

func Test() {
    attachment := &SlackMessageAttachment{
        "フォールバックメッセージだよ",
        "#00ff00",
        "プレテキストだよ",
        "著者だよ",
        "https://www.google.com/",
        "https://img.icons8.com/metro/420/email.png",
        "タイトルだよ",
        "せつめーだよ",
        nil,
        "https://upload.wikimedia.org/wikipedia/en/thumb/e/e0/WPVG_icon_2016.svg/1024px-WPVG_icon_2016.svg.png",
        "https://developer.android.com/guide/practices/ui_guidelines/images/NB_Icon_Mask_Shapes_Ext_02.gif?hl=ja",
        "フッターだよ",
        "https://image.flaticon.com/icons/png/512/33/33447.png",
        0,
    }
    fields := make([]*SlackMessageAttachmentField, 0)
    fields = append(fields, &SlackMessageAttachmentField{
        "あいうえお",
        "かきくけこ",
        true,
    })
    fields = append(fields, &SlackMessageAttachmentField{
        "さしすせそ",
        "たちつてと",
        true,
    })
    fields = append(fields, &SlackMessageAttachmentField{
        "長いテキスト",
        "みなみあそみずのうまれるさとはくすいこうげん",
        false,
    })
    fields = append(fields, &SlackMessageAttachmentField{
        "長いテキスト",
        "Llanfairpwllgwyngyllgogerychwyrndrobwllllantysiliogogogoch",
        false,
    })
    attachment.Fields = &fields
    NotifySlack("#channel_name", "", &[]*SlackMessageAttachment{attachment})
}

結果

スクリーンショット

所感

構造体作るの面倒くさい。

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

Go言語の勉強に役立つリンク集(Qiita Only)

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

Go言語のブックマーク

※随時更新して行きます。

チートシート的なやつ

とりあえず手っ取り早く全体像掴めみたいときや、辞書的な感じで使えるいい感じの記事。

関数

golangの関数をまとめてみた。 - Qiita

配列とスライス

Goのarrayとsliceを理解するときがきた - Qiita

ポインタ

Goで学ぶポインタとアドレス - Qiita

Interface

インタフェースの実装パターン #golang - Qiita

構造体

Goを学びたての人が誤解しがちなtypeと構造体について #golang - Qiita

メソッド

メソッドとレシーバについてのまとめ #golang - Qiita

エラーハンドリング

デバッグ

go言語のデバッガ(delveとgdb)とcore dump - Qiita

SQL

[Go言語] database/sqlパッケージを使ってみた - Qiita

DynamoDB

気楽にDynamoDBを使おう - Qiita

ORM

【GORM】Go言語でORM触ってみた - Qiita

YAML

Go言語でゆるふわにYAMLを使う - Qiita

Swagger

[swaggo]GoのGoDocを書いたら、Swaggerを出せるやばいやつ - Qiita

パッケージ管理

Go Modules - Qiita

Git

Docker

静的解析ツール

無料で使える Go 言語の CI サービス『GolangCI』を使ってみる | DevelopersIO

ダックタイピング

Go言語でダックタイピングをやってみる - Qiita

gRPC

モック

Go Mockでインタフェースのモックを作ってテストする #golang - Qiita

タスクランナー

Goで書けるタスクランナーMageが快適すぎて捗る - Qiita

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

Go言語の勉強に役立つブックマーク集

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

Go言語の学習に役立つブックマーク集

※随時更新して行きます。

チートシート的なやつ

とりあえず手っ取り早く全体像掴めみたいときや、辞書的な感じで使えるいい感じの記事。

関数

golangの関数をまとめてみた。 - Qiita

配列とスライス

Goのarrayとsliceを理解するときがきた - Qiita

ポインタ

Goで学ぶポインタとアドレス - Qiita

Interface

インタフェースの実装パターン #golang - Qiita

構造体

Goを学びたての人が誤解しがちなtypeと構造体について #golang - Qiita

メソッド

メソッドとレシーバについてのまとめ #golang - Qiita

エラーハンドリング

デバッグ

go言語のデバッガ(delveとgdb)とcore dump - Qiita

SQL

[Go言語] database/sqlパッケージを使ってみた - Qiita

DynamoDB

気楽にDynamoDBを使おう - Qiita

ORM

【GORM】Go言語でORM触ってみた - Qiita

YAML

Go言語でゆるふわにYAMLを使う - Qiita

Swagger

[swaggo]GoのGoDocを書いたら、Swaggerを出せるやばいやつ - Qiita

パッケージ管理

Go Modules - Qiita

Git

Docker

静的解析ツール

無料で使える Go 言語の CI サービス『GolangCI』を使ってみる | DevelopersIO

ダックタイピング

Go言語でダックタイピングをやってみる - Qiita

gRPC

goのgRPCで便利ツールを使う - Qiita

microservicesはじめました (1) - 朝日ネット 技術者ブログ

モック

Go Mockでインタフェースのモックを作ってテストする #golang - Qiita

タスクランナー

Goで書けるタスクランナーMageが快適すぎて捗る - Qiita

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

Goスタック模索メモ

HTTP Server

Router

gorilla/mux: A powerful URL router and dispatcher for golang.
https://github.com/gorilla/mux

定番。薄い。

go-chi/chi: lightweight, idiomatic and composable router for building Go HTTP services
https://github.com/go-chi/chi

薄い。gorilla/muxよりAPIが直感的。

JSON Request

小さいので自前で書く人が多いっぽい

以下などに薄い実装

render/decoder.go at master · go-chi/render
https://github.com/go-chi/render/blob/master/decoder.go

Render

unrolled/render: Go package for easily rendering JSON, XML, binary data, and HTML templates responses.
https://github.com/unrolled/render

人気っぽい

Job Queue

RichardKnop/machinery: Machinery is an asynchronous task queue/job queue based on distributed message passing.
https://github.com/RichardKnop/machinery

Broker、ストアそれぞれのバックエンドがいろいろ対応してる(ex. AMQP, Redis, SQS, GCP Pub/Sub, Memcache, MongoDB)
DelayもRetryも対応してる

gocraft/work: Process background jobs in Go
https://github.com/gocraft/work

Redisバックエンド。Delayも対応してる。

RDBMS

jinzhu/gorm: The fantastic ORM library for Golang, aims to be developer friendly
https://github.com/jinzhu/gorm

人気。ORM。

go-gorp/gorp: Go Relational Persistence - an ORM-ish library for Go
https://github.com/go-gorp/gorp

人気。Select文は自分でSQL書いてstructへのマッピングはやってくれる。
クエリをコントロールしたい場合によさそう。

Development

oxequa/realize: Realize is the #1 Golang Task Runner which enhance your workflow by automating the most common tasks and using the best performing Golang live reloading.
https://github.com/oxequa/realize

ホットリロード
go mod使ってる & cmdディレクトリにmainがあるときに相対モジュールが解決できないエラーが起きる(条件は合っていないかも)が、以下にある設定で一応解決する。

Realize が Go 1.11 の Modules で使えない - Qiita
https://qiita.com/enta0701/items/0d0592abb18a333b3268

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

Goのスコープに苦しんだ事例集

コンパイル通るけどtestで死ぬ事例、個人的No.1のスコープ関連についてまとめ。

事例その1 メソッド完結

メソッド内でスコープ切れちゃうので、メソッド内でnewしてもダメだぜの例。
"スコープが切れる"という表現でいいのだろうか。。。

type hogehoge map[string]string

func (h hogehoge) Seter(p string) {
    h["key"] = p
}
func (h *hogehoge) NewSeter(p string) {
    h = &hogehoge{"p": p}
}

func main() {
    f := hogehoge{}
    f.Seter("ddd")
    fmt.Println(f) // <- map[key:ddd]

    f.NewSeter("sss")
    fmt.Println(f) // <- map[key:ddd]
}

https://play.golang.org/p/mCEUyNGLgsy

そもそも、こういうことがやりたかったのでコード間違ってたんですけどね。

事例その2 ループ内部完結

=:=を間違える、よくやるやつ。

dev := "hoge"

for _, v := range []string{"a", "b"} {
    dev := v
    fmt.Println(dev) // <- "a","b"
}
fmt.Println(dev) // <- "hoge"

https://play.golang.org/p/ilj019ANt_f

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

Goといえばチャネルでしょ!!! 第3弾

第三弾?

前回のやつはこれ
Goroutineを触った。
今回はタイトル通りチャネルを触っていこうと思う

channelとは

並列処理を行った結果を呼び出し先の関数に返すことが出来る。
前回のモノで戻り値を返そうとするとエラーが起きる

コード

package main

import "fmt"

func channel(s []int,c chan int){
    sum:=0
    for i:=0;i<5;i++ {
        sum += s[i]
    }
    c <- sum
}

func main(){
    s := []int{1,2,3,4,5}
    c := make(chan int)
    go channel(s,c)
    r := <-c
    fmt.Println(r)
}

解説

func main()
  • 1~5の数字の入ったスライスを作りこれをsで宣言する
  • そしてmakeでchan intで戻り値の値を設定しチャネルとしてcを宣言する
  • そして並列処理のためにgoを記入し、引数にスライスとチャネルを入れる
  • Go to channel
  • そしてchannelからcが送られてきたのでrで受け取る。
func channel()
  • 並列処理によりスレッドぐ作られ、この関数がスタートする
  • 引数のスライスを足していき結果をcのチャネルに送信する。
  • その時の記号は <- である。

最後に

解説が見にくくなってしまった許してください。
次回はBuffer channelでーす。

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

xerrorsパッケージでラップしたエラーをswitchで判別する #golang

TL;DR

switchの条件式をxerrors.Unwrap(err).(type)にする。

問題

xerrors.Errorfでラップしたエラーをerrors.Cause(err).(type)で条件分岐させようとしたが、defaultに振り分けられてしまった。

err := xerrors.Errorf("my error: %w", &MyError{})
switch errors.Cause(err).(type) {
case *MyError:
    fmt.Println("my error")
default:
    fmt.Println("other")
}
//-> other

The Go Playground

解決方法

試行錯誤した結果、switchの条件式をxerrors.Unwrap(err).(type)にすることで目的の処理をさせることができた。

err := xerrors.Errorf("my error: %w", &MyError{})
switch xerrors.Unwrap(err).(type) {
case *MyError:
    fmt.Println("my error")
default:
    fmt.Println("other")
}
//-> my error

The Go Playground

おまけ

ラップしたエラーを取り出すときはxerrors.Asを使う。

switch xerrors.Unwrap(err).(type) {
case *MyError:
    var e *MyError
    xerrors.As(err, &e)
    fmt.Printf("%v\n", e)
default:
    fmt.Println("other")
}

The Go Playground

リンク

xerrors godoc

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

ojichatをSlackに流す

最近ojichatが流行ってますね。
普段会社の勤怠はSlackに投稿してるんですが、あまりに自分の遅刻が多く自分のメッセージで埋まるので、ojichatを流すことにしました。

https://github.com/naomichi-y/ojichat-slack-bot

Screen Shot 2019-06-07 at 9.50.22.png

和む。

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

[Go初心者]map

func main() {
    m := map[string]int{"apple": 100, "banana": 200} //map[apple:100 banana:200]

    fmt.Println(m)
    fmt.Println(m["apple"]) //100
    m["banana"] = 300
    fmt.Println(m) //map[apple:100 banana:300]

    m["orange"] = 500
    fmt.Println(m) //map[apple:100 banana:300 orange:500]

    fmt.Println(m["nothing"]) //0 intのデフォルト値

    v, ok := m["apple"] //okは中身が入っているかチェックするもの。2つ目の返り値はなくても良い
    fmt.Println(v, ok)  //100 true

    v2, ok2 := m["nothing"]
    fmt.Println(v2, ok2) //0 false

    m2 := make(map[string]int)
    m2["sp"] = 20000
    fmt.Println(m2)
    //メモリ上に空のマップをつくってから値を代入した

    /*
        var m3 map[string]int
        m3["sp"] = 50000
        fmt.Println(m3) //panic: assignment to entry in nil map
        //宣言はしているがメモリ上に入れるマップがないのでエラー
    */

    var s []int
    if s == nil {
        fmt.Println("NIL")
    }
    //varで宣言した場合は、mapもスライスもnil
}

【参考】
現役シリコンバレーエンジニアが教えるGo入門(https://www.udemy.com/share/100BhMB0obeFpbTX4=/)

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

Lambda(Golang)でAPI Gatewayのクエリ文字列を使用する

はじめに

Lambda(Golang)でAPI Gatewayのクエリ文字列を使用する方法がなかなか見つからなかったので備忘録としてまとめます。

デモ

https://rjt8xm2a63.execute-api.ap-northeast-1.amazonaws.com/dev/hello?name=Naoki

{"message":"Hello, Naoki"}

TL;DR

  • Lambdaのハンドラーの第2引数でrequest events.APIGatewayProxyRequestを受け取る
  • q := request.QueryStringParametersでクエリ文字列のMapを返す

サンプルコード

https://github.com/oke-py/qs-demo
Serverless Frameworkを利用してデプロイする前提とします。

serverless.yml
service: qs-demo
frameworkVersion: ">=1.28.0 <2.0.0"

provider:
  name: aws
  runtime: go1.x

# you can overwrite defaults here
  stage: dev
  region: ap-northeast-1

# you can add statements to the Lambda function's IAM Role here
  iamRoleStatements:
    - Effect: "Allow"
      Action:
        - "logs:CreateLogGroup"
        - "logs:CreateLogStream"
        - "logs:PutLogEvents"
      Resource: "arn:aws:logs:*:*:*"

package:
 exclude:
   - ./**
 include:
   - ./bin/**

functions:
  hello:
    handler: bin/hello
    events:
      - http:
          path: hello
          method: get
          request:
            parameters:
              querystrings:
                # クエリ文字列が必須ならtrue、必須でなければfalse
                name: true
hello/main.go
package main

import (
    "bytes"
    "context"
    "encoding/json"

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

// Response is of type APIGatewayProxyResponse since we're leveraging the
// AWS Lambda Proxy Request functionality (default behavior)
//
// https://serverless.com/framework/docs/providers/aws/events/apigateway/#lambda-proxy-integration
type Response events.APIGatewayProxyResponse

// Handler is our lambda handler invoked by the `lambda.Start` function call
func Handler(ctx context.Context, request events.APIGatewayProxyRequest) (Response, error) {
    q := request.QueryStringParameters
    name := q["name"]

    var buf bytes.Buffer

    body, err := json.Marshal(map[string]interface{}{
        "message": "Hello, " + name,
    })
    if err != nil {
        return Response{StatusCode: 404}, err
    }
    json.HTMLEscape(&buf, body)

    resp := Response{
        StatusCode:      200,
        IsBase64Encoded: false,
        Body:            buf.String(),
        Headers: map[string]string{
            "Content-Type":           "application/json",
            "X-MyCompany-Func-Reply": "hello-handler",
        },
    }

    return resp, nil
}

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

まとめ

無事、Lambda(Golang)でAPI Gatewayのクエリ文字列を使用することができました。

参考

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

yamlから欲しい情報をGoでとる(マイグレーションツールを使うときに使うファイルを流用する)

動機

 migrationツールを使うと次のようなdb.confを書いたりします。

development:
    dialect: mysql
    dir: db/migrations
    datasource: user:password@tcp(db:3306)/db_name?charset=utf8mb4&collation=utf8mb4_general_ci&parseTime=true

production:
    dialect: postgres
    dir: migrations/postgres
    datasource: dbname=myapp sslmode=disable
    table: migrations

せっかくなら、普通のデータベース接続もこのYAMLからデータを取ってきたい!取ってきたくない?

go-yamlを使って簡単に()実装できます!

実装例

buf, err := ioutil.ReadFile("file.pass")

    if err != nil {
        log.Fatal(err)
        return
    }

    m := make(map[interface{}]interface{})
    err = yaml.Unmarshal(buf, &m)
    if err != nil {
        log.Fatal(err)
        panic(err)
    }


    fmt.Printf("%d\n", m["development"].(map[interface {}]interface {})["datasource"])
    db_config :=m["development"].(map[interface {}]interface {})["datasource"].(string)


    db, err := dbr.Open("mysql", db_config , nil)

 忘備録だけど、ここに行きつくのにどちゃくそ時間がかかった……
 Goのインターフェースよくわからん。ちなみにdbrを接続用のツールに使っています。

参考

https://qiita.com/umanoda/items/07887d33ef1155b26ed2
https://ota42y.com/blog/2014/11/13/go-yaml/
https://qiita.com/daiching/items/a384a5ce229cf714a3b5

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

goで atcoder の入力例実行の手間を省くツールを作った

このページについて

atcoderの入力例をすべて取得し、指定された実行スクリプトに標準出力として渡すツールについて紹介しています

repository

ex.) 実行例
実物は、okだったら緑、errorだったら赤でプリントされます

$ acc atcoder -u https://atcoder.jp/contests/abc119/tasks/abc119_b -c "go run ./main.go"
start atcoder test v0.0.0-5780f7c (built with go1.12.1)

Case [0] exp: 48000.0
    ok!
Case [1] exp: 138000000.0038
    ok!

背景

atcoder の入力例をいちいちfileにコピペして下記のようにコマンド叩いていましたが
さすがに面倒になってきたので作ってみました

$ cat file | go run main.go

内容

設計思想

  • サイトに迷惑をかけない
    • 最初の一回リクエストしたあとは、cacheを残してそこから取得するようにしました
    • $GOPATH/bin にdbが作られます

使い方

$ go get -u github.com/smith-30/acc

インストールしたらあとはatcoderの問題ページのurlと
テストケースを流したいスクリプトを渡すだけです

$ acc atcoder -u http://atcoder.jp/<problem path> -c "go run path/to/main.go"

ライブラリなど

  • cahceのdbはpudgeというkey-valueのもの使ってます
  • htmlのパースはgo-query
  • cli のテンプレートにはcobra使ってます

その他

いろんなテストケースと予想されている出力パターンがあると思いますが
全てに対応しているかはわかりません。うまく使えないとかあればissueお願いします
よかったら使ってみてください。僕も使いながら改良していきます

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