Git.io から短縮 URL を取得するコード

(初出: Git.io 短縮 URL を golang コードで取得してみる - Qiita

Git.io で短縮 URL が取得できるらしい

これを読んでたら後ろの方に Git.io の話が出ていた。 このサイトで短縮 URL を生成できるらしい。

API が curl で掲載されていて,例えば私の https://github.com/spiegel-im-spiegel なら

$ curl -i "https://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 で書けるんなら Go 言語で表現できるんじゃね?

cURL as DSL

cURL as DSL とは curl の構文を任意のコード1 に変換してくれるもので,どういうことかというと「Web API は curl で表現すればいいんじゃね?」ということらしい。

さっそく curl を Go 言語に変換してみる

では早速,上述の curl コマンドを cURL as DSL を使って Go 言語に変換してみる(ただし -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")
    writer.Close()

    resp, err := http.Post("https://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))
}

出力のみちょっと弄って

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()

    resp, err := http.Post("https://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 gitio.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 が取得できた。

ちなみに最初の curl コマンドの -F-d に替えて cURL as DSL にかけると2

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("https://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))
}

のように変換される。 http.Post() 関数から http.PostForm() 関数に替わってかなりコードがすっきりした。 今回のような単純な request ならこちらの方がいいだろう。

ついでにパッケージも作ってみた

これを称して「他人の褌で相撲を取る」という3。 なるほど。 こうやって API を実装していくんだね。

ブックマーク

Go 言語に関するブックマーク集はこちら


  1. 今のところは Go 言語のほかに Python3, PHP, JavaScript (node.js/XMLHttpRequest), Java, Objective-C (NSURL_Session/NSURLConnection), Vim Script (WebAPI-vim) に対応している。 ↩︎

  2. 初出の記事のコメントで cURL as DSL の作者の方に教えていただいた。感謝! ↩︎

  3. 実はジェネレータで生成したコードの著作権は誰に帰属するのか,とかいろいろ思うところはあるのだけど,それはまた別の機会に。 ↩︎