42
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

Goで超簡単API

概要

Goを使用してCRUDを行える簡単なAPIを作成します。(DBは使用しません。)

前提条件・設定

  1. Goの開発環境が整っている事を前提としています。
  2. ルートを設定する為にgorilla/muxを使用するのでインストールを行います。
go get -u github.com/gorilla/mux

手順

  1. 開発準備
  2. ルート(エンドポイント)の設定
  3. モデルの作成
  4. モックデータの作成
  5. CRUDの設定
  6. 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()の上に作成します。
titleauthorの情報を持つBookfirstnamelastnameを持つ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

関数を完成させる為に必要ないくつかのpackageimportします。

  • 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つのデータを取得する事ができました。

image.png

Get(http://localhost:8000/api/books/:id)

今度はidで指定して必要なデータのみを取得します。

image.png

POST (http://localhost:8000/api/books)

次にデータを作成してみましょう。
PostリクエストなのでURLを入力する右側の選択肢をGetからPostに変更し、json形式のデータを渡します。

image.png

PUT(http://localhost:8000/api/books/:id)

次は一度登録したデータをUpdate(更新)してみましょう。
URL右の選択肢をPUTに変更。

image.png

DELETE(http://localhost:8000/api/books/:id)

最後に一度登録したデータをDestroy(削除)してみましょう。
URL右の選択肢をDELETEに変更。

image.png

Register as a new user and use Qiita more conveniently

  1. You can follow users and tags
  2. you can stock useful information
  3. You can make editorial suggestions for articles
What you can do with signing up
42
Help us understand the problem. What are the problem?