Help us understand the problem. What is going on with this article?

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

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away