Edited at

🙂< golang+gae+datastore+echo+jsonのapiです - 其の弐


はじめに

appengine公式サンプル?を参考にしています。jsonでreq/resのやりとりすることを前提としています。


コード

前半と後半で分けます。前半はサーバ起動、ルーティング。後半はハンドラー関数とdatastore関連になります。ファイルはmain.goのみです。


前半


main.go

package main

import (
"fmt"
"github.com/labstack/echo"
"github.com/labstack/echo/middleware"
"google.golang.org/appengine"
"google.golang.org/appengine/datastore"
"google.golang.org/appengine/log"
"net/http"
"time"
)

var e = createMux()

type Post struct {
Author string `json:"author"`
Message string `json:"message"`
Posted time.Time `json:"posted"`
}

type templateParams struct {
Notice string `json:"notice"`
Posts []Post `json:"posts"`
}

func main() {
e := echo.New()
e.Start(":8080")
appengine.Main()
}

func createMux() *echo.Echo {
e := echo.New()
http.Handle("/", e)
return e
}

func init() {
g := e.Group("/posts")
g.Use(middleware.CORS())
g.POST("", createPost)
g.GET("", getPosts)
g.GET("/:author", getPost)
}



後半


main.go

func createPost(c echo.Context) error {

ctx := appengine.NewContext(c.Request())
post := Post{}

if err := c.Bind(&post); err != nil {
return err
}

post.Posted = time.Now()
key := datastore.NewIncompleteKey(ctx, "Post", nil)

if _, err := datastore.Put(ctx, key, &post); err != nil {
log.Errorf(ctx, "Put: %v", err)
c.Response().WriteHeader(http.StatusInternalServerError)
params := templateParams{}
params.Notice = err.Error()
return c.JSON(http.StatusInternalServerError, params)
}

params := templateParams{}
params.Notice = "Success!!"
return c.JSON(http.StatusOK, params)
}

func getPosts(c echo.Context) error {
ctx := appengine.NewContext(c.Request())
q := datastore.NewQuery("Post").Order("-Posted").Limit(20)
params := templateParams{}

if _, err := q.GetAll(ctx, &params.Posts); err != nil {
log.Errorf(ctx, "Getting Post Error: %v", err)
c.Response().WriteHeader(http.StatusInternalServerError)
params.Notice = "Getting Post Error"
return c.JSON(http.StatusInternalServerError, params)
}
params.Notice = fmt.Sprintf("Success")
return c.JSON(http.StatusOK, params.Posts)
}

func getPost(c echo.Context) error {
ctx := appengine.NewContext(c.Request())
authorParam := c.Param("author")
post := &Post{
Author: authorParam,
}
q := datastore.NewQuery("Post").Filter("Author =", post.Author) // .Filter("Country =", post.***) 条件増やすことも可能。
it := q.Run(ctx)
_, err := it.Next(post)
if err != nil {
log.Errorf(ctx, "New page: %v", err)
}
return c.JSON(http.StatusOK, post)
}



デプロイ及び使い方


terminal

$ gcloud app deploy


POSTMAN等でリクエストやレスポンスを確認してみてください。Datastoreに、Kindが作られ、エンティティが格納されているはずです。


余談

ある条件のデータを複数取り出したい場合のコードを備忘録として掲載しておきます。authorはechoフレームワークを用いて、URLパラメータから取得しています。これは余談です。


main.go


// パラメータを使い、クエリを出して、複数の返り値を出したいなら、
// このような書き方もできるかも!? 参照:https://qiita.com/mztnnrt/items/f1934e21a318daad71b9
func getPosts(c echo.Context) error {
ctx := appengine.NewContext(c.Request())
authorParam := c.Param("author")
post := &Post{
Author: authorParam,
}
q := datastore.NewQuery("Post").Filter("author =", post.Author)
it := q.Run(ctx)
var posts []Post
for {
var user Post
_, err := it.Next(&user) // 次のデータを取得
if err != nil {
if err == datastore.Done { // データが無くなったらループを抜ける
break
}
return err // エラー発生!
}
posts = append(posts, user) // スライスにデータを追加
}
return c.JSON(http.StatusOK, posts)
}

不明点や間違っている点、気軽にコメントしてください。Twitterでも構いません。