概要
Goを使用してCRUDを行える簡単なAPIを作成します。(DBは使用しません。)
前提条件・設定
- Goの開発環境が整っている事を前提としています。
- ルートを設定する為にgorilla/muxを使用するのでインストールを行います。
go get -u github.com/gorilla/mux
手順
- 開発準備
- ルート(エンドポイント)の設定
- モデルの作成
- モックデータの作成
- CRUDの設定
- postmanを使用して動作確認
開発準備
API用のディレクトリを作成し、main.go
ファイルの作成を行います。
$ mkdir goApi
$ cd goApi
$ touch main.go
ルート(エンドポイント)の設定
先ほどインストールしたgorilla/mux
を使用して以下のようにルート(エンドポイント)を設定します。
package main
import (
"github.com/gorilla/mux"
"log"
)
func main() {
// ルーターのイニシャライズ
r := mux.NewRouter()
// ルート(エンドポイント)
r.HandleFunc("/api/books", getBooks).Methods("GET")
r.HandleFunc("/api/books/{id}", getBook).Methods("GET")
r.HandleFunc("/api/books", createBook).Methods("POST")
r.HandleFunc("/api/books/{id}", updateBook).Methods("PUT")
r.HandleFunc("/api/books/{id}", deleteBook).Methods("DELETE")
log.Fatal(http.ListenAndServe(":8000", r))
}
モデルの作成
データの型となるモデル(struct)をfunc main()
の上に作成します。
title
とauthor
の情報を持つBook
とfirstname
とlastname
を持つAuthor
を作成します。
package main
import (
/*省略*/
)
type Book struct {
ID string `json:"id"`
Title string `json:"title"`
Author *Author `json:"author"`
}
type Author struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
func main() {
/*省略*/
}
モックデータの作成
データの型となるモデルをもとにAPIの動作確認用のモックデータを作成します。
package main
import (
/*省略*/
)
type Book struct {
/*省略*/
}
type Author struct {
/*省略*/
}
// Bookのデータを保持するスライスの作成
var books []Book
func main() {
// ルーターのイニシャライズ
/*省略*/
// モックデータの作成
books = append(books, Book{ID: "1", Title: "Book one", Author: &Author{FirstName: "Philip", LastName: "Williams"}})
books = append(books, Book{ID: "2", Title: "Book Two", Author: &Author{FirstName: "John", LastName: "Johnson"}})
// ルート(エンドポイント)
/*省略*/
}
CRUDの設定
以下の関数を設定していきます。
-
getBooks()
: 全ての本を取得する。 -
getBook()
: 特定の本を取得する。 -
createBook()
: 新しい本を作成する。 -
updateBook()
: 特定の本の情報を更新する。 -
deleteBook()
: 特定の本を削除する。
// Get All Books
func getBooks(w http.ResponseWriter, r *http.Request) {
}
// Get Single Book
func getBook(w http.ResponseWriter, r *http.Request) {
}
// Create a Book
func createBook(w http.ResponseWriter, r *http.Request) {
}
// Update a Book
func updateBook(w http.ResponseWriter, r *http.Request) {
}
// Delete a Book
func deleteBook(w http.ResponseWriter, r *http.Request) {\
}
packageのimport
関数を完成させる為に必要ないくつかのpackage
をimport
します。
- jsonデータを作成、取得する為に
encoding/json
- ランダムなidを作成する為に
math/rand
- 作成したidを
string
型に変更する為にstrconv
- http通信を可能にする為に
net/http
package main
import (
"encoding/json"
"github.com/gorilla/mux"
"log"
"math/rand"
"net/http"
"strconv"
)
/*省略*/
関数の作成
ここでの詳細の説明は省略しますが、他言語でAPIを作成する際に用いるCRUDの関数の構造と特に大き違いはないかと思います。
package main
import (
"encoding/json"
"github.com/gorilla/mux"
"log"
"math/rand"
"net/http"
"strconv"
)
// Book Struct (Model)
type Book struct {
/*省略*/
}
type Author struct {
/*省略*/
}
// Init Books var as a slice Book struct
var books []Book
// Get All Books
func getBooks(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(books)
}
// Get Single Book
func getBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
// Loop through books and find with id
for _, item := range books {
if item.ID == params["id"] {
json.NewEncoder(w).Encode(item)
return
}
}
json.NewEncoder(w).Encode(&Book{})
}
// Create a Book
func createBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var book Book
_ = json.NewDecoder(r.Body).Decode(&book)
book.ID = strconv.Itoa(rand.Intn(10000)) // Mock ID - not safe in production
books = append(books, book)
json.NewEncoder(w).Encode(book)
}
// Update a Book
func updateBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for index, item := range books {
if item.ID == params["id"] {
books = append(books[:index], books[index+1:]...)
var book Book
_ = json.NewDecoder(r.Body).Decode(&book)
book.ID = params["id"]
books = append(books, book)
json.NewEncoder(w).Encode(book)
return
}
}
json.NewEncoder(w).Encode(books)
}
// Delete a Book
func deleteBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for index, item := range books {
if item.ID == params["id"] {
books = append(books[:index], books[index+1:]...)
break
}
}
json.NewEncoder(w).Encode(books)
}
func main() {
/*省略*/
}
最後の動作確認に移る前にここまでのmain.go
のコードは以下です。
package main
import (
"encoding/json"
"github.com/gorilla/mux"
"log"
"math/rand"
"net/http"
"strconv"
)
// Book Struct (Model)
type Book struct {
ID string `json:"id"`
Title string `json:"title"`
Author *Author `json:"author"`
}
type Author struct {
FirstName string `json:"firstname"`
LastName string `json:"lastname"`
}
// Init Books var as a slice Book struct
var books []Book
// Get All Books
func getBooks(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(books)
}
// Get Single Book
func getBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
// Loop through books and find with id
for _, item := range books {
if item.ID == params["id"] {
json.NewEncoder(w).Encode(item)
return
}
}
json.NewEncoder(w).Encode(&Book{})
}
// Create a Book
func createBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
var book Book
_ = json.NewDecoder(r.Body).Decode(&book)
book.ID = strconv.Itoa(rand.Intn(10000)) // Mock ID - not safe in production
books = append(books, book)
json.NewEncoder(w).Encode(book)
}
// Update a Book
func updateBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for index, item := range books {
if item.ID == params["id"] {
books = append(books[:index], books[index+1:]...)
var book Book
_ = json.NewDecoder(r.Body).Decode(&book)
book.ID = params["id"]
books = append(books, book)
json.NewEncoder(w).Encode(book)
return
}
}
json.NewEncoder(w).Encode(books)
}
// Delete a Book
func deleteBook(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
params := mux.Vars(r)
for index, item := range books {
if item.ID == params["id"] {
books = append(books[:index], books[index+1:]...)
break
}
}
json.NewEncoder(w).Encode(books)
}
func main() {
// Initiate Router
r := mux.NewRouter()
// Mock Data
books = append(books, Book{ID: "1", Title: "Book one", Author: &Author{FirstName: "Philip", LastName: "Williams"}})
books = append(books, Book{ID: "2", Title: "Book Two", Author: &Author{FirstName: "John", LastName: "Johnson"}})
// Route Hnadlers / Endpoints
r.HandleFunc("/api/books", getBooks).Methods("GET")
r.HandleFunc("/api/books/{id}", getBook).Methods("GET")
r.HandleFunc("/api/books", createBook).Methods("POST")
r.HandleFunc("/api/books/{id}", updateBook).Methods("PUT")
r.HandleFunc("/api/books/{id}", deleteBook).Methods("DELETE")
log.Fatal(http.ListenAndServe(":8000", r))
}
postmanを使用して動作確認
動作を確認する為にmain.go
を実行し、postmanを開きます。
$ go run main.go
Get(http://localhost:8000/api/books)
モックデータとして作成した2つのデータを取得する事ができました。
Get(http://localhost:8000/api/books/:id)
今度はid
で指定して必要なデータのみを取得します。
POST (http://localhost:8000/api/books)
次にデータを作成してみましょう。
Post
リクエストなのでURLを入力する右側の選択肢をGet
からPost
に変更し、json形式のデータを渡します。
PUT(http://localhost:8000/api/books/:id)
次は一度登録したデータをUpdate(更新)
してみましょう。
URL右の選択肢をPUT
に変更。
DELETE(http://localhost:8000/api/books/:id)
最後に一度登録したデータをDestroy(削除)
してみましょう。
URL右の選択肢をDELETE
に変更。