【Go】Gin でテンプレートファイルを使わずにhtmlを返したい(レスポンスメソッドのおさらいを兼ねて)

# はじめに
gin にはtemplateを使ったHTMLを返すメソッドは用意されていますが、
文字列をHTMLとして返すメソッドは用意されていません。

ですが
**APIを作っていてどうしても1ページだけwebページを作りたくなる状況ってありますよね！？**

つまり、わざわざtemplateをデプロイするの~~がめんどくさい~~に時間をかけたくない
バッドノウハウかもしれないけれど...

# そもそもGinのレスポンスって何が返せるの
はい、というわけで、まずはGinのレスポンスで何を返せるのかを見て行きましょう
*READMEより抜粋しています
https://github.com/gin-gonic/gin/blob/master/context.go

## JSON
言わずと知れたJSON
返せなかったら正気を疑う

```go:JSON
c.JSON(http.StatusOK, msg)
```
## XML
廃れつつあるXML。xmlのparseしなきゃいけない状況とか泣ける！
[一昔前の議論](http://www.publickey1.jp/blog/10/jsonxml.html)

```go:XML
c.XML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
```
## YAML
rails界隈ではよく使われているみたいですけれど、今の所使う予定はなし。
https://qiita.com/Yama-to/items/587544993fb62610528a

```go:YAML
c.YAML(http.StatusOK, gin.H{"message": "hey", "status": http.StatusOK})
```
## SecureJSON
調べるまで知らなかったけれど、
バグのせいで強制的にjsonを引っこ抜けることが昔あったらしく、その名残らしい。
IE6とか知らん(笑)
https://qiita.com/yuku_t/items/078eebf02bbbb45adc93

```go:SecureJson
	names := []string{"lena", "austin", "foo"}
	// Will output  :   while(1);["lena","austin","foo"]
	c.SecureJSON(http.StatusOK, names)
```

## IndentedJSON
こちらも調べるまでしらなかったけれど、デバッグ時にはこれで出力するのも良いかも。

```go:IndentedJSON
c.JSON(http.StatusOK, msg)
```
## String
単に文字列を返したい時に使う。

```go:String
test := "hoge"
c.String(200, "pong")
c.String(200, "%s", test)//みたいな書き方もできるらしい。
// 内部的にはfmt.Fprintf(w, format, data...)となるような使い方
// wはhttp.ResponseWriter
```
## HTML
HTMLのレンダリング機能。ただしファイルからしか読み込めない。。。
もちろんファイルを置かなければpanicです

```go:HTML
c.HTML(http.StatusOK, "index.tmpl", gin.H{
	"title": "Main website",
})
```
# 実装を眺める
ここでようやく本題です。結論から言えばcontext変数に値を入れてやれば終わりです。
contextを見て行きましょう。


```go:context.go

// Context is the most important part of gin. It allows us to pass variables between middleware,
// manage the flow, validate the JSON of a request and render a JSON response for example.
type Context struct {
	writermem responseWriter
	Request   *http.Request
	Writer    ResponseWriter

	Params   Params
	handlers HandlersChain
	index    int8

	engine *Engine

	// Keys is a key/value pair exclusively for the context of each request.
	Keys map[string]interface{}

	// Errors is a list of errors attached to all the handlers/middlewares who used this context.
	Errors errorMsgs

	// Accepted defines a list of manually accepted formats for content negotiation.
	Accepted []string
}
```
``` response_writer.go
type ResponseWriter interface {
	http.ResponseWriter
	http.Hijacker
	http.Flusher
	http.CloseNotifier

	// Returns the HTTP response status code of the current request.
	Status() int

	// Returns the number of bytes already written into the response http body.
	// See Written()
	Size() int

	// Writes the string into the response body.
	WriteString(string) (int, error)

	// Returns true if the response body was already written.
	Written() bool

	// Forces to write the http header (status code + headers).
	WriteHeaderNow()
}
func (w *responseWriter) WriteString(s string) (n int, err error) {
	w.WriteHeaderNow()
	n, err = io.WriteString(w.ResponseWriter, s)
	w.size += n
	return
}
```
よく見ると、
net/httpでレスポンスを書き込むを書き込むhttp.ResponseWriterが
Context.Writer.ResponseWiterにあるじゃないですか。
しかも御誂え向きのWriteStringが用意されてますね。

# 本題
というわけでコードを書いていきましょう

```go:main.go
package main

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

func main() {
	r := gin.Default()
	r.GET("/ping", func(c *gin.Context) {
		c.Writer.WriteString(`<!DOCTYPE html><html><body><input type="number"></body></html>`)
		//c.String(200, `<!DOCTYPE html><html><body><input type="number"></body></html>`)
	})
	r.Run() // listen and serve on 0.0.0.0:8080
}

```

これを実行して`http://127.0.0.1:8080/` にアクセスすると無事htmlとそのinput要素を表示することができました。
ちなみにコメントアウトしているc.Stringを実行すると文字列が虚しく表示されます。

# まとめ
c.Writer.WriteString(``)を使えばなんとかなる。
バッドノウハウの可能性がありますので、用法用量を守ってお使いください。