Codic API を利用するパッケージを作ってみた
つい最近まで知らなかったのだが codic というサービスがあるらしい。
簡単に言うと日本語の「名前」を英語に変換してくれるサービスなのだが,プログラマ向けに変数名やメソッド名として使いやすいよう提案してくれる優れものである。
まさに英語不得手な私のためにあるようなサービスじゃないか! 何故今までこのサービスに辿り着けなかったのか orz
Web 画面はこんな感じ。
あの時このサービスのことを知っていたらメソッド名に regist
とか付けようとして赤っ恥をかかなくて済んだのに。
とほほ。
というわけで早速サインアップしましたよ。 GitHub のアカウントでもサインアップできるのが素敵(最終確認にメールアドレスを要求されるけど)。
で, codic では API を公開しているようだ。
で,これを使うための Go 言語パッケージも既に見られるんだけど
CLI しか用意されてない,っていうか何で GET で取ろうとするんだよ! というわけで自作することにした。
→ 自作しました。
すみません。 勢いで作ったのでテストを書いてません。 そのうちなんとかします。 日本語圏向けのサービスなんだから README もガッツリ日本語でいいよね(笑)
Curl で API を確認する
RESTfull API なんだから curl で説明してくれよ,と思う私は贅沢なのでしょうか。
- cURL as DSL — cURL as DSL 1.0 documentation
- Shibu’s Diary: cURL as DSLとは何だったのか。あるいは細かすぎて伝わらないcURL as DSL。
とりあえず,翻訳用の API は curl を使うと以下のように記述できる。
curl "https://api.codic.jp/v1/engine/translate.json" -H "Authorization: Bearer YOUR_ACCESS_TOKEN" -F "text=hello" -F "casing=camel"
text=hello
って日本語やないやないかい! というのはとりあえずスルーしていただいて,これを cURL as DSL で Go 言語コードに変換すると以下のようになる。
package main
import (
"bytes"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
)
func main() {
client := &http.Client{}
var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer)
writer.WriteField("text", "hello")
writer.WriteField("casing", "camel")
writer.Close()
request, err := http.NewRequest("POST", "https://api.codic.jp/v1/engine/translate.json", &buffer)
request.Header.Add("Authorization", "Bearer YOUR_ACCESS_TOKEN")
request.Header.Add("Content-Type", "multipart/form-data; boundary="+writer.Boundary())
resp, err := client.Do(request)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Print(string(body))
}
これが雛形で出発点である。
YOUR_ACCESS_TOKEN
に正しいアクセス・トークン(codic にサインアップするともらえる)をセットすればちゃんと動く。
動くコードってのは大事だよね。
最終的にどうなったかは README を見ていただきたい。
spf13/viper を使ってみたかったのだ
外部パッケージは dep で管理することにした。 こんな感じである。
[[constraint]]
name = "github.com/spf13/cobra"
branch = "master"
[[constraint]]
name = "github.com/spf13/viper"
version = "^1.0.0"
[[constraint]]
name = "github.com/spiegel-im-spiegel/gocli"
version = "^0.4.0"
[[constraint]]
name = "github.com/pkg/errors"
version = "^0.8.0"
pkg/errors パッケージ以外は CLI (Command-Line Interface) 用のパッケージである。 この中でも今回は特に spf13/viper を使ってみたかったのだ。 だって毎回アクセス・トークンをコマンドラインに書く訳にはいかないでしょ。 呼び出しバッチやスクリプトに書くとか以ての外だし。
spf13/viper は設定ファイルにアクセスするためのパッケージで,特に spf13/cobra との相性がいいのが特徴である。 というか同じ作者なのだが。 spf13/cobra の使い方は以前紹介したので,そちらを参考にして欲しい。
spf13/cobra が生成してくれる cmd/root.go
に spf13/viper 初期化のコードがある。
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Print(err)
os.Exit(1)
}
// Search config in home directory with name ".gocodic" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".gocodic")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Print("Using config file:", viper.ConfigFileUsed())
}
}
この関数は spf13/cobra が生成した cmd
パッケージの init()
関数内で呼び出される。
このまま弄らなくても問題ないが,個人的にはエラーを標準出力に出してるのが気に入らなかったので少し変えている。
その後, spf13/viper で読み込む設定項目を記述していくのだが
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.gocodic.yaml)")
rootCmd.PersistentFlags().BoolP("json", "j", false, "output by JSON format (raw data)")
rootCmd.PersistentFlags().StringP("token", "t", "", "access token of codic.jp")
viper.BindPFlag("json", rootCmd.PersistentFlags().Lookup("json"))
viper.BindPFlag("token", rootCmd.PersistentFlags().Lookup("token"))
こんな感じで spf13/cobra 側のフラグ(厳密には spf13/pflag)と spf13/viper をバインドしてしまう。
これで cmd
パッケージ側からはフラグ情報を透過的に扱える。
フラグ情報を取り出す場合には
jsonFlag := viper.GetBool("json")
token := viper.GetString("token")
などとすればよい。 分かれば簡単。
ところで
2016年4月からブログが更新されてないけど,そのうちサービスが止まるなんてないよね? Twitter アカウントは生きてるみたいだし。