golangでシンプルなRESTful APIを作ってみよう！

Webからエンタープライズアプリケーションまで、RESTfulというアーキテクチャーが使われています。ステートレス設計として、別々のソフトウェアコンポーネント間の通信を提供する強力な方法であります。 Web開発者として、RESTful APIを作るために、主にPythonを使いますが、最近Goプログラミング言語に出会い、興味を持ってきました。Goプログラミング言語（golangでも呼ばれる）は、Googleのプロジェクトで、マイクロサービスアーキテクチャに適当な多くの機能も提供するので、人気が増えています。

本記事、golangを使ってシンプルなRESTful APIをどう作るか説明したいと思います。

# 前提条件
このチュートリアルがゼロからじゃなくて、前提として読者がこの三つのポイントが持っています：

* プログラミングの経験や知識があること
* [RESTful APIに関して理解](https://qiita.com/masato44gm/items/dffb8281536ad321fb08)
* [Golang（^1.12.1）がインストールされていること](https://golang.org/dl/)

# 仕様
RESTful APIは、通常CRUDができます。CRUDとは、データベースの四つの主要な機能、「作成（Create）」「読み出し（Read）」「更新（Update）」「削除（Delete）」ですが、今回は、簡単にするために、読み出しの機能しか作りません。そして、データがJSONの形式で書きます。

そして、このエンドポイントがあります：

* __/__ -> ホームページですが、とりあえずテキストしかを見せない
* __/items/__ -> Itemのリスト、Itemデータを全部見せる
* __/items/*{id}*__ -> 特定のItemの情報

それぞれのItemは、「title」と「description」のデータがあって、簡単にするために、データベースを使用するのではなく、データを事前に定義します。

# 開発プロセス
最初は、必要なパッケージをインストールします。ルーティングのために、Muxというパッケージを使っていきます。CMD / Terminalを開けて、このコマンドを実行してください：

```bash
go get -u github.com/gorilla/mux
```

__GitHubリポ__：https://github.com/gorilla/mux

その後、`main.go`というファイルを作成して、このコードを入れてください：

```golang
package main

import (
	"fmt"
	"log"
	"net/http"

	"github.com/gorilla/mux"
)
```

すべてのgolangを使って作られたプログラムがパッケージで構成されています。この部分では、何のパッケージが必要かが書いてあります。この場合には、四つのパッケージが必要です。

## ルーティング
同じファイルで、さっきの書いたコードの下に、このコードを入れてください：

```golang
// Controller for the / route (home)
func homePage(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "This is the home page. Welcome!")
}

// Controller for the /items route
func returnAllItems(w http.ResponseWriter, r *http.Request) {
	// Code for returning all items here
}

// Controller for the /items/{id} route
func returnSingleItem(w http.ResponseWriter, r *http.Request) {
	// Code for returning a single item here
}

func handleRequests() {
	myRouter := mux.NewRouter().StrictSlash(true)
	myRouter.HandleFunc("/", homePage)
	myRouter.HandleFunc("/items", returnAllItems)
	myRouter.HandleFunc("/items/{id}", returnSingleItem)
	log.Fatal(http.ListenAndServe(":8000", myRouter))
}

func main() {
	handleRequests()
}
```

`main()`という関数は、このプログラムをスタートすると、自動的に実行されます。その中に、`handleRequests()`という関数が実行されます。`handleRequests()`の関数で、それぞれのエンドポイントがアクセスされると、何が起こるかが書いてあります。例えば、`/`のエンドポイントがアクセスされると、`homePage`という関数が実行されるとか、`/items`のエンドポイントがアクセスされると、`returnAllItems`という関数が実行されます。

そして、このコード：

```golang
log.Fatal(http.ListenAndServe(":8000", myRouter))
```

の意味は、このプログラムが`8000`のポートで、アクセスできます。これで、もう使えるなので、スタートしてみましょう！

CMD / Terminal で、このコマンドを実行してください：

```bash
go run main.go
```

ウェブブラウザ（Google Chrome、Mozilla Firefoxなど）を開けて、`localhost:8000`に行くと、このテキストが見えます：

![image.png](https://qiita-image-store.s3.amazonaws.com/0/300933/ab370378-4f99-25cb-efa7-125802c452b7.png)

`homePage()`の関数で、このテキストが見えます。でも、`/items`に行くと、何もが見えません。原因は、他の関数（特にreturnAllItems）がまだ何もしません。

## サポート関数

これから、二つのパッケージが必要なので、インポートしましょう。最初のimport部分をこれに変更してください：

```golang
import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
)
```

`encoding/json`と`strconv`というパッケージを追加しました。もうすぐこの二つを使います。

それから、二つのサポート関数を書きましょう：

```golang
func respondWithError(w http.ResponseWriter, code int, msg string) {
	respondWithJson(w, code, map[string]string{"error": msg})
}

func respondWithJson(w http.ResponseWriter, code int, payload interface{}) {
	response, _ := json.Marshal(payload)
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)
	w.Write(response)
}
```

両方の関数は、JSONの形式でHTTP requestに答える役割があります。

## Itemデータ構造

Itemのデータ構造を書きましょう。importの部分の下に、このコードを入れてください：

```golang
// Item representation
type Item struct {
	Title   string `json:"title"`
	Description    string `json:"description"`
}
```

仕様に基づいて、それぞれのItemは、「title」と「description」のデータがあります。そして、その下に、これを入れて下さい：

```golang
// Global, static list of items
var itemList = []Item{
	Item{Title: "Item A", Description: "The first item"},
	Item{Title: "Item B", Description: "The second item"},
}
```

今回は、データベースを使わないので、これでデータを事前に定義します。二つのItemだけ書きましたが、自由にいくつでもいいですよ。

## コア関数

最後に、コア関数（returnAllItemsとreturnSingleItem）を書きます。

```golang
// Controller for the /items route
func returnAllItems(w http.ResponseWriter, r *http.Request) {
	respondWithJson(w, http.StatusOK, itemList)
}
```

基本的に、`/items`のエンドポイントをアクセスすると、`returnAllItems()`という関数がすべてのItemをJSONの形式で答えます。

```golang
// Controller for the /items/{id} route
func returnSingleItem(w http.ResponseWriter, r *http.Request) {
	// Get query parameters using Mux
	vars := mux.Vars(r)

	// Convert {id} parameter from string to int
	key, err := strconv.Atoi(vars["id"])

	// If {id} parameter is not valid int
	if err != nil {
		respondWithError(w, http.StatusBadRequest, "Invalid request payload")
		return
	}
	
	// If Item with ID of {id} does not exist
 	if key >= len(itemList) {
 		respondWithError(w, http.StatusNotFound, "Item does not exist")
 		return
 	}

 	respondWithJson(w, http.StatusOK, itemList[key])
}
```

そして、`returnSingleItem()`という関数が、`id`のURLパラメーターに基づいて特定のItemの情報をJSONの形式で答えます。

例えば、`localhost:8000/items/1`をアクセスしたら、`1`が__id__になります。それから、その__id__は、indexとして`itemList`という配列からデータを取ってJSONの形式で答えます。__id__は`1`の場合は、二つ目のデータが取られます。そして、__id__は`0`の場合は、一つ目のデータが取られます。

__id__は、数だけであるべきであり、Itemの数以上になってはいけないので、二つのチェックを書きました。これで、終わりです。作ってみましょう！

# テスト

CMD / Terminal で、さっきのrunを閉じて、もう一回実行してください：

```bash
go run main.go
```

これで、`localhost:8000/items` に行くと、このデータが見えます：
![image.png](https://qiita-image-store.s3.amazonaws.com/0/300933/6b72a9f7-81d5-295b-2765-7437a27eec23.png)

`localhost:8000/items/0`や`localhost:8000/items/1`も使えますが、間違えの__id__を入れたら、エラーが出て来ます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/300933/a6769d24-bb89-261c-8005-70094bbc8f0c.png)

PostmanでもJavascript clientでも、このRESTful APIをアクセスできます。

# ソースコード

問題がある場合は、ソースコードを参照してください。
https://gist.github.com/sbenemerito/bf8cdc720a41e2d2ce2cc2fd760bbbd5

# まとめ

今回は、簡単にするために、すごくシンプルなRESTful APIを作りましたが、これでgolangでRESTful APIを作成がどれほど簡単かを見えます。もちろん実際のプロジェクトでは、実勢の値を返すために、データベースにコネクトします。

このプロジェクトを続けることに興味があったら、次のステップはCRUDの機能をするとか、データベースにコネクトすることです。

以上

# 参考リソース

* [0からREST APIについて調べてみた](https://qiita.com/masato44gm/items/dffb8281536ad321fb08)
* [Go Programming Language - Documentation](https://golang.org/doc/)
* [Build a RESTful API in Go and MongoDB](https://hackernoon.com/build-restful-api-in-go-and-mongodb-5e7f2ec4be94)
* [Why Golang is the fastest growing language on GitHub](https://hub.packtpub.com/why-golan-is-the-fastest-growing-language-on-github/)