1.はじめに
記事をご覧いただきありがとうございます。
今までC#とMySQLの接続は行ったことがあったのですが
ほとんど触れたことのないGo言語(+echo)とPostgreSQLとの接続
を行うことになったので備忘録的に手順を記していこうかと思います。
初歩的なところから説明するので適宜読み飛ばしていただければと思います。
2.PostgreSQLの設定
2-1.PostgreSQLのダウンロード
PostgreSQLのHPにアクセスしてダウンロードをクリック
 
Binary packagesの中から自分のOSをクリック
 
ページ内のDownload the installerをクリック(今回はWindowsですが他も同じ手順です。)
 
自分のOSの使いたいバージョンのDownloadをクリック
(今回はWindowsx86-64の12.1バージョンをダウンロードしました。)
 
2-2.PostgreSQLのインストールと環境変数設定(Windows10)
ダウンロードした**postgresql-(バージョン数)-(OS名)アプリケーションを実行し
このような画面が出たら基本的にNext>**を押し続けてください。
passwordだけは自分で設定しますが、portは基本的に干渉しなければ変えなくてよいと思います
インストールが完了したらシステム環境変数を設定します。
PostgreSQLをインストールした場所の中のbinフォルダがある場所
(変更していなければ、C:\Program Files\PostgreSQL(バージョン数))
にPathを通します。
Windows10の場合、スタートメニューを右クリック>設定で以下の画面が出るので
「システム環境」と入力すると「システム環境変数」が出てきます。
下のような画面が出てくるので環境変数をクリック
システム環境変数のPathをクリックして編集>前のパスの間に**;(セミコロン)**を
はさんでPostgreSQLをインストールした場所の中のbinフォルダがある場所のパスを入力
 
ここまで終わったらコマンドプロンプトを起動し、
psql --varsion
と入力してPostgreSQLのバージョン数が出ればインストール完了です。
3.echoのインストール
下のコマンドで一発でインストールできます。
go get -u github.com/labstack/echo...
4.SQLのデータをc.Stringでreturnするプログラム
4-1.概要
PostgreSQLの表示パターンを2個作っていきます。
- sql.GetPost()
URLのプレースホルダからidをもらってきて
idが一致するレコードを表示する。
- sql.GetPosts()
postsテーブルのレコードをすべて表示する。
4-2.データベースとテーブル作成
コマンドプロンプトでPostgreSQLにログインする
下のコマンドを打ってパスワードを入力
psql -U postgres
今回はsampleという名前のDBを作るので
下のコマンドを入力
CREATE DATABASE sample
先ほど作ったデータベースに接続するコマンドを入力
¥c sample
sampleデータベースにpostsテーブルを作る
create table posts (
  id integer, 
  content varchar(80),
  content author(80)
);
postsテーブルにレコード挿入する(お好きなだけどうぞ)
insert into posts values (1, 'test', 'test1user');
insert into posts values (2, 'testtest', 'test2user');
insert into posts values (3, 'testtesttest', 'test3user');
以上でPostgreSQLの操作は完了です。
4-3.フォルダ構成
作業フォルダ--- main.go
             ∟ sql      --- sql.go
4-4.main.go
package main
import (
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
    "github.com/~/sql"   //SQLについて記述したパッケージのパス
)
func main() {
    // Echoのインスタンス
    e := echo.New()
    // ミドルウェア類
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(interceptor.BasicAuth())
    // ルーティング
    e.GET("/sql/record/:id", sql.GetPost()) //プレースホルダでidをもらってくる
    e.GET("/sql/table", sql.GetPosts())
    // サーバー起動
    e.Start(":1323")
}
【ポイント】
- 基本的にmain.goにはルーティングをだけをしています。
4-5.sql.go
package sql
import (
	"database/sql"
	"net/http"
	"github.com/labstack/echo"
	"github.com/pkg/errors"
	_ "github.com/lib/pq"
	"strconv"
)
type Post struct {
	Id      int
	Content string
	Author  string
}
var content string
var Db *sql.DB
func init() {
	var err error
	Db, err = sql.Open("postgres", "user=postgres dbname=sample password=自分で設定したパスワード sslmode=disable")
	if err != nil {
		panic(err)
	}
}
func GetPost() echo.HandlerFunc {
	return func(c echo.Context) error {
		id := c.Param("id")  //プレースホルダのidを取得
		post := Post{}
		if err := Db.QueryRow("select id, content, author from posts where id = $1", id).Scan(&post.Id, &post.Content, &post.Author); err != nil {
			return errors.Wrapf(err, "connot connect SQL")
		}
		return c.String(http.StatusOK, " ID : " + strconv.Itoa(post.Id) + " CONTENT : " + post.Content + " AUTHOR : " + post.Author)
		// string(Post.Id)だと何故かファイルダウンロードしてしまい、IDも表示されない。
		// strconv.Itoa(post.Id) の部分はプレースホルダから取り出したidでも可
	}
}
func GetPosts() echo.HandlerFunc {
	return func(c echo.Context) error {
		post := Post{}
		response := ""
		rows, err := Db.Query("select id, content, author from posts")
		if err != nil {
			return errors.Wrapf(err, "connot connect SQL")
		}
		defer rows.Close()
		for rows.Next(){
			if err := rows.Scan(&post.Id, &post.Content, &post.Author); err != nil {
				return errors.Wrapf(err, "connot connect SQL")
			}
			response += "ID : " + strconv.Itoa(post.Id) + "	CONTENT : " + post.Content + "	AUTHOR : " + post.Author + "\n"
		}
		return c.String(http.StatusOK, str)
	}
}
【ポイント】
- Db.QueryRowは1つのレコードを取得する関数でDb.Queryは複数のレコードを取得する関数
- post.Idに関してはint型なのでstring(Post.Id)にキャストしようと思うと思いますが
 それだと変な挙動をしてしまうので、strconvをインポートして**strconv.Itoa(post.Id)**とすることできちんと動きます。
- GetPosts()のほうは何回もreturnすることができないのでresponseという文字列にすべての結果を格納して表示しています。
4-6.実行画面
- sql.GetPost()
 
- sql.GetPosts()
 
5.SQLのデータをc.JSONでreturnするプログラム(12.12 追記)
記事を投稿した後にAPIサーバで使うならc.JSONで返すプログラムでなければならないな…
と思いc.JSONでreturnするプログラムに作り変えてみました。
main.goは変更していないので4-4をご覧ください。
5-1.sql.go
package sql
import (
	"database/sql"
	"net/http"
	"github.com/labstack/echo"
	"github.com/pkg/errors"
	_ "github.com/lib/pq"
)
type Post struct {
	Id      int	`json:"id"`
	Content string	`json:"content"`
	Author  string	`json:"author"`
}
var content string
var Db *sql.DB
func init() {
	var err error
	Db, err = sql.Open("postgres", "user=postgres dbname=sample password=自分で設定したパスワード sslmode=disable")
	if err != nil {
		panic(err)
	}
}
func GetPost() echo.HandlerFunc {
	return func(c echo.Context) error {
		id := c.Param("id")
		post := Post{}
		posts := []*Post{}
		if err := Db.QueryRow("select id, content, author from posts where id = $1", id).Scan(&post.Id, &post.Content, &post.Author); err != nil {
			return errors.Wrapf(err, "connot connect SQL")
		}
		posts = append(posts, &Post{Id: post.Id, Content: post.Content, Author: post.Author})
		return c.JSON(http.StatusOK, posts)
	}
}
func GetPosts() echo.HandlerFunc {
	return func(c echo.Context) error {
		post := Post{}
		posts := []*Post{}
		rows, err := Db.Query("select id, content, author from posts")
		if err != nil {
			return errors.Wrapf(err, "connot connect SQL")
		}
		defer rows.Close()
		for rows.Next(){
			if err := rows.Scan(&post.Id, &post.Content, &post.Author); err != nil {
				return errors.Wrapf(err, "connot connect SQL")
			}
			posts = append(posts, &Post{Id: post.Id, Content: post.Content, Author: post.Author})
		}
		return c.JSON(http.StatusOK, posts)
	}
}
【ポイント】
- structにjson:"○○"を追加する
- postsにデータをappendしてからreturn
5-2.実行例
6.終わりに
GoもechoもPostgreSQLも初心者なのでざっとした流れとSQLのデータ表示についてまとめてみました。
まとめてくれているサイトなどがかなり少なかったので同じようなことに迷っている人の
助けになれば幸いです。
何か間違っているところや改善したほうがいいところなどありましたら教えていただけると幸いです。





