🐬

【GO】~ APIを叩く基本 標準パッケージnet/httpを使って ~

に公開

はじめに

今回はGOでAPIを叩く記事です!
フレームワークを使用せずに標準パッケージhttpを使用してAPIを叩きます!
シンプルなリクエストから、path parameter, query parameterを含むリクエストまで考えます!

準備

今回の環境

https://jsonplaceholder.typicode.com/
こちらのダミーAPIから、以下のGETメソッドのものを叩いてみます。

GET /posts(parameterなし)
"https://jsonplaceholder.typicode.com/posts"
GET /posts/1(path parameterあり)
"https://jsonplaceholder.typicode.com/posts/1"
GET /posts?userId=1(query parameterあり)
"https://jsonplaceholder.typicode.com/posts?userId=1"

便利ツール

https://mholt.github.io/json-to-go/
JSONをコピペすると、GOの構造体を生成してくれます。jsonタグもつけてくれます。
デモ

APIを叩く

基本の流れ

  • ベースURLの用意
  • エンドポイントの構築
  • リクエスト作成
  • (HTTPクライアントを使用して)リクエストの送信
  • レスポンスを受け取って中身を読む
  • JSONレスポンスを構造体にデコードする

parameterなしで叩く

GET /posts
"https://jsonplaceholder.typicode.com/posts"

http.GET関数とhttp.NewRequest関数の2つ方法があります。

【http.GET】

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

// 構造体の準備
type Post struct {
	UserID int    `json:"userId"`
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Body   string `json:"body"`
}

func main() {
	// ベースURLの用意
	baseURL := "https://jsonplaceholder.typicode.com/posts"

	// エンドポイントの構築
	endpoint, err := url.Parse(baseURL)
	if err != nil {
		panic(err)
	}

	// リクエスト作成 + 送信
	resp, err := http.Get(endpoint.String())
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	//レスポンスを受け取って中身を読む
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	//JSONレスポンスを構造体にデコードする
	var posts []Post
	if err := json.Unmarshal(body, &posts); err != nil {
		panic(err)
	}

	fmt.Println(posts)
}

【http.NewRequest】

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

// 構造体の準備
type Post struct {
	UserID int    `json:"userId"`
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Body   string `json:"body"`
}

func main() {
	// ベースURLの用意
	baseURL := "https://jsonplaceholder.typicode.com/posts"

	// エンドポイントの構築
	endpoint, err := url.Parse(baseURL)
	if err != nil {
		panic(err)
	}

	//リクエスト作成
	req, err := http.NewRequest("GET", endpoint.String(), nil)
	if err != nil {
		panic(err)
	}

	// HTTPクライアントを使用して送信
	var client *http.Client = &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	//レスポンスを受け取って中身を読む
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	//JSONレスポンスを構造体にデコードする
	var posts []Post
	if err := json.Unmarshal(body, &posts); err != nil {
		panic(err)
	}

	fmt.Println(posts)
}

path parameter で叩く

GET /posts/1
"https://jsonplaceholder.typicode.com/posts/1"

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

// 構造体の準備
type Post struct {
	UserID int    `json:"userId"`
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Body   string `json:"body"`
}

func main() {
	// ベースURLの用意
	baseURL := "https://jsonplaceholder.typicode.com/posts"
	id := "1"
	URL := fmt.Sprintf("%s/%s", baseURL, id)

	// エンドポイントの構築
	endpoint, err := url.Parse(URL)
	if err != nil {
		panic(err)
	}
	fmt.Println(endpoint.String())
	// https://jsonplaceholder.typicode.com/posts/1

	// リクエスト作成 + 送信
	resp, err := http.Get(endpoint.String())
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	//レスポンスを受け取って中身を読む
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	//JSONレスポンスを構造体にデコードする
	var posts Post
	if err := json.Unmarshal(body, &posts); err != nil {
		panic(err)
	}

	fmt.Println(posts)
}

query parameter で叩く

GET /posts?userId=1
"https://jsonplaceholder.typicode.com/posts?userId=1"

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
)

// 構造体の準備
type Post struct {
	UserID int    `json:"userId"`
	ID     int    `json:"id"`
	Title  string `json:"title"`
	Body   string `json:"body"`
}

func main() {
	// ベースURLの用意
	baseURL := "https://jsonplaceholder.typicode.com/posts"

	// エンドポイントの構築
	endpoint, err := url.Parse(baseURL)
	if err != nil {
		panic(err)
	}
	q := endpoint.Query()
	q.Set("userId", "1")
	endpoint.RawQuery = q.Encode()

	fmt.Println(endpoint.String())
	// https://jsonplaceholder.typicode.com/posts?userId=1

	// リクエスト作成 + 送信
	resp, err := http.Get(endpoint.String())
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	//レスポンスを受け取って中身を読む
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		panic(err)
	}

	//JSONレスポンスを構造体にデコードする
	var posts []Post
	if err := json.Unmarshal(body, &posts); err != nil {
		panic(err)
	}

	fmt.Println(posts)
}

最後に

  • http.NewRequestとhttp.GETはどっちがいいの?
    http.GETはシンプル、ただ柔軟性低い
    http.NewRequestは柔軟、ただ少し手間が増える
    今回はGETメゾットでAPIを叩ければ良かったので、http.GETの方を使用しています。ヘッダーをつけたり、GET以外のメソッドだとhttp.NewRequestの方を使用します。

今回の記事ではシンプルなAPIを叩きました。
今後はGETメソッド以外のメソッドやヘッダー付きリクエストなども実践していきます。

最後まで読んでいただきありがとうございました!

今回の調べごと・深掘りしたいこと

  • エンドポイントとは?
    APIの中の、特定の機能やデータにアクセスするためのURLのこと

参考文献

https://pkg.go.dev/net/http

Discussion