Category Archives: gae

gcp コマンド

// update
gcloud components update

// アカウントの切り替え
gcloud auth login

// プロジェクトの切り替え
gcloud config set project {プロジェクト名}

// firewallのリスト確認
gcloud beta app firewall-rules list

golang select2

API作成

api_handler.go

// Index ...
func Index(c *gin.Context) {
    ctx := appengine.NewContext(c.Request)
    httpclient := urlfetch.Client(ctx)
    client, err := kintone.NewClient(
        os.Getenv("KINTONE_DOMAIN"),
        os.Getenv("KINTONE_USER"),
        os.Getenv("KINTONE_PASSWORD"),
        "38",
        httpclient,
    )
    if err != nil {
        panic(err)
    }

    var us []*user
    query := c.DefaultQuery("q", "")
    if query != "" {
        query := fmt.Sprintf(`name like "%s"`, c.Query("q"))
        rs, err := client.GetRecords(query)
        if err != nil {
            panic(err)
        }
        for _, r := range rs {
            var u user
            u.ID = string(r.Fields["employee_number"].(kintone.SingleLineTextField))
            u.Text = string(r.Fields["name"].(kintone.SingleLineTextField))
            us = append(us, &u)
        }
    }
    if len(us) > 0 {
        c.JSON(200, us)
    } else {
        b := []byte(`[]`)
        c.JSON(200, string(b))
    }
}

レスポンス

[{"id":"1","text":"{名前1}"},{"id":"2","text":"{名前2}"},

ajax

$(function(){
  $('select').select2({
    placeholder: "名前か従業員番号を入力して、検索してください",
    ajax: {
        url: "http://localhost:8080/api/apps/40/records",
        delay: 250,
        cache: true,
        dataType: 'json',
        type: "GET",
        data: function(params) {
          return { q: params.term };
        },
        processResults: function (data, params) {
        return { results: $.map(data, function(obj) {
            return { id: obj.id, text: obj.text };
          })
        };
      }
    }
  })
});

html

<label>{{.FieldInfo.Label}}</label>
<select name={{.FieldInfo.Code}} class="form-control">
</select>

taskque module

app.yaml

application: test
module: dev  // module名セット
version: 2
runtime: go
api_version: go1.8

queue.yaml

queue:
- name: dev  // module名セット
  rate: 1/s
  mode: push
  target: dev  // module名セット
  max_concurrent_requests: 1
  retry_parameters:
    task_retry_limit: 3
    task_age_limit: 1d

queueセット

p := url.Values{
    "recordID": {w.Record.ID},
    "appID":    {w.App.ID},
}
task := taskqueue.NewPOSTTask(endpoint, p)
_, err := taskqueue.Add(ctx, task, "dev")  // module名セット
if err != nil {
    return err
}

gin file post

fileData, header, err := c.Request.FormFile(fi.Code)
if err == nil && fileData != nil {
    fileName := header.Filename
    formData, formDataContentType, err := getFormData(fileData, fileName)
    if err != nil {
        return nil, err
    }
    fileKey, err := client.AddFile(formData.Bytes(), formDataContentType)
    if err != nil {
        return nil, err
    }
    fs = append(fs, &kintone.File{FileKey: fileKey})
}

func (c *Client) AddFile(body []byte, formDataContentType string) (fileKey string, err error) {
    req, err := http.NewRequest("POST", c.url(APIEndpointFile, ""), bytes.NewBuffer(body))
    if err != nil {
        return
    }
    req.Header.Set("Content-Type", formDataContentType)
    res, err := c.do(nil, req)
    if err != nil {
        return
    }
    body, err = ioutil.ReadAll(res.Body)
    res.Body.Close()
    if err != nil {
        return
    }
    if res.StatusCode != 200 {
        err = fmt.Errorf(string(body))
        return
    }
    var t struct {
        FileKey string `json:"filekey"`
    }
    if err = json.Unmarshal(body, &t); err != nil {
        return
    }
    fileKey = t.FileKey
    return
}

func getFormData(fileData multipart.File, fileName string) (*bytes.Buffer, string, error) {
    formData := &bytes.Buffer{}
    writer := multipart.NewWriter(formData)
    h := make(textproto.MIMEHeader)
    h.Set("Content-Disposition", fmt.Sprintf(`form-data; name="file"; filename="%s"`, fileName))
    h.Set("Content-Type", "text/plain")
    fw, _ := writer.CreatePart(h)
    io.Copy(fw, fileData)
    formDataContentType := writer.FormDataContentType()
    writer.Close()
    return formData, formDataContentType, nil
}

datastore

package controllers

import (
    "app-engine-test/app/models"
    "strconv"

    "github.com/gin-gonic/gin"
    "google.golang.org/appengine"
    "google.golang.org/appengine/datastore"
)

// Datastore ...
type Datastore struct{}

// Create ...
func (Datastore) Create(c *gin.Context) {
    ctx := appengine.NewContext(c.Request)
    var user models.User
    user.Name = "yyy"
    c.Bind(&user)
    key := datastore.NewIncompleteKey(ctx, "User", nil)
    _, err := datastore.Put(ctx, key, &user)
    if err != nil {
        c.JSON(500, err)
    } else {
        c.JSON(200, user)
    }
}

// GetsAll ...
func (Datastore) GetsAll(c *gin.Context) {
    ctx := appengine.NewContext(c.Request)
    q := datastore.NewQuery("User").Limit(10)
    users := make([]models.User, 0, 10)
    q.GetAll(ctx, &users)
    s := strconv.Itoa(len(users))
    c.String(200, s)
}

// Find ...
func (Datastore) Find(c *gin.Context) {
    ctx := appengine.NewContext(c.Request)
    users := make([]models.User, 0, 10)
    q := datastore.NewQuery("User").Filter("Name =", "yyy")
    q.GetAll(ctx, &users)
    s := strconv.Itoa(len(users))
    c.String(200, s)
}

gae サービス名

1つのアプリケーションに複数のサービスを展開することが可能

application: {アプリケーション名}
module: {サービス名}
version: 1
runtime: go
api_version: go1.8

handlers:
- url: /.*
  script: _go_app
  secure: always

gae go gin

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

func init() {
    r := gin.Default()
    r.GET("/", handler)
    http.Handle("/", r)
}

func handler(c *gin.Context) {
    code := c.Query("code") // /?code=12345
    c.String(200, code)
}