GoogleAppEngineを使ってGithubPagesでreCAPTCHAを導入する

# 前書き
特に意味はないけれどメールフォームを設置してみたかったので、
GoogleAppEngineでAPI作って、GihubPagesのポートフォリオに設置してみました

# 準備
まず、reCAPTCHAに登録する必要があります
[reCAPTCA](https://www.google.com/recaptcha/admin)の画面を開いて
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/54388/d1a543c2-9537-2a71-60d3-73b77b64a904.png)
Labelに適当な名前を入れて、Domainsに一行ごとにreCAPTCHAを利用するドメインを入れます(エイリアス用のドメインなど)
そして`Register`をクリック

# GithubPages側の記述
ふつうに`<form>`を書いてjsを貼り付けるだけです
さっき登録したあとに表示されたページの
![2.png](https://qiita-image-store.s3.amazonaws.com/0/54388/53c6f9dc-5147-4623-7b78-a59c0eed8259.png)
`Adding reCAPTCHA to your site`の中の`Step 1: client-side integration`の`<script src='https://www.google.com/recaptcha/api.js'></script>
`をheadタグ内に、`<div class="g-recaptcha" data-sitekey="～～～"></div>`を<form>内にコピペします
そして、POSTでGoogleAppEngine側をたたくように`<form method="POST" action="～～GoogleAppEngineにつくるAPIのURL～～">`と書きます
form内のそれぞれの入力箇所に`name`属性がついていることを確認します(ないとAPI側で受け取れません)

# GoogleAppEngine側の記述
まず、ルーティングを適当に設定して、POSTを受け取り、その中のデータを取り出します
![3.png](https://qiita-image-store.s3.amazonaws.com/0/54388/fc49483d-44ec-0c73-6632-f50b0a195a67.png)
そうしたら、`https://www.google.com/recaptcha/api/siteverify`に`secret さっきの登録したあとのページのStep2の中のsecret`,`response POSTで受け取ったg-recaptcha-response`をつけてPOSTします
そうすると、有効かどうかの結果が返ってきます(ex. `{"success": true}`,`{"success": false, "error-codes": [～]}`)
(GETでもできるみたいです ex.`https://www.google.com/recaptcha/api/siteverify?secret=～&g-recaptcha-response=～`)
これで有効かどうか受け取れたので、その結果を返すならページにパラメータつけてリダイレクトなどしてGithubPages側でページを書き換えるなどできます

# ソース
自分はreCAPTCHAのあとで自分にメールを送りつけています(メールフォームなので…)
GoogleAppEngine側はGo、GitHubPages側はhaml([MaterialDesignLite](https://www.getmdl.io/)使用)で書いています
## GoogleAppEngine側
ルーティングの部分などは省略します
Goですが、おそらくほかの言語でもおんなじ感じでかけると思います

```go:mainMail.go
package s4naxyz

import(
  "fmt"
  "net/http"
  "io/ioutil"
  "encoding/json"
  "google.golang.org/appengine"
  "google.golang.org/appengine/log"
  "google.golang.org/appengine/urlfetch"
  "google.golang.org/appengine/mail"
)

const secretkey = "～～～～secret～～～～"

type googleResponse struct {
	Success bool `json:success`
	ErrorCodes []string `json:error-codes`
}

func mailSendHandler(w http.ResponseWriter, r *http.Request) {
	ctx := appengine.NewContext(r)
	r.ParseForm()
	if r.Form.Get("g-recaptcha-response") == "" {
		log.Errorf(ctx, "Couldnt send email<recaptcha response error>")
		fmt.Fprint(w, "{error: true, message: \"recaptcha response error\"}")
		return
	}
	client := urlfetch.Client(ctx)
	res, err := client.Get("https://www.google.com/recaptcha/api/siteverify?secret="+secretkey+"&response="+r.Form.Get("g-recaptcha-response"))
	if err != nil {
		log.Errorf(ctx, "Couldnt send email<http getting error>: %v", err)
		fmt.Fprint(w, "{error: true, message: \"http getting error\"}")
		return
	}
	defer res.Body.Close()

	resByte, err := ioutil.ReadAll(res.Body)
	if err != nil {
		log.Errorf(ctx, "Couldnt send email<body transforming error>: %v", err)
		fmt.Fprint(w, "{error: true, message: \"body transforming error\"}")
		return
	}

	parsed := googleResponse{}
	err = json.Unmarshal(resByte, &parsed)
	if err != nil {
		log.Errorf(ctx, "Couldnt send email<json parsing error>: %v", err)
		fmt.Fprint(w, "{error: true, message: \"json parsing error\"}")
		return
	}
	if !parsed.Success {
		log.Errorf(ctx, "Couldnt send email<recaptcha authorize error>")
		fmt.Fprint(w, "{error: true, message: \"recaptcha authorize error\"}")
		return
	}

	msg := &mail.Message{
		Sender: "api.4na.xyz <～～～GMailのアドレス～～～>",
		To: []string{"～～～普段使いのアドレス～～～"},
		Subject: r.Form.Get("title"),
		Body: "From: "+r.Form.Get("name")+" ("+r.Form.Get("email")+")\n----------\nMessage:\n"+r.Form.Get("message"),
	}
	if err := mail.Send(ctx, msg); err != nil {
		log.Errorf(ctx, "Couldnt send email<mail sending error>: %v", err)
		fmt.Fprint(w, "{error: true, message: \"mail sending error\"}}")
		return
	}
	w.Header().Set("Content-Type", "text/json")
	w.Header().Set("Access-Control-Allow-Origin", "*")

	//fmt.Fprint(w, "{error: false}")

	http.Redirect(w, r, "https://s.4na.xyz/contact/", 301)
}
```

fmt.Fprintしてリダイレクトみたいなことになってますが、
まだ作り途中なので…

## GithubPages側
関連個所のみ抜粋で

```haml:index.haml
  #form.mdl-cell.mdl-cell--8-col
    .mdl-card.mdl-shadow--3dp
      .mdl-card__title
        %h2.h4.mdl-card__title-text Contact
      .mdl-card__supporting-text
        %form#form-main{method: "POST", action: "https://api.4na.xyz/mail/send"}
          .mdl-textfield.mdl-js-textfield.mdl-textfield--floating-label
            %input.mdl-textfield__input#name{name: "name", type: "text", required: true}
            %label.mdl-textfield__label{for: "name"} Name
          %br
          .mdl-textfield.mdl-js-textfield.mdl-textfield--floating-label
            %input.mdl-textfield__input#email{name: "email", type: "email", required: true}
            %label.mdl-textfield__label{for: "email"} Email Address
          %br
          .mdl-textfield.mdl-js-textfield.mdl-textfield--floating-label
            %input.mdl-textfield__input#title{name: "title", type: "text", required: true}
            %label.mdl-textfield__label{for: "title"} Title
          %br
          .mdl-textfield.mdl-js-textfield.mdl-textfield--floating-label
            %textarea.mdl-textfield__input#message{name: "message", type: "text", rows: "5", required: true}
            %label.mdl-textfield__label{for: "message"} Message
          %br
          .g-recaptcha{"data-sitekey": "～～～sitekey～～～"}
          %input#submit.mdl-button.mdl-js-button.mdl-button--raised.mdl-button--colored.mdl-js-ripple-effect{type: "submit"}
  %script{type: "text/javascript", src: "https://www.google.com/recaptcha/api.js?hl=ja", defer: true, async: true}
```

#関連情報
## reCAPTCHA
- [ウェブサイトにキャプチャを導入する方法【reCAPTCHAの使い方】](https://syncer.jp/how-to-introduction-recaptcha)

## GithubPages
- [\<form\>－HTML5タグリファレンス](http://www.htmq.com/html5/form.shtml)

## GoogleAppEngine
- [URL Fetch Go API Overview - Go — Google Cloud Platform](https://cloud.google.com/appengine/docs/go/urlfetch/)
- [Mail Go API Overview - Go — Google Cloud Platform](https://cloud.google.com/appengine/docs/go/mail/)
- [Go言語とJSON](http://qiita.com/vvakame/items/6719b3c90dfaa8220e44)