TypeScriptでe-Stat APIのデータを取得する
TypeScriptでe-Stat APIのデータを取得する方法
e-Stat APIの概要
e-Stat APIは、日本の政府統計総合窓口(e-Stat)が提供する公式APIです。このAPIを使用することで、日本の様々な統計データに簡単にアクセスできます。主な特徴は以下の通りです:
-
豊富なデータセット:人口統計、経済指標、社会調査など、幅広い分野のデータが利用可能です。
-
リアルタイムデータ:最新の統計情報にアクセスできます。
-
カスタマイズ可能なクエリ:特定の地域、期間、カテゴリーなどでデータをフィルタリングできます。
-
JSON形式のレスポンス:プログラムで扱いやすいJSON形式でデータが提供されます。
-
アクセス制限:APIキーが必要で、1日あたりのリクエスト数に制限があります。
e-Stat APIを使用するには、まず利用登録を行い、APIキーを取得する必要があります。
コードの全体像
まず、完全なコードを見てみましょう:
import { HttpsProxyAgent } from 'https-proxy-agent'
import fetch from 'node-fetch'
import paramsSerializer from './modules/paramsSerializer'
import { EstatParamsType } from './types/params'
import { EStatResponseType } from './types/response'
const API_KEY = process.env.ESTAT_API_APPID
const BASE_URL = 'https://api.e-stat.go.jp/rest/3.0/app/json/getStatsData'
const PROXY_URL = process.env.HTTP_PROXY
const agent = PROXY_URL ? new HttpsProxyAgent(PROXY_URL) : undefined
function isValidEStatResponse(data: unknown): data is EStatResponseType {
return data && typeof data === 'object' && 'GET_STATS_DATA' in data
}
export async function fetchEstatAPI(
params: Omit<EstatParamsType, 'appId'>
): Promise<EStatResponseType> {
const queryParams: EstatParamsType = {
appId: API_KEY!,
...Object.fromEntries(
Object.entries(params).map(([key, value]) => [
key,
Array.isArray(value) ? value.join(',') : value,
])
),
} as EstatParamsType
const url = `${BASE_URL}?${paramsSerializer(queryParams)}`
try {
const response = await fetch(url, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
agent,
})
if (!response.ok) {
throw new Error(
`e-Stat APIリクエストが失敗しました: ${response.status} ${response.statusText}`
)
}
const data = await response.json()
if (!isValidEStatResponse(data)) {
throw new Error('e-Stat APIからの応答形式が無効です')
}
return data
} catch (error) {
console.error('e-Statデータの取得中にエラーが発生しました:', error)
throw new Error(
'e-Statデータの取得に失敗しました。詳細はコンソールを確認してください。'
)
}
}
1. 型定義
e-Stat APIを使用する際、適切な型定義は非常に重要です。以下に、すべての型定義を示します:
export interface EstatParamsType {
appId?: string
statsDataId: string
cdCat01: string | string[]
cdArea?: string | string[]
}
export interface ResultType {
STATUS: number
ERROR_MSG: string
DATE: string
}
export interface NarrowingCondType {
CODE_CAT01_SELECT: string
}
export interface ParameterType {
LANG: string
STATS_DATA_ID: string
NARROWING_COND: NarrowingCondType
DATA_FORMAT: string
START_POSITION: number
METAGET_FLG: string
}
export interface ResultInfType {
TOTAL_NUMBER: number
FROM_NUMBER: number
TO_NUMBER: number
}
export interface StatNameType {
code: string
text: string
}
export interface GovOrgType {
code: string
text: string
}
export interface MainCategoryType {
code: string
text: string
}
export interface SubCategoryType {
code: string
text: string
}
export interface StatisticsNameSpecType {
TABULATION_CATEGORY: string
TABULATION_SUB_CATEGORY1: string
}
export interface TitleSpecType {
TABLE_NAME: string
}
export interface TableInfType {
id: string
STAT_NAME: StatNameType
GOV_ORG: GovOrgType
STATISTICS_NAME: string
TITLE: string | Record<string, unknown>
CYCLE: string
SURVEY_DATE: number
OPEN_DATE: string
SMALL_AREA: number
MAIN_CATEGORY: MainCategoryType
SUB_CATEGORY: SubCategoryType
OVERALL_TOTAL_NUMBER: number
UPDATED_DATE: string
STATISTICS_NAME_SPEC: StatisticsNameSpecType
TITLE_SPEC: TitleSpecType
}
export interface ClassType {
code: string
name: string
level: string
unit: string
}
export interface ClassObjType {
id: string
name: string
CLASS: ClassType | ClassType[]
}
export interface ClassInfType {
CLASS_OBJ: ClassObjType[]
}
export interface NoteType {
char: string
text: string
}
export interface ValueType {
tab: string
cat01: string
area: string
time: string
unit: string
text: string
}
export interface DataInfType {
NOTE: NoteType[]
VALUE: ValueType[]
}
export interface StatisticalDataType {
RESULT_INF: ResultInfType
TABLE_INF: TableInfType
CLASS_INF: ClassInfType
DATA_INF: DataInfType
}
export interface GetStatsDataType {
RESULT: ResultType
PARAMETER: ParameterType
STATISTICAL_DATA: StatisticalDataType
}
export interface EStatResponseType {
GET_STATS_DATA: GetStatsDataType
}
これらの型定義により、APIリクエストのパラメータ(EstatParamsType
)とレスポンス(EStatResponseType
)の構造が明確になります。また、StatisticalDataType
のような中間の型定義により、レスポンスデータの詳細な構造も把握できます。
型定義を使用することで、以下のメリットがあります:
- コード補完: IDEが適切なプロパティを提案してくれます。
- 型チェック: コンパイル時にエラーを検出できます。
- ドキュメンテーション: コードの理解が容易になります。
2. 必要なモジュールのインポート
import { HttpsProxyAgent } from 'https-proxy-agent'
import fetch from 'node-fetch'
import paramsSerializer from './modules/paramsSerializer'
import { EstatParamsType } from './types/params'
import { EStatResponseType } from './types/response'
ここでは、必要なモジュールとカスタム型をインポートしています。HttpsProxyAgent
はプロキシ接続のため、fetch
はHTTPリクエスト用、paramsSerializer
はクエリパラメータの変換用です。また、EstatParamsType
とEStatResponseType
はAPIのパラメータとレスポンスの型定義です。
3. 定数の設定
const API_KEY = process.env.ESTAT_API_APPID
const BASE_URL = 'https://api.e-stat.go.jp/rest/3.0/app/json/getStatsData'
const PROXY_URL = process.env.HTTP_PROXY
const agent = PROXY_URL ? new HttpsProxyAgent(PROXY_URL) : undefined
ここでは、API認証キー、ベースURL、プロキシURL(必要な場合)を設定しています。環境変数を使用することで、セキュリティを確保しつつ、柔軟な設定が可能になります。
4. レスポンス検証関数
function isValidEStatResponse(data: unknown): data is EStatResponseType {
return data && typeof data === 'object' && 'GET_STATS_DATA' in data
}
この関数は、APIからのレスポンスが期待される形式かどうかを検証します。型ガードとして機能し、TypeScriptの型安全性を強化します。
5. メインのAPI取得関数
export async function fetchEstatAPI(
params: Omit<EstatParamsType, 'appId'>
): Promise<EStatResponseType> {
// ... (実装詳細)
}
この関数が、実際にAPIからデータを取得する中心的な部分です。非同期関数として実装され、プロミスを返します。
6. クエリパラメータの構築
const queryParams: EstatParamsType = {
appId: API_KEY!,
...Object.fromEntries(
Object.entries(params).map(([key, value]) => [
key,
Array.isArray(value) ? value.join(',') : value,
])
),
} as EstatParamsType
ここでは、APIに送信するクエリパラメータを構築しています。配列パラメータはカンマ区切りの文字列に変換されます。
7. APIリクエストの実行
const url = `${BASE_URL}?${paramsSerializer(queryParams)}`
const response = await fetch(url, {
method: 'GET',
headers: { 'Content-Type': 'application/json' },
agent,
})
構築したURLを使用してAPIリクエストを実行します。プロキシが設定されている場合は、agent
を使用します。
8. エラーハンドリングとレスポンス処理
if (!response.ok) {
throw new Error(
`e-Stat APIリクエストが失敗しました: ${response.status} ${response.statusText}`
)
}
const data = await response.json()
if (!isValidEStatResponse(data)) {
throw new Error('e-Stat APIからの応答形式が無効です')
}
return data
レスポンスのステータスコードとデータ形式を確認し、エラーがあれば例外をスローします。正常なレスポンスの場合、データを返します。
EstatParamsType の詳細
EstatParamsType
はe-Stat APIへのリクエストパラメータを定義するインターフェースです。主要なプロパティは以下の通りです:
export interface EstatParamsType {
appId?: string
statsDataId: string
cdCat01: string | string[]
cdArea?: string | string[]
}
-
appId
: APIキー。通常は環境変数から取得します。 -
statsDataId
: 取得したい統計データのID。e-Statのウェブサイトで確認できます。 -
cdCat01
: データのカテゴリコード。単一の文字列または文字列の配列で指定できます。 -
cdArea
: 地域コード。オプションで、単一の文字列または文字列の配列で指定できます。
この型定義により、APIリクエストを作成する際に必要なパラメータを明確に把握でき、誤ったパラメータ名の使用や必須パラメータの欠落を防ぐことができます。
使用例:
const params: Omit<EstatParamsType, 'appId'> = {
statsDataId: '0003348423',
cdCat01: ['A1100', 'A1200'],
cdArea: '13000'
};
EStatResponseType の詳細
EStatResponseType
はe-Stat APIからのレスポンスの構造を定義するインターフェースです。この型は複雑な入れ子構造を持っています:
export interface EStatResponseType {
GET_STATS_DATA: GetStatsDataType
}
export interface GetStatsDataType {
RESULT: ResultType
PARAMETER: ParameterType
STATISTICAL_DATA: StatisticalDataType
}
主要な部分を詳しく見ていきます:
-
RESULT
: APIリクエストの結果情報export interface ResultType { STATUS: number ERROR_MSG: string DATE: string }
-
STATUS
: リクエストの状態コード -
ERROR_MSG
: エラーがある場合のメッセージ -
DATE
: レスポンスの日付
-
-
PARAMETER
: リクエストで使用されたパラメータの情報export interface ParameterType { LANG: string STATS_DATA_ID: string NARROWING_COND: NarrowingCondType DATA_FORMAT: string START_POSITION: number METAGET_FLG: string }
-
STATISTICAL_DATA
: 実際の統計データexport interface StatisticalDataType { RESULT_INF: ResultInfType TABLE_INF: TableInfType CLASS_INF: ClassInfType DATA_INF: DataInfType }
-
RESULT_INF
: データの結果情報(総数、範囲など) -
TABLE_INF
: テーブル情報(統計名、作成機関など) -
CLASS_INF
: データの分類情報 -
DATA_INF
: 実際の統計値データ
-
この詳細な型定義により、レスポンスデータの構造を正確に把握し、型安全な方法でデータにアクセスできます。また、IDEの自動補完機能を最大限に活用できるため、開発効率が向上します。
使用例:
function processResponse(response: EStatResponseType) {
const status = response.GET_STATS_DATA.RESULT.STATUS;
if (status !== 0) {
console.error(`Error: ${response.GET_STATS_DATA.RESULT.ERROR_MSG}`);
return;
}
const data = response.GET_STATS_DATA.STATISTICAL_DATA.DATA_INF
Discussion