paiza開発日誌

IT/Webエンジニア向け総合求人・学習サービス「paiza」(https://paiza.jp ギノ株式会社)の開発者が開発の事、プログラミングネタ、ITエンジニアの転職などについて書いています。

Go言語フレームワークRevelとPaizaCloudを使って10分でWebサービスを作る方法

f:id:paiza:20180323134353p:plain
(English article is here)

f:id:paiza:20151217152725j:plainこんにちは、吉岡(@)です。

Go言語は -ネットワーク関連を含めて標準ライブラリが充実している -並列処理が簡単に書ける -実行ファイルが1ファイルで運用しやすい などの特徴があり、Webサービス開発でも最近人気のモダンな言語です。

Google Trendsをみても、人気が伸びていることがわかりますね。

f:id:paiza:20180323105259p:plain google trends より

Go言語は、標準ライブラリだけでもWebサービスを開発できるようになっていますが、本格的なWebサービスを作るには、Webアプリケーションフレームワークやライブラリがあるとより簡単に開発できます。

Go言語のWebアプリケーションフレームワークには、Revel, Echo, Gin, Irisなどがありますが、Webサービス開発に必要な機能が一通り揃っているフルスタックのGo言語フレームワークとして有名なのがRevelです。

Revelには、Web開発に便利なルーティング、MVC、ジェネレータ等の機能が含まれており、Revelの流儀にしたがって作れば、自然とわかりやすい構造のWebアプリケーションが作れるようになっています。またRevel自身の機能ではありませんが、ORマッパーもGormなどとライブラリを組み合わせることで利用できます。

ただ、初心者がいざ開発で使おうとすると、Go言語、Revel、Gorm、データベースを動かすための環境構築やデプロイなどなどが必要になってきます。これが意外と厄介で、手順通りにインストールしたつもりでも、OSやバージョン、ほかのソフトウェアなど、さまざまな原因でエラーが出たりして失敗することもあります。

そこで、今回はブラウザだけでGo言語とRevelを使ったWeb開発ができるPaizaCloud Cloud IDEを使ってみます。

PaizaCloudは自由度が高く、さまざまなフレームワークや言語を使ったWeb開発が、初心者でも簡単にできますので、最短でGo言語とRevelを使ったWeb開発が始められます。開発環境がクラウド上で動作しているので、自分でサーバなどを用意しなくても、作ったWebサービスをその場で公開することも可能です!

今回は、まずは簡単なプログラムから始めて、Go言語WebフレームワークRevelでToDoリストを作成・編集できるサービスを作ってみましょう。手順に沿って進めれば、初心者でも10分程度で作れるかと思いますのでぜひ挑戦してみてください。

PaizaCloud Cloud IDEを使う

それでは、始めていきましょう。

PaizaCloud Cloud IDEのサイトはhttps://paiza.cloud/です。

https://paiza.cloud/

メールアドレスなどを入力して登録すると、登録確認メールが送られてきます。GitHubGoogle(Gmail)ログインを利用すると、ボタン一つで登録することもできます。

サーバを作る

開発環境となるサーバを作りましょう。

f:id:paiza:20171213234155p:plain

「新規サーバ作成」ボタンを押して、サーバ作成画面を開きます。

データベースを利用できるように、phpMyAdmin, MySQLをクリックして「新規サーバ作成」ボタンを押します。

f:id:paiza:20180228111202p:plain

3秒程度で、Go言語WebフレームワークRevelを使える開発環境がブラウザ上にできあがります。

f:id:paiza:20180228120822p:plain

パッケージのインストール

まずは、Revelとgormの環境を用意しましょう。といっても、PaizaCloudではGo言語やMySQLなどはすでにインストールされているので、"go get"コマンドを実行するだけです。

PaizaCloudでは、ブラウザ上でコマンドを入力するための「ターミナル」を使うことができます。

画面左側の「ターミナル」のボタンをクリックしましょう。

f:id:paiza:20171213234317p:plain

ターミナルが起動しますので、"go get ライブラリ名"のようにコマンドを入れます。ここでは、以下のようにRevel、Gorm用のパッケージをインストールします。

$ go get github.com/revel/revel
$ go get github.com/revel/cmd/revel
$ go get github.com/jinzhu/gorm
$ go get github.com/go-sql-driver/mysql

f:id:paiza:20180323105536p:plain

これで、"revel"コマンドが~/go/binにインストールされます。

プロジェクト作成

それでは、実際にRevelを使ってWebアプリケーションを作成してみましょう。

Revelを使ったWebアプリケーションの作成には、Go言語、Revel、Gorm、データベース(MySQL)等の設定が必要ですが、PaizaCloudでは開発環境がほとんど用意されているので、すぐにサービス開発を始められます。

まずはプロジェクトを作成しましょう。

プロジェクトの作成は、"revel new プロジェクト名"のようにコマンドを入れます。

また、go言語のプロジェクトは"go"ディレクトリに作りますので、"cd go"でgoディレクトリに移動しておきましょう。

ここでは、プロジェクト名は"myapp"としておきます。"revel new myapp"とコマンドを入れて、エンターキーを押します。

(PaizaCloudでは必要ありませんが、~/go/binにPATHが設定されていない場合"~/go/bin/revel"のように実行するか、PATH="${PATH}:${HOME}/go/bin"のようにパスを設定してください)

$ cd ~/go
$ revel new myapp

f:id:paiza:20180323111349p:plain

画面左側のファイルファインダを見ると、"go/src/myapp"というディレクトリが作られています。フォルダをクリックして、中を見てみましょう。

f:id:paiza:20180323110203p:plain

Revelプロジェクトで利用するファイルが作られています。

アプリケーションサーバの起動

作成したプロジェクトは、もうこの時点で動かすことができます。実際に動かしてみましょう!

"cd ~/go"コマンドでgoディレクトリに移動したあと、"revel run myapp"とコマンドを入れてRevelの開発用サーバを起動してみましょう。

$ cd ~/go
$ revel run myapp

f:id:paiza:20180323111505p:plain

画面の左側に、"9000"と書かれたボタンが追加されました。

f:id:paiza:20180323111533p:plain

Revelの開発環境では、9000番ポートでサーバが起動します。PaizaCloudでは、この9000番ポートに対応したブラウザ起動ボタンを自動で追加しています。

ボタンをクリックすると、ブラウザ(PaizaCloudの中で動くブラウザ)が起動して、Revelについてのページが表示されました!

f:id:paiza:20180323111629p:plain

(なお、RevelのサーバはHTTPで動作していますが、PaizaCloudではこれをHTTPSに変換しています。)

ファイルの編集

まずは、表示されたメッセージを書き換えてみましょう。

表示されているメッセージは、"~/go/src/myapp/app/views/App/Index.html"というファイルになりますので、このファイルを書き換えます。

ファイルの編集は、画面左側のファイルファインダからファイルを選択してダブルクリックします。

"go/src/myapp/app/views/App/Index.html"をダブルクリックして開いてみましょう。

f:id:paiza:20180323111814p:plain

エディタが起動しました! f:id:paiza:20180323112038p:plain

このファイルの"It works!" を、以下のように書き換えてみましょう。

go/src/myapp/app/views/App/Index.html:

      <h1>Hello Go and Revel!</h1>

f:id:paiza:20180323111945p:plain

編集したら「保存」ボタンを押すか、「Command-S」または「Ctrl-S」で保存します。

保存後、サーバが起動していない場合は起動します。

$ revel run myapp

画面左の9000と表示されているブラウザアイコンをクリックしましょう。

ブラウザが起動している場合、リロードボタンを押してみましょう。

f:id:paiza:20180323112149p:plain

設定したメッセージが表示されました!

データベースを作成

今度は、このアプリケーションでデータベースを使ってみましょう。

データベースサーバ(MySQL)はサーバ作成時に設定したので起動していますが、設定していない場合は、以下のように起動しておきましょう。

$ sudo systemctl enable mysql
$ sudo systemctl start mysql

PaizaCloudでは、このようにroot権限でパッケージやサービスをインストールすることも可能です。

まずはMySQL上に、このアプリケーションで使うデータベースを作成したいと思います。

ここでは、mysqlコマンドを使って、"mydb"というデータベースを作ります。

ターミナルを起動し、以下のようなコマンドを実行しましょう。

$ mysql -u root
create database mydb;

f:id:paiza:20180216010049p:plain

データベースが作成できました。

次に、アプリケーションでこのデータベースを使うように設定しましょう。

データベース設定などのアプリケーションの設定は"conf/app.conf"ファイルで行います。

開発モードの設定は"[dev]"セクションで行います。データベースの設定は"db.info = DBユーザ:DBパスワード@/データベース?オプション"のように記述します。

ここでは、ユーザ名は"root"、パスワードはなし、データベース名は"mydb"になりますので、オプションを加えて以下のように"[dev]"の下に設定を記述します。

go/src/myapp/conf/app.conf:

[dev]
db.info = root:@/mydb?charset=utf8&parseTime=True

また、データベースの初期化を行うコードを"app/controllers/gorm.go"に作成します。

"go/src/myapp/app/controllers"ディレクトリを選択し、右クリックメニューから「新規ファイル」を選択します。

f:id:paiza:20180323112555p:plain

ファイル名に"gorm.go"を入力し、「作成」ボタンを押してファイルを作成します。

f:id:paiza:20180323112643p:plain

エディタが開きますので、以下のように記述しておきます。

go/src/myapp/app/controllers/gorm.go:

package controllers

import (
    _ "github.com/go-sql-driver/mysql"
    "github.com/jinzhu/gorm"
    "github.com/revel/revel"
    "myapp/app/models"
    "log"
    )

var DB *gorm.DB

func InitDB() {
    dbInfo, _ := revel.Config.String("db.info")
    db, err := gorm.Open("mysql", dbInfo)
    if err != nil {
        log.Panicf("Failed gorm.Open: %v\n", err)
    }

    db.DB()
    db.AutoMigrate(&models.Post{})
    DB = db
}

記述できたら、保存ボタンを押すか、Ctrl-S、Command-Sキーを押して、ファイルを保存します。

このコードを見てみましょう。

InitDB()関数では、設定ファイルの"db.info"からデータベース設定を読み込み、gormライブラリを利用してデータベースを開きます。

"db.AutoMigrate()"を呼び出すること、後ほど作成するPostモデルにしたがってデーブルを作成します。

開いたデータベースは大文字で始まる"DB"変数に割り当てておき、他のファイルから"controllers.DB"でアクセスできるようにします。

また、"app/init.go"を以下のように編集して、このInitDB()関数を呼び出します。

go/src/myapp/app/init.go:

package app

import (
  "github.com/revel/revel"
  "myapp/app/controllers"
)

...

func init() {
  ...
  revel.OnAppStart(controllers.InitDB)
}

...

変更箇所は二箇所です。まず、importに"myapp/app/controllers"を追加し、controllersパッケージを呼び出せるようにします。

また、init()関数の最後に"revel.OnAppStart(controllers.InitDB)"を追加することで、アプリケーション起動時に先ほど作成した"germ.go"の"InitDB()"関数を呼び出します。

テーブル、モデル等の作成

次に、データベーステーブルを作成したいと思います。

gormではGo言語で構造体として記述したモデル情報を使って、データベースを操作することができます。

ここでは、ToDoリストの情報を保存する"post"テーブルを、"Post"モデルを使って操作します。

Postモデルは"app/models/post.go"ファイルで作成します。

"go/src/myapp/app"ディレクトリを右クリックして「新規ディレクトリ」を選択し、"models"ディレクトリを作成します。そして、""go/src/myapp/app/models"ディレクトリを右クリックして「新規ファイル」を選択し、"post.go"ファイルを作成します。作成した"app/models/post.go"ファイルを以下のように編集します。

go/src/myapp/app/models/post.go:

package models

type Post struct {
    Id  uint64 `gorm:"primary_key" json:"id"`
    Body string `sql:"size:255" json:"body"`
}

コードを見てみましょう。"Post"構造体では、整数型のId、文字列型のBodyというフィールドがあります。これがデータベースの"post"テーブルの"id"カラムと、"body"カラムに対応します。

サーバを一度終了して再起動してみましょう。

$ cd ~/go
$ revel run myapp

アプリケーション実行時にマイグレーションが実行されテーブル"posts"が作成されました。

作成したデータベーステーブルのデータは、phpMyAdminでも確認できます。

PaizaCloudのブラウザ上で"http://localhost/phpmyadmin/"と入れてみましょう。

f:id:paiza:20180323132256p:plain

postsモデルが確認できますね。ここから、データの追加、編集、削除なども行えます。

ルーティング設定

ToDoリストでは、一覧表示、ToDoの追加、ToDoの削除の3つの操作を行います。

それぞれ、以下のようなURLルーティングを割り当てます。

メソッド パス名 操作
GET /posts ToDo一覧表示
POST /posts/create ToDo追加
POST /posts/<int:id>/delete ToDo削除

ルーティング設定は"conf/routes"で行います。

トップページは"/posts"にリダイレクトする設定にしておきましょう。

以下のように"conf/routes"を設定します。

go/src/myapp/conf/routes:

GET     /                                       Post.RedirectToPosts
GET     /posts                                  Post.Index
POST    /posts                                  Post.Create
POST    /posts/:id/delete                       Post.Delete

"Get /"リクエストではPostコントローラのRedirectToPostsメソッドを呼び出します。

"Get /posts"、"POST /posts"、"POST /posts/:id/delete"リクエストではPostコントローラのIndex,Create,Delete関数を呼び出します。

":id"の部分はパラメータとしてプログラムから参照できます。

コントローラ設定

ルーティングから呼び出されるコントローラを"app/controllers/post.go"として作成します。

"app/controllers"ディレクトリを右クリックして"post.go"ファイルを作成します。

このファイルで、一覧表示、追加、削除に対応する、Index()、Create()、Delete()メソッドを定義します。

go/src/myapp/app/controllers/post.go:

package controllers

import (
    "github.com/revel/revel"
    "myapp/app/models"
    "errors"
)

type Post struct {
    *revel.Controller
}

func (c Post) Index() revel.Result {
    posts := []models.Post{}

    result := DB.Order("id desc").Find(&posts);
    err := result.Error
    if err != nil {
        return c.RenderError(errors.New("Record Not Found"))
    }
    return c.Render(posts)
}
func (c Post) Create() revel.Result {
    post := models.Post{
        Body: c.Params.Form.Get("body"),
    }
    ret := DB.Create(&post)
    if ret.Error != nil {
        return c.RenderError(errors.New("Record Create failure." + ret.Error.Error()))
    }
    return c.Redirect("/posts")    
}
func (c Post) Delete() revel.Result {
    id := c.Params.Route.Get("id")
    posts := []models.Post{}
    ret := DB.Delete(&posts, id)
    if ret.Error != nil {
        return c.RenderError(errors.New("Record Delete failure." + ret.Error.Error()))
    }
    return c.Redirect("/posts")    
}

func (c Post) RedirectToPosts() revel.Result {
    return c.Redirect("/posts")    
}

コードを見ていきましょう。

まず、importに"myapp/app/models"を追加し、Postモデルを参照できるようにします。

"type Post struct"でPostコントローラを作成します。

"func (c Post) Index() revel.Result"はPostコントローラのIndex()メソッドで、Todo一覧ページを返します。

"posts := []models.Post{}"では、Postモデルの配列posts作成します。

'DB.Order("id desc").Find(&posts)'では、データベースのpostsテーブルから全てのレコードを取得し、posts配列に格納します。

エラーがなければ、Renderメソッドを呼び出してHTMLファイルを作成します。

HTMLファイルは、あとでviewsディレクトリに作成するHTMLテンプレートから作成します。Render()の引数にpostsを指定することで、テンプレート中でpostsテーブルの内容を参照できるようになります。

"func (c Post) Create() revel.Result"はPostコントローラのCreate()メソッドで、Todoを作成します。

models.Post{...}ではモデルを作成します。モデルのBodyフィールドには、フォームで送信される"body"パラメータの内容を"c.Params.Form.Get()"で取得して設定します。

DB.Create(&post)でモデルからデータベースのレコードを作成し、最後に'c.Redirect("/posts")'で一覧ページにリダイレクトします。

"func (c Post) Delete() revel.Result"はPostコントローラのDelete()メソッドで、Todoを削除します。

'c.Params.Route.Get("id")'ではURLの"/posts/:id/delete"の":id"部分を取得します。

"DB.Delete(&posts, id)"で指定したidのレコードをデータベースから削除します。

最後に'c.Redirect("/posts")'で一覧ページにリダイレクトします。

"func (c Post) Redirect() revel.Result"はトップページからTodo一覧ページにリダイレクトするためのメソッドです。

HTMLテンプレートの作成

次に、HTMLテンプレートです。HTMLテンプレートはHTMLファイルにコードを埋め込んで記述します。

ToDo一覧表示と、ToDo追加、削除のためのHTMLテンプレートを"app/views/Post/index.html"という名前で作成しましょう。

まず、"go/myapp/app/views"フォルダを右クリックして「新規ディレクトリ」を選び、"Post"ディレクトリを作成します。

そして、"go/myapp/app/views/Post"フォルダを右クリックして「新規ファイル」を選び、"index.html"ファイルを作成します。

作成した"app/views/Post/index.html"ファイルに以下のように記述します。

go/myapp/app/views/Post/index.html:

{{set . "title" "Todo list"}}
{{template "header.html" .}}

<header class="jumbotron" style="background-color:#A9F16C">
  <div class="container">
    <div class="row">
      <h1>Todo list</h1>
      <p></p>
    </div>
  </div>
</header>

<div class="container">
  <div class="row">
    <div class="span6">
      {{template "flash.html" .}}
    </div>
  </div>
</div>

<div class="container">
    <form action="/posts" method="post">
        <div class="form-group">
            <div class="row">
                <label for="todo" class="col-xs-2">Todo</label>
                <input type="text" name="body" class="col-xs-8">
                <div class="col-xs-2">
                    <button type="submit" class="btn btn-success">
                        <i class="fa fa-plus"></i> Add Todo
                    </button>
                </div>            
            </div>
        </div>
    </form>

    <h2>Current Todos</h2>
    <table class="table table-striped todo-table">
        <thead>
            <th>Todos</th><th>&nbsp;</th>
        </thead>

        <tbody>
            {{ range .posts }}
                <tr>
                    <td>
                        <div>{{ .Body }}</div>
                    </td>
                    <td>
                        <form action="/posts/{{.Id}}/delete" method="post">
                            <button class="btn btn-danger">Delete</button>
                        </form>
                    </td>
                </tr>
            {{ end }}
        </tbody>
    </table>
    
</div>


{{template "footer.html" .}}

HTMLテンプレートでは、"{{"と"}}"の間ではアクションを記述し、記述したアクションの内容でHTMLが作成されます。

'{{set . "title" "Todo list"}}'では、"title"変数に"Todo list"を設定しています。

'{{template "header.html" .}}'では、"header.html"テンプレートからHTMLを生成します。

このように他のHTMLテンプレートを呼び出すことで、複数のテンプレートに共通の内容をまとめることができます。

ここでは、"header.html"には、HTMLヘッダの内容がまとまっています。

'<form action="/posts" method="post">'はTodoを作成するためのフォームです。

'<input type="text" name="body" class="col-xs-8">'で、Todoの内容を入力するテキスト入力フォームを表示します。

フォームの名前を"body"に設定し、フォーム送信時のbodyパラメータにTodoの内容が入るようにします。

'{{ range .posts }}'から'{{ end }}'の間は、posts配列の内容を順番に読み出して、HTMLを繰り返し作成します。

'{{ .Body }}'では、posts配列のBodyフィールドの内容を表示します。{{.ID}}では、posts配列のIdフィールドの内容を表示します。

最後に'{{template "footer.html" .}}'でフッターのHTMLテンプレートを読み込みます。

動作確認

プログラムは以上です。実際に動かしてみましょう。

サーバを起動していない場合は起動します。

ブラウザアイコン(9000)をクリックして、PaizaCloud内のブラウザを起動します。

最初はToDoはないのですが、"Todo List"ページが表示されています。

ToDoの追加や削除をしてみましょう。

f:id:paiza:20180323133151p:plain

動きましたね!Go言語フレームワークRevelで作ったToDoリストの完成です!

なお、PaizaCloudの無料プランでは、一定時間が経つとサーバは停止します。継続的に動かしたい場合は、ベーシックプランへアップデートしてください。

詳しくはこちら
https://paiza.cloud

まとめ

というわけで、PaizaCloudを使って、開発環境などを構築することなく、ブラウザだけでGo言語フレームワークRevelのWebアプリケーションを作ってみました。

すぐに作れますし、そのまま公開することもできるので、みなさんもぜひ試してみてください!

(何かサービスができたらpaiza( @paiza_official )まで教えてくれるとうれしいです!)


PaizaCloud」は、環境構築に悩まされることなく、ブラウザだけで簡単にウェブサービスやサーバアプリケーションの開発や公開ができます。
https://paiza.cloud


paizaラーニング」では、未経験者でもブラウザさえあれば、今すぐプログラミングの基礎が動画で学べるレッスンを多数公開しております。

そして、paizaでは、Webサービス開発企業などで求められるコーディング力や、テストケースを想定する力などが問われるプログラミングスキルチェック問題も提供しています。

スキルチェックに挑戦した人は、その結果によってS・A・B・C・D・Eの6段階のランクを取得できます。必要なスキルランクを取得すれば、書類選考なしで企業の求人に応募することも可能です。「自分のプログラミングスキルを客観的に知りたい」「スキルを使って転職したい」という方は、ぜひチャレンジしてみてください。

paizaのスキルチェック