Edited at

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

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

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


前提条件

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


仕様

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

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



  • / -> ホームページですが、とりあえずテキストしかを見せない


  • /items/ -> Itemのリスト、Itemデータを全部見せる


  • /items/{id} -> 特定のItemの情報

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


開発プロセス

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

go get -u github.com/gorilla/mux

GitHubリポhttps://github.com/gorilla/mux

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

package main

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

"github.com/gorilla/mux"
)

すべての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という関数が実行されます。

そして、このコード:

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

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

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

go run main.go

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

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


サポート関数

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

import (

"encoding/json"
"fmt"
"log"
"net/http"
"strconv"

"github.com/gorilla/mux"
)

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

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

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の部分の下に、このコードを入れてください:

// Item representation

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

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

// 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)を書きます。

// Controller for the /items route

func returnAllItems(w http.ResponseWriter, r *http.Request) {
respondWithJson(w, http.StatusOK, itemList)
}

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

// 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をアクセスしたら、1idになります。それから、そのidは、indexとしてitemListという配列からデータを取ってJSONの形式で答えます。id1の場合は、二つ目のデータが取られます。そして、id0の場合は、一つ目のデータが取られます。

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


テスト

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

go run main.go

これで、localhost:8000/items に行くと、このデータが見えます:

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

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


ソースコード

問題がある場合は、ソースコードを参照してください。

https://gist.github.com/sbenemerito/bf8cdc720a41e2d2ce2cc2fd760bbbd5


まとめ

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

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

以上


参考リソース