Git.io で短縮 URL が取得できるらしい
これを読んでたら後ろの方に Git.io の話が出ていた。このサイトで短縮 URL を生成できるらしい。
API が curl で掲載されていて,例えば私の https://github.com/spiegel-im-spiegel なら
$ curl -i "http://git.io" -F "url=https://github.com/spiegel-im-spiegel"
HTTP/1.1 201 Created
Server: Cowboy
Connection: keep-alive
Date: Sat, 08 Aug 2015 02:42:16 GMT
Status: 201 Created
Content-Type: text/html;charset=utf-8
Location: http://git.io/vOj52
Content-Length: 37
X-Xss-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Runtime: 0.210952
X-Node: 871d903e-a8e0-46ff-a96f-ef424385e5ed
X-Revision: b1d9ce07ccb700fc90398edafd397beb8d3bd772
Via: 1.1 vegur
https://github.com/spiegel-im-spiegel
てな感じで,ヘッダの Location 要素に短縮 URL が返ってくる仕組みらしい。
って,これって curl で書けるんなら golang で表現できるんじゃね?
cURL as DSL
- cURL as DSL — cURL as DSL 1.0 documentation
- Shibu's Diary: cURL as DSLとは何だったのか。あるいは細かすぎて伝わらないcURL as DSL。
cURL as DSL とは curl の構文を任意のコード(今のところは golang, Python, PHP, JavaScript, Java, Objective-C, Vim Script)に変換してくれるもので,どういうことかというと「Web API は curl で表現すればいいんじゃね?」ということらしい。
さっそく curl を golang に変換してみる
では早速,上述の curl コマンドを golang に変換してみる(ちなみに -i
は付けない)。こんな感じ。
package main
import (
"bytes"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
)
func main() {
var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer)
writer.WriteField("url", "https://github.com/spiegel-im-spiegel")
resp, err := http.Post("http://git.io", "multipart/form-data; boundary="+writer.Boundary(), &buffer)
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))
}
まずは何も考えずに動かしてみる。
C:>go run gitio0.go
2015/08/08 12:00:00 Invalid url:
あれ? おかしいなぁ。ん~,じゃあちょっと出力をいじって...
package main
import (
"bytes"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
)
func main() {
var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer)
writer.WriteField("url", "https://github.com/spiegel-im-spiegel")
resp, err := http.Post("http://git.io", "multipart/form-data; boundary="+writer.Boundary(), &buffer)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Println(" Status: ", resp.Header.Get("Status"))
log.Println("Location: ", resp.Header.Get("Location"))
log.Println(" Body: ", string(body))
}
C:>go run gitio1.go
2015/08/08 12:00:00 Status: 422 Unprocessable Entity
2015/08/08 12:00:00 Location:
2015/08/08 12:00:00 Body: Invalid url:
ん? あっそうか。 url がちゃんと渡ってないんだ。ひとしきり悩んだ後,以下のようにすればいいことに気がついた。
package main
import (
"bytes"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
)
func main() {
var buffer bytes.Buffer
writer := multipart.NewWriter(&buffer)
writer.WriteField("url", "https://github.com/spiegel-im-spiegel")
writer.Close() //writer はちゃんと閉じましょう
resp, err := http.Post("http://git.io", "multipart/form-data; boundary="+writer.Boundary(), &buffer)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Println(" Status: ", resp.Header.Get("Status"))
log.Println("Location: ", resp.Header.Get("Location"))
log.Println(" Body: ", string(body))
}
多分 buffer
に flush されてなかったんだね(この問題は修正されたようです)。これで
C:>go run gitio2.go
2015/08/08 12:00:00 Status: 201 Created
2015/08/08 12:00:00 Location: http://git.io/vOj52
2015/08/08 12:00:00 Body: https://github.com/spiegel-im-spiegel
となり,めでたく短縮 URL が取得できた。
ちなみに,これには http.PostForm
関数を使った別解がある。最初の curl の式の -F
を -d
にかえればいいらしい。結果は以下の通り
package main
import (
"io/ioutil"
"log"
"net/http"
"net/url"
)
func main() {
values := url.Values{
"url": {"https://github.com/spiegel-im-spiegel"},
}
resp, err := http.PostForm("http://git.io", values)
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))
}
今回に限れば,こちらのほうがコードがスッキリして分かりやすい。
では,楽しい夏休みを!