読者です 読者をやめる 読者になる 読者になる

Go言語で、はてなスターをカウントするJSONPを実装した。

f:id:nasust:20170121165229j:plain

こんにちはnasustです。 先週ぐらいから、関連記事に❤️と数字が付いているのをお気づきでしょうか。

実ははてなスターをカウントしたものです。記事にはてなスターというものがあるので、関連記事の一覧にはてなスターの数を表示したかったんですよね。

そうすることで、記事の評価が分かりやすいかなと思いまして表示する様にしました。

ブログ全体のはてなスター取得は簡単ですけど、個々の記事のスター数は簡単に取得できないですよね。

はてなスター取得 API - Hatena Developer Center

こちらのAPIで記事毎にスター数を取得できますが、JSONPに対応していないのでJavaScriptから利用できません。

ですので、このAPIと橋渡しするGo言語のJSONPAPIを作成しました。

Go言語のAPIに記事のURLを渡すとスター数を返す様にしました。

Go言語のソース

はてなスターを取得するAPIは以下のオープンソースを利用しています。

GitHub - antonholmquist/jason: Easy-to-use JSON Library for Go

このオープンソースを利用することで簡単にJSONから値を取り出せます。

func handlerStar(writer http.ResponseWriter, req *http.Request) {
    urls := req.FormValue("urls")
    callback := req.FormValue("callback")

    if urls == "" || callback == "" {
        writer.WriteHeader(http.StatusInternalServerError)
        fmt.Println(writer, "param error")
        return
    }

    urlList := strings.Split(urls, ",")

    var uri string = ""

    for i, queryUrl := range urlList {
        if strings.HasPrefix(queryUrl, "http://nasust.hatenablog.com") == false {
            writer.WriteHeader(http.StatusInternalServerError)
            fmt.Println(writer, "http://nasust.hatenablog.com only")
            return
        }

        uri += "uri=" + url.QueryEscape(queryUrl)
        if i < len(urlList)-1 {
            uri += "&"
        }
    }

    response, err := http.Get("http://s.hatena.com/entry.json?" + uri)
    if err != nil {
        writer.WriteHeader(http.StatusInternalServerError)
        fmt.Println(writer, err)
        return
    }

    starsJson, err := jason.NewObjectFromReader(response.Body)
    if err != nil {
        writer.WriteHeader(http.StatusInternalServerError)
        fmt.Println(writer, err)
        return
    }

    starCountMap := map[string]interface{}{}

    entries, _ := starsJson.GetObjectArray("entries")
    for _, entry := range entries {

        var starCount int
        stars, _ := entry.GetObjectArray("stars")
        for _, star := range stars {
            count, err := star.GetInt64("count")
            if err == nil {
                starCount += int(count)
            } else {
                starCount += 1
            }
        }

        coloredStars, _ := entry.GetObjectArray("colored_stars")
        for _, coloredStar := range coloredStars {
            stars, _ := coloredStar.GetObjectArray("stars")
            for _, star := range stars {
                count, err := star.GetInt64("count")
                if err == nil {
                    starCount += int(count)
                } else {
                    starCount += 1
                }
            }

        }

        entryUri, _ := entry.GetString("uri")
        starCountMap[entryUri] = starCount
    }

    jsonBytes, _ := json.MarshalIndent(starCountMap, "", "    ")
    jsonp := callback + "(" + string(jsonBytes) + ");"

    writer.Header().Set("Content-Type", "application/javascript")
    writer.WriteHeader(http.StatusOK)
    fmt.Fprint(writer, jsonp)

}
広告を非表示にする