20210101のGoに関する記事は4件です。

Go言語によるWebアプリケーション開発_ハンズオン1日目

この参考書の内容をハンズオンしながら理解不足な箇所をまとめました。
https://www.oreilly.co.jp/books/9784873117522/
サンプルプログラムはGitHubで提供されています。
https://github.com/oreilly-japan/go-programming-blueprints/tree/master/chapter1/chat

チャットアプリケーションを作るアウトライン

・HTMLを提供するWebサーバを作成する
・チャットメッセージのやり取りをする機能を追加する

利用パッケージまとめ

パッケージ名 詳細
net/http HTTPクライアントおよびサーバーの実装を提供
text/template テキスト出力を生成するためのデータ駆動型テンプレートを実装
html/template コードインジェクションに対して安全なHTML出力を生成するためのデータ駆動型テンプレートを実装
path/filepath オペレーティングシステムで定義されたファイルパスと互換性のある方法でファイル名パスを操作するためのユーティリティルーチンを実装
sync 相互排他ロックなどの基本的な同期プリミティブを提供

func(w http.ResponseWriter, r *http.Request)

この書き方はHTTPリクエストを処理する際によく使われています。

text/templateとhtml/templateの違い

これらは同じような処理が行われますが、html/templateパッケージはコンテキストを認識するという点が異なります。不正なスクリプトを埋め込む攻撃を回避できる、URLで使用できない文字をエンコードするといったメリットがあります。

sync.Once型ってなに??

関数が1回しか実行されないことを保証できる型。

感想

中級者向けの参考書だと感じました。理解が追い付かない箇所が多く、結構難しいです、、、
とりあえず頑張って1周目を終わらせます!!

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

Go言語でお天気botを作ってラズパイ4で動かす

やったこと

Go言語で特定の地域の天気と気温をTweetするアプリを作り、Raspberry Pi 4上からcronで任意のタイミングで実行させるようにしました。

環境

・macOS Catalina 10.15.7
・Raspbian 10.6
・go 1.15.2

流れ

1.TwitterのAPIアカウント申請 & APP作成
2.TwitterアプリのApp Permissons設定をReadからRead & Writeに変更
3.OpenWeatherMapのアカウント作成 & APIキーの取得
4.Go言語でTweetアプリ作成
5.作ったアプリをラズパイ向けにビルド & 配置
6.cronを使ってラズパイから任意のタイミングで実行させる

1.TwitterのAPIアカウント申請 & APP作成

以下の記事を参考にしました。
2020年度版 Twitter API利用申請の例文からAPIキーの取得まで詳しく解説
Twitter Developerの開発者申請(例文あり)とAPIキー取得方法まとめ【2019年版】

API key & secretとAccess token & secretを取得します。

2.TwitterアプリのApp Permissons設定をReadからRead & Writeに変更

作成したTwitterアプリのApp permissionsの設定が「Read」になっていると、Tweetしようとした時に権限エラーになってしまうので、「Read and Write」に変更します。
Screenshot 2021-01-01 at 13.30.06.png
Screenshot 2021-01-01 at 13.30.38.png

3.OpenWeatherMapのアカウント作成 & APIキーの取得

まず、以下のページからアカウントを作成します。
http://home.openweathermap.org/users/sign_up

サインイン後、API keysのタブを選択するとAPI keyが表示されます。
Screenshot 2021-01-01 at 13.19.05.png

4.Go言語でTweetアプリ作成

以下の記事を参考にしました。
Go言語のTwitter APIで定期的にツイートする
【Go】OpenWeatherMap APIを使用して現在の天気情報を取得する

まずTwitter認証用のコードを書きます。
「1.TwitterのAPIアカウント申請 & APP作成」で取得したAPI key & secretとAccess token & secretをそれぞれ下記のコードの該当箇所にあてはめます。

keys.go
package keys

import (
    "github.com/ChimeraCoder/anaconda"
)

func GetTwitterApi() *anaconda.TwitterApi {
    anaconda.SetConsumerKey("API_KEY")
    anaconda.SetConsumerSecret("API_KEY_SECRET")
    api := anaconda.NewTwitterApi("ACCESS_TOKEN", "ACCESS_TOKEN_SECRET")
    return api
}

次にOpenWeatherMapから天気を取得するコードを書きます。
APIリクエストパラメータのappidは、「3.OpenWeatherMapのアカウント作成 & APIキーの取得」で取得したAPIキーを指定します。

getweather.go
package getweather

import (
    "encoding/json"
    "io/ioutil"
    "net/http"
    "net/url"
)

type OpenWeatherMapAPIResponse struct {
    Main    Main      `json:"main"`
    Weather []Weather `json:"weather"`
    Coord   Coord     `json:"coord"`
    Wind    Wind      `json:"wind"`
    Dt      int64     `json:"dt"`
}

type Main struct {
    Temp     float64 `json:"temp"`
    TempMin  float64 `json:"temp_min"`
    TempMax  float64 `json:"temp_max"`
    Pressuer int     `json:"pressure"`
    Humidity int     `json:"humidity"`
}

type Coord struct {
    Lon float64 `json:"lon"`
    Lat float64 `json:"lat"`
}

type Weather struct {
    Main        string `json:"main"`
    Description string `json:"description"`
    Icon        string `json:"icon"`
}

type Wind struct {
    Speed float64 `json:"speed"`
    Deg   int     `json:"deg"`
}

func GetWeather() OpenWeatherMapAPIResponse {

    endPoint := "https://api.openweathermap.org/data/2.5/weather" // APIのエンドポイント

    // パラメータを設定
    values := url.Values{}
    values.Set("q", "Tokyo,jp")                             // 地域を指定(ここでは東京)
    values.Set("units", "metric")                           // 単位は摂氏・メートルで取得
    values.Set("lang", "ja")                                // Discriptionを日本語で取得
    values.Set("appid", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") // APIキー

    // リクエストを投げる
    res, err := http.Get(endPoint + "?" + values.Encode())
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    // レスポンスを読み取り
    bytes, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    // JSONパース
    var apiRes OpenWeatherMapAPIResponse
    if err := json.Unmarshal(bytes, &apiRes); err != nil {
        panic(err)
    }

    return apiRes
}

最後にツイートする文章を作成するコードを書きます。

text.go
package text

import (
    . "tenkiapp/getweather"
    "fmt"
    "time"
)

func GetTweetText() string {
    weather := GetWeather()
    tweettext := fmt.Sprintf("%s\n", time.Unix(weather.Dt, 0).Format("2006/01/02 15:04"))
    tweettext += fmt.Sprintf("%s\n", weather.Weather[0].Main)
    tweettext += fmt.Sprintf("%s\n", weather.Weather[0].Description)
    tweettext += fmt.Sprintf("%.1f%s\n", weather.Main.Temp, "℃")
    return tweettext
}

ちなみにフォルダ構成は以下です。

tenkiapp
├── main.go
├── keys
│   └── keys.go
├── getweather
│   └── getweather.go
└── text
    └── text.go

試しに一度実行してみます。

go run main.go

作成したTwitterアカウントで以下のようなツイートができていればOKです。

2020/01/01 12:00
曇りがち
6.8℃

5.作ったアプリをラズパイ向けにビルド&配置

以下のページを参考にしました。
go buildとクロスコンパイル

ラズパイ4上でgo envを実行してみたところ以下でした。
(ラズパイ上でgoのバイナリを動かすだけなら、ラズパイ上にgoをインストールする必要はありませんが、確認のために実施)

GOARCH="arm"
GOOS="linux"

アプリのディレクトリに移動して、以下コマンドを実行します。

env GOOS=linux GOARCH=arm go build main.go

できたバイナリをラズパイ上に転送します。

scp [アプリのディレクトリ]/main pi@xxx.xxx.xxx.xxx:/home/pi/tenkiapp/

6.cronを使ってラズパイから任意のタイミングで実行させる

以下の記事を参考にしました。
ラズベリーパイ4でcronを動かす

ここからはラズパイ上での作業です。ssh接続します。

ssh pi@xxx.xxx.xxx.xxx

まずcronのログを有効化します。

/etc/rsyslog.conf
#以下のコメントアウトを外す
cron.*                          /var/log/cron.log
// 変更を反映
$ sudo /etc/init.d/rsyslog restart

// cronのステータス確認 active (running)になっていればOK
$ sudo /etc/init.d/cron status

// cronの再起動(必要に応じて)
$ sudo /etc/init.d/cron restart

次にcronの設定を行います。

$ crontab -e

// 毎日6時、12時、18時にTweetさせる
0 6 * * * /home/pi/tenkiapp/main
0 12 * * * /home/pi/tenkiapp/main
0 18 * * * /home/pi/tenkiapp/main

設定した時間にTweetできていればOKです。

参考

参考にさせていただいた記事の作成者様、ありがとうございました。

2020年度版 Twitter API利用申請の例文からAPIキーの取得まで詳しく解説
Twitter Developerの開発者申請(例文あり)とAPIキー取得方法まとめ【2019年版】
Go言語のTwitter APIで定期的にツイートする
【Go】OpenWeatherMap APIを使用して現在の天気情報を取得する
go buildとクロスコンパイル
ラズベリーパイ4でcronを動かす

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

【Go言語】OpenWeatherMapとTwitterAPIを使ってお天気情報をラズパイから定期的にツイートさせる

やったこと

Go言語で特定の地域の天気と気温をツイートするアプリを作り、Raspberry Pi 4上からcronで自動実行させるようにしました。
OpenWeatherMapとTwitterAPIを利用しています。

環境

・macOS Catalina 10.15.7(開発と動作確認時)
・Raspbian 10.6(Raspberry Pi 4B)
・go 1.15.2

流れ

1.TwitterのAPIアカウント申請 & App作成
2.TwitterアプリのApp Permissons設定をReadからRead & Writeに変更
3.OpenWeatherMapのアカウント作成 & APIキーの取得
4.Go言語でツイートアプリ作成
5.作ったアプリをラズパイ向けにビルド & 配置
6.cronを使ってラズパイから自動実行させる

1.TwitterのAPIアカウント申請 & App作成

Developerページから開発者申請とTwitterアプリケーション作成を行い、API key & secretとAccess token & secretを取得します。

以下の記事を参考にさせていただきました。
2020年度版 Twitter API利用申請の例文からAPIキーの取得まで詳しく解説
Twitter Developerの開発者申請(例文あり)とAPIキー取得方法まとめ【2019年版】

2.TwitterアプリのApp Permissons設定をReadからRead & Writeに変更

作成したTwitterアプリのApp permissionsの設定が「Read Only」になっていると、ツイートしようとした時に権限エラーになってしまうので、「Read and Write」に変更します。
Screenshot 2021-01-01 at 13.30.06.png
Screenshot 2021-01-01 at 13.30.38.png

3.OpenWeatherMapのアカウント作成 & APIキーの取得

まず、以下のページからアカウントを作成します。
http://home.openweathermap.org/users/sign_up

サインイン後、API keysのタブを選択するとAPI keyが表示されます。
Screenshot 2021-01-01 at 13.19.05.png

4.Go言語でツイートアプリ作成

OpenWeatherMapから天気情報を取得して、TwitterAPIでツイートするアプリを作ります。

以下の記事を参考にさせていただきました。
Go言語のTwitter APIで定期的にツイートする
【Go】OpenWeatherMap APIを使用して現在の天気情報を取得する

フォルダ構成は以下です。

tenkiapp
├── keys
│   └── keys.go
├── getweather
│   └── getweather.go
├── text
│   └── text.go
└── main.go

まずTwitter認証用のコードを書きます。
「1.TwitterのAPIアカウント申請 & App作成」で取得したAPI key & secretとAccess token & secretをそれぞれ下記のコードの該当箇所にあてはめます。

keys.go
package keys

import (
    "github.com/ChimeraCoder/anaconda"
)

func GetTwitterApi() *anaconda.TwitterApi {
    anaconda.SetConsumerKey("API_KEY")
    anaconda.SetConsumerSecret("API_KEY_SECRET")
    api := anaconda.NewTwitterApi("ACCESS_TOKEN", "ACCESS_TOKEN_SECRET")
    return api
}

次にOpenWeatherMapから天気を取得するコードを書きます。
APIリクエストパラメータのappidには、「3.OpenWeatherMapのアカウント作成 & APIキーの取得」で取得したAPIキーを指定します。

getweather.go
package getweather

import (
    "encoding/json"
    "io/ioutil"
    "net/http"
    "net/url"
)

type OpenWeatherMapAPIResponse struct {
    Main    Main      `json:"main"`
    Weather []Weather `json:"weather"`
    Coord   Coord     `json:"coord"`
    Wind    Wind      `json:"wind"`
    Dt      int64     `json:"dt"`
}

type Main struct {
    Temp     float64 `json:"temp"`
    TempMin  float64 `json:"temp_min"`
    TempMax  float64 `json:"temp_max"`
    Pressuer int     `json:"pressure"`
    Humidity int     `json:"humidity"`
}

type Coord struct {
    Lon float64 `json:"lon"`
    Lat float64 `json:"lat"`
}

type Weather struct {
    Main        string `json:"main"`
    Description string `json:"description"`
    Icon        string `json:"icon"`
}

type Wind struct {
    Speed float64 `json:"speed"`
    Deg   int     `json:"deg"`
}

func GetWeather() OpenWeatherMapAPIResponse {

    endPoint := "https://api.openweathermap.org/data/2.5/weather" // APIのエンドポイント

    // パラメータを設定
    values := url.Values{}
    values.Set("q", "Tokyo,jp")                             // 地域を指定(ここでは東京)
    values.Set("units", "metric")                           // 気温の単位を摂氏で取得
    values.Set("lang", "ja")                                // Descriptionを日本語で取得
    values.Set("appid", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx") // APIキー

    // リクエストを投げる
    res, err := http.Get(endPoint + "?" + values.Encode())
    if err != nil {
        panic(err)
    }
    defer res.Body.Close()

    // レスポンスを読み取り
    bytes, err := ioutil.ReadAll(res.Body)
    if err != nil {
        panic(err)
    }

    // JSONパース
    var apiRes OpenWeatherMapAPIResponse
    if err := json.Unmarshal(bytes, &apiRes); err != nil {
        panic(err)
    }

    return apiRes
}

ツイートする文章を作成するコードを書きます。

text.go
package text

import (
    . "tenkiapp/getweather"
    "fmt"
    "time"
)

func GetTweetText() string {
    weather := GetWeather()
    tweetText := fmt.Sprintf("%s\n", time.Unix(weather.Dt, 0).Format("2006/01/02 15:04"))
    tweetText += fmt.Sprintf("%s\n", weather.Weather[0].Main)
    tweetText += fmt.Sprintf("%s\n", weather.Weather[0].Description)
    tweetText += fmt.Sprintf("%.1f%s\n", weather.Main.Temp, "℃")
    return tweetText
}

最後にmain.goを作ります。

main.go
package main

import (
    . "tenkiapp/keys"
    . "tenkiapp/text"
)

func main() {
    api := GetTwitterApi()
    _, err := api.PostTweet(GetTweetText(), nil)
    if err != nil {
        panic(err)
    }
}

試しに一度実行してみます。

$ go run main.go

作成したTwitterアカウントで以下のようなツイートができていればOKです。

2021/01/01 12:00
Clouds
曇りがち
6.8℃

5.作ったアプリをラズパイ向けにビルド & 配置

以下の記事を参考にさせていただきました。
go buildとクロスコンパイル

ラズパイ4上でgo envを実行してみたところ、GOARCHとGOOSは下記の通りでした。
(ラズパイ上でgoのバイナリを動かすだけなら、ラズパイ上にgoをインストールする必要はありませんが、確認のために実施)

GOARCH="arm"
GOOS="linux"

アプリのディレクトリに移動して、下記のコマンドを実行します。

$ env GOOS=linux GOARCH=arm go build main.go

できたバイナリファイルをラズパイ上に転送します。

$ scp [アプリのディレクトリ]/main pi@xxx.xxx.xxx.xxx:/home/pi/tenkiapp/

6.cronを使ってラズパイから自動実行させる

以下の記事を参考にさせていただきました。
ラズベリーパイ4でcronを動かす

ラズパイにssh接続します。

$ ssh pi@xxx.xxx.xxx.xxx

ここからはラズパイ上での作業です。
まずはcronのログを有効化します。

/etc/rsyslog.conf
#以下のコメントアウトを外す
cron.*                          /var/log/cron.log
// 変更を反映
$ sudo /etc/init.d/rsyslog restart

// cronのステータス確認 active (running)になっていればOK
$ sudo /etc/init.d/cron status

// cronの再起動(必要に応じて)
$ sudo /etc/init.d/cron restart

次にcronの設定を行います。

$ crontab -e

// 毎日6時、12時、18時にツイートさせる
0 6 * * * /home/pi/tenkiapp/main
0 12 * * * /home/pi/tenkiapp/main
0 18 * * * /home/pi/tenkiapp/main

設定した時間にツイートできていればOKです。

参考

参考にさせていただいた記事の作成者様、ありがとうございました。

2020年度版 Twitter API利用申請の例文からAPIキーの取得まで詳しく解説
Twitter Developerの開発者申請(例文あり)とAPIキー取得方法まとめ【2019年版】
Go言語のTwitter APIで定期的にツイートする
【Go】OpenWeatherMap APIを使用して現在の天気情報を取得する
go buildとクロスコンパイル
ラズベリーパイ4でcronを動かす

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

2020年から始めた個人開発で作ったWEBアプリとスマホアプリを振り返る

前置き

いつかやるぞーと思って先延ばしにしまくっていた個人開発を2020年の初めごろにえいやでやり始めました。
1,2本のWEBアプリが作れたらいいなと思っていましたが、勢い余って2本のWEBアプリと1本のスマホアプリを作りました。
宣伝もかねて投稿します。何かしら深堀りしたい内容がありましたらコメントよろしくお願いいたします。

Band Summary(β)

https://bandsummary.com/

bandsummary.png

どういうものか

ライブ情報を投稿管理でき、リンクを追加したらいい感じにまとめてくれるサービス
リンクツリー+バンドのライブ情報を投稿、管理なイメージ

開発経緯

(周りの)インディーズバンドでホームページがないバンドが多くて、どこを調べたらライブ情報が一覧で把握できるかわかりづらかった。
ツイッター見ても、他の投稿で流れていて追っかけるのに時間がかかってる。
ホームページを作るのは大変なので、簡単にpostできるサービスがあれば使ったもらえるかなと思い作成。
また、2020年の目標をWEBアプリ開発(初めての個人開発)に置いていたため、身近な題材(自分自身バンドを組んでいるので)で取り組んでみました。

主な使用言語とか

Go,Beego(Goのwebフレームワークの一つ)
Oracle always free, ATP

反省点

  • どうせだからとoracle always freeでの完全無料稼働を目指して、OracleのATPに苦しんだこと。
  • なんならアクセスがあるのに自動停止措置が取られる謎仕様のため、現在も苦しんでるところ。
  • フレームワークがoracleに完全対応していなくて、結局フレームワーク側のソースを修正するに至ったこと。

学んだこと

チャレンジしたいことはせめて三つ以内にすること

初めての個人開発、初めてのGolang、初めてのOracle SQL(+ATP)、初めてのクラウド開発環境、自前のSNS連携にアカウント管理

特にクラウド開発環境は、どんなよわよわPCからでも開発し続けたいと思い、Oracleのクラウド上に開発環境を構築してcode-serverなりなんなりで達成したけれども、そもそも手持ちのノートPCのスペックは上々なため本当に必要ありませんでした。

Blog Book Rank

https://bookrank.ihmdevs.com/

blogbookrank.png

どういうものか

note記事を解析し、おすすめ本の中でAmazonのリンクが貼られているものを集計、ランキング化。

開発経緯

身近な人が本に関わる仕事をしているため、近しい何か作れないかなと思ったこと。
個人開発のマネタイズを意識した際にテック・ブック・ランクのようにアフィリエイトでチャリンチャリンできないかなと思ったため。
AWSの勉強中だったためLamdaの無料枠で何かできないかなと思ったため。

主な使用言語とか

Go(速度が良いとのことで前作から引き続き)
AWS Lambda, dynamodb

反省点

  • 多様なランキングを出す際にはDynamodbは不向き。
  • 前処理、後処理のためにLambdaを回すはめに。
  • 集計、ランキング化をしたはいいが宣伝が不足しまくっている。

学んだこと

ドメインはサービスごとに作らない、サブドメインで対応する。

Amazonの情報を正規表現で取得しているけれど、ゴミが多すぎて時々正規表現をメンテナンスしています。
noteのAPI情報で引っこ抜けるっぽいところを、自前でやった方がカッケーじゃんって思ってしまったのが不運の始まりでした。
本当にゴミが多い。URLのルールも探してもなさげでした。

ランキングに載った投稿に自動で「いいね」つけるくらいはしたいなと思ってます。
電子書籍版と実物版が合算されていないのをどうにかしたい(収益が見込めたらやりたい、今のところとても面倒そう)

Tickets Band

https://imikio.github.io/TicketsBand/

どういうものか

スマホアプリ

イベントの予約状況などを複数人(グループ)で管理、把握。秒で反映。

開発経緯

flutterに出会ってしまった。

スマホアプリが作りたかった。
glideで所属バンド用に、イベントごとの予約を登録、把握できる同等のアプリを作成していたが、glideが無料枠で同時ログインできない仕様になったため頑張ってみました。
(身近な)他のバンドも予約状況の共有と把握で結構困っているっぽかったため。

主な使用言語とか

Flutter,Dart
Firebase

反省点

  • 逃げてきたUI/UXとの闘いになった。(現在もそのさなか)

2020/12/31 今まだバージョンアップをしつつなので、反省しては開発って感じでいます。

学んだこと

Githubでのコード管理とBitrizeでのCIで、管理系にも本腰を入れてみて、新たな世界が開けた気がします。
Flutter,Firebaseで世界が開けた気がします、BandSummaryで自前で実装、管理していたものがこんなにも簡単に…。

あと、Macを持っていないため、どこまでMacなしでできるかを試してみてたらついにはリリースまで行けました。(これはまた別で投稿出来たらいいなって思ってます。)
flutterとbitrizeに感謝です。

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