Help us understand the problem. What is going on with this article?

Go言語(Gin+Lorca)+News APIで作るデスクトップアプリ

More than 1 year has passed since last update.

Go言語のWebフレームワークGinと、デスクトップアプリ開発用ライブラリのLorcaを使って簡易的なニュースビューワーを作ってみました。
GitHubにコードをアップしています(https://github.com/wassan128/newsman/)。

あらまし

ニュースを見る癖が無く、世間に置いて行かれがちな自分のためにニュースビューワーを作ろうと思ったのがきっかけです。Node.js(Electron)で書こうとも思ったのですが、せっかく最近Go言語を勉強し始めたのでGoで似たようなことができないかと調べていたところ、同じようなことができるものがあることを知ったのでやってみた次第です。

作るに当たって

  1. ニュースを何かAPIで取得
  2. 簡易的なWebアプリとして起動
  3. デスクトップアプリ風ウィンドウに描画する

ということをします。一旦完成とした画面は以下のようになっています。

newsman.png

環境

  • Ubuntu18.04 1 LTS 64bit
  • Go言語バージョン go1.10.4 linux/amd64

Gin

Go製のWebフレームワークです(https://github.com/gin-gonic/gin)。

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

と、イケてるDescriptionもさることながら、初学者の私でもある程度直感に従って使えるフレームワークであるように感じたので採用しました(他に良いものがあれば知りたいです)。

Lorca

Go製のデスクトップアプリ開発用ライブラリです(https://github.com/zserge/lorca)。HTML5でUIを書くことができる、軽量なライブラリとなっており、Go言語コード内でJavaScriptコードを呼び出せるなどの特徴があるようです(今回のプログラムではその機能は使っていませんが)。

開発①ニュースの取得

今回ニュース取得のAPIにはNews API(https://newsapi.org/)のTop headlinesを用いました。
News APIにデベロッパー登録するとAPIキーがもらえます(手順は割愛します)。リクエストは
https://newsapi.org/v2/top-headlines?country=jp&apiKey=XXX
に飛ばします。今回は日本のニュースがほしいのでcountryjpとしています。

APIからはJSONが返されるので、これをGo言語側で受け取ります。Top headlinesのサンプルレスポンスを見るとNews APIのJSONは

{
    "status": "ok",
    "totalResults": 36,
    "articles": [
    {
        "source": {
             "id": "cnn",
             "name": "CNN"
        },
        "author": null,
        "title": "Mueller starts to piece together Russia puzzle in most significant move yet - CNN",
        "description": null,
        "url": "https://www.cnn.com/2018/11/30/politics/donald-trump-michael-cohen-robert-mueller/index.html",
        "urlToImage": null,
        "publishedAt": "2018-11-30T06:53:00Z",
        "content": null
     }, ...

という構造になっているので、これをそのまま

type Source struct {
    Id   string `json:"id"`
    Name string `json:"name"`
}
type Article struct {
    Source      Source `json:"source"`
    Author      string `json:"author"`
    Title       string `json:"title"`
    Description string `json:"description"`
    Url         string `json:"url"`
    UrlToImage  string `json:"urlToImage"`
    PublishedAt string `json:"publishedAt"`
    Content     string `json:"content"`
}
type News struct {
    Status       string    `json:"status"`
    TotalResults int       `json:"totalResults"`
    Articles     []Article `json:"articles"`
}

と構造体に落とし込みます。これで

// ニュースをHTTPリクエストし
res, err := http.Get(EndPoint)
if err != nil {
    fmt.Println("json load error")
}
defer res.Body.Close()

// レスポンスのBodyからJSON形式のニュースを取り出し
var news News
data, _ := ioutil.ReadAll(res.Body)
// JSONをデコードしてNews型変数にデータを入れる
if err := json.Unmarshal(data, &news); err != nil {
    fmt.Println(err)
}

とすると変数newsにニュースの情報を格納することができます。このJSONと構造体の対応付けなどはGo言語ならでは感があるなと思いました(初学者並感)。

開発②Webアプリ化

「/」にアクセスするとニュースのタイトルが出るような実装にしたいので、

func server(news News) {
    router := gin.Default()
    // cssや画像は「static」ディレクトリ配下に設置することとする
    router.Static("/static", filepath.Join(os.Getenv("GOPATH"), repo_path, "static"))
    // テンプレートファイルは「templates」ディレクトリ配下に設置することとする
    router.LoadHTMLGlob(filepath.Join(os.Getenv("GOPATH"), repo_path, "templates/*"))
    router.GET("/", func(c *gin.Context) {
        c.HTML(http.StatusOK, "index.tmpl", gin.H{
            "articles": news.Articles,
        })
    })
    go router.Run()
}

というような関数を用意します。router.Run()でポートを指定できますが今回は省略しているので、デフォルトの「:8080」になります。
index.tmplというテンプレートファイルにarticlesという名前でニュースの記事データを渡しています。ここで渡した値はテンプレートファイル内で

{{range .article}}
    <p>{{.Title}}</p>
{{end}}

というように参照できます。

router.Run()先頭にgoをつけてgoroutineにしているのは次ステップのLorcaでの画面描画をブロックしないためです。

開発③デスクトップアプリにする

ここまででニュースを取得して表示するWebアプリができているので、あとはこれをLorcaの力でデスクトップアプリにするだけです。

var ui lorca.UI
// 幅320、高さ480のウィンドウを生成
ui, _ = lorca.New("", "", 320, 480)
defer ui.Close()

// Ginで動かしたWebアプリのURLを指定
ui.Load("http://localhost:8080")
<-ui.Done()

とても簡単にできました。

プログラム実行の時系列としては「ニュースの取得」→「サーバー起動」→「デスクトップアプリにする」なので、ループに入るサーバー起動部を非同期処理にすることでサーバーを裏で動かしつつそこでホスティングされているコンテンツを描画しています。

まとめ

思っていたよりも簡単にデスクトップアプリ化することができました。まだまだ改良の余地もありそうですし、これからもちょっとずつ機能追加や他のアプリも作ってみたいです。

Go言語を学び始めて日が浅く、間違いやここはもっとこうした方が良いよなどあればぜひアドバイスいただきたいので、よろしくお願いします。

参考にさせていただいた記事

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away