tomato diary

Golang で Web API を扱う方法

06 Jul 2019 -

概要

コード

総務省の無線局等情報検索APIについては、Web-API機能(無線局等情報検索)についてをご覧ください。

総務省の無線局等情報検索APIは、https://www.tele.soumu.go.jp/musen/list?ST=1&OF=2&OW=AT&DA=1&SC=1&DC=1のようなリクエストを送ると、下記のようなJSONを取得できます。 この場合は、アマチュア無線局について検索結果の1件目から500件分の詳細情報をJSON形式で送ってくださいという意味のリクエストになります。

{
	"musen": [{
		"detailInfo": {
			"radioSpec1": "A1A\\t435.795 MHz\\t1   W\\nG1D\\t435.91 MHz\\t1   W\\n20K0F1D\\t435.91 MHz\\t1   W\\n20K0F3E\\t435.91 MHz\\t1   W\\nA1A\\t435.795 MHz から        435.9 MHz まで\\t1   W\\nJ3E\\t435.795 MHz から        435.9 MHz まで\\t1   W",
			"radioStationPurpose": "アマチュア業務用",
			"note": "",
			"permittedOperatingHours": "常 時",
			"address": "*****",
			"licenseDate": "2016-08-19",
			"broadcastMatter": "",
			"commMatter": "アマチュア業務に関する事項",
			"office": "",
			"validTerms": "2021-08-18まで",
			"commPartner": "アマチュア局",
			"startingLimit": "",
			"broadcastDistrict": "",
			"workPersonName": "",
			"identificationSignals": "8J1JCS      ",
			"radioStationNumber": "",
			"radioStationCategory": "アマチュア局",
			"movementArea": "",
			"radioEuipmentLocation": "軌道傾斜角 98度\\n軌道周期  110分\\n遠地点高度 1,705km\\n近地点高度 805km\\n軌道の種類 円軌道極軌道",
			"licenseNumber": "*****",
			"name": "一般社団法人日本アマチュア無線連盟"
		},
		"listInfo": {
			"name": "一般社団法人日本アマチュア無線連盟(8J1JCS)",
			"radioStationPurpose": "アマチュア業務用",
			"tdfkCd": " ",
			"no": "1",
			"licenseDate": "2016-08-19"
		}
	}, {
            ...
            ...
            省略
            ...
            ...
		}
	}],
	"musenInformation": {
		"totalCount": "408919",
		"lastUpdateDate": "2019-07-05"
	}
}

これをJSON-to-Go を使って、Golangの構造体に変換します。 生成直後は、構造体の名前が AutoGenerated となっているので、適当な名前に変更します。 ここでは、無線局詳細情報のリストを表しているので、radioListsとしました。

// json struct
// generated by this site:  
type radioLists struct {
	Musen []struct {
		DetailInfo struct {
			RadioSpec1              string `json:"radioSpec1"`
            ...                     ...
            省略
            ...                     ...
		} `json:"detailInfo"`
		ListInfo struct {
			Name                string `json:"name"`
			RadioStationPurpose string `json:"radioStationPurpose"`
			TdfkCd              string `json:"tdfkCd"`
			No                  string `json:"no"`
			LicenseDate         string `json:"licenseDate"`
		} `json:"listInfo"`
	} `json:"musen"`
	MusenInformation struct {
		TotalCount     string `json:"totalCount"`
		LastUpdateDate string `json:"lastUpdateDate"`
	} `json:"musenInformation"`
}

次に、APIにリクエストを投げて、構造体を返してくれる関数を書きます。

// get list of radio
// sc is start count
// sc番目から最大500件のデータを取得します。
func requestList(sc int) (*radioLists, error) {
    // Options
	st := 1    // 免許状の情報
	of := 2    // json format
	ow := "AT" // amateur radio
	da := 1    // request details
	dc := 2    // Number of acquisitions
	url := fmt.Sprintf("https://www.tele.soumu.go.jp/musen/list?ST=%d&OF=%d&OW=%s&DA=%d&SC=%d&DC=%d", st, of, ow, da, sc, dc)

	// get web api response
	resp, err := http.Get(url)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// check HTTP status code
	if 300 <= resp.StatusCode && resp.StatusCode < 200 {
		return nil, errors.New("request faild")
	}

	// decode response data 
	var data *radioLists
	err = json.NewDecoder(resp.Body).Decode(&data)
	if err != nil {
		return nil, err
	}

	return data, nil
}
url := fmt.Sprintf("https://www.tele.soumu.go.jp/musen/list?ST=%d&OF=%d&OW=%s&DA=%d&SC=%d&DC=%d", st, of, ow, da, sc, dc)

初めに、fmt.Sprintf()を使い、リクエストを組み立てurlに代入します。 オプションを後々変更することを考えて、変数に一度代入してから、fmt.Sprintfで結合しています。 そのURLを使用して、http.Get()でレスポンスを得ます。 実際には、HTTPのステータスコードをチェックして、対応した処理を行う必要があるのですが、 簡単にするために、200番台なら続行、それ以外の場合はすべてエラーとしています。

得られたレスポンスボディを下記のコードでパースして終了! めちゃくちゃ簡単。

// decode response data by json format
var data *radioLists
err = json.NewDecoder(resp.Body).Decode(&data)
if err != nil {
    return nil, err
}

このrequestList関数は、引数に何件目から取得するかを指定して呼び出します。 下のような感じで使います。

lists, err := requestList(1)
if err != nil {
    fmt.Println(err)
}

あとは、得られたJSONを表す構造体を使えばいろいろと遊べます。 すべての無線局の情報について、取得したい場合は、検索結果の総件数を超えるまで requestList() を引数を変えながら呼び出すことでできます。 総件数は、requestList() で得られる構造体に含まれているのでそれを利用します。

ただし、その際はサーバに負荷を掛けすぎないように行ってください。