UNPKG

kokkai

Version:

A TypeScript client for the Kokkai API, providing access to Japanese Diet data.

133 lines (132 loc) 5.39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.KokkaiClient = void 0; const axios_1 = require("axios"); const errors_1 = require("./errors"); const DEFAULT_BASE_URL = 'https://kokkai.ndl.go.jp/api'; const DEFAULT_TIMEOUT = 10000; // 10 seconds const DEFAULT_REQUEST_INTERVAL = 3000; // 3 seconds class KokkaiClient { constructor(options = {}) { this.lastRequestTime = 0; const { baseURL = DEFAULT_BASE_URL, timeout = DEFAULT_TIMEOUT, requestInterval = DEFAULT_REQUEST_INTERVAL, userAgent, headers = {}, } = options; this.requestInterval = requestInterval; const axiosConfig = { baseURL, timeout, headers: { 'Accept': 'application/json', ...(userAgent && { 'User-Agent': userAgent }), ...headers, }, }; this.httpClient = axios_1.default.create(axiosConfig); } /** * 会議単位簡易出力 API (/meeting_list) * @param params 検索パラメータ * @returns 会議録情報のリスト */ async getMeetingList(params) { const apiParams = this.applyDefaultParams(params, 30, 100); this.validateCommonParams(apiParams); return this.request('/meeting_list', apiParams); } /** * 会議単位出力 API (/meeting) * @param params 検索パラメータ * @returns 会議録情報と全発言のリスト */ async getMeeting(params) { const apiParams = this.applyDefaultParams(params, 3, 10); this.validateCommonParams(apiParams); return this.request('/meeting', apiParams); } /** * 発言単位出力 API (/speech) * @param params 検索パラメータ * @returns 発言情報のリスト */ async getSpeech(params) { const apiParams = this.applyDefaultParams(params, 30, 100); this.validateCommonParams(apiParams); return this.request('/speech', apiParams); } async request(endpoint, params) { await this.enforceRateLimit(); const queryParams = this.serializeParams(params); try { const response = await this.httpClient.get(endpoint, { params: queryParams }); const responseData = response.data; if (this.isErrorResponse(responseData)) { throw new errors_1.KokkaiError(responseData.message, undefined, responseData.details); } return responseData; } catch (error) { throw (0, errors_1.handleApiError)(error); } } async enforceRateLimit() { const now = Date.now(); const timeSinceLastRequest = now - this.lastRequestTime; const waitTime = this.requestInterval - timeSinceLastRequest; if (waitTime > 0) { await new Promise(resolve => setTimeout(resolve, waitTime)); } this.lastRequestTime = Date.now(); } validateCommonParams(params) { if (params.startRecord !== undefined && params.startRecord < 1) { throw new errors_1.KokkaiError('startRecord must be 1 or greater.', 'ValidationError'); } if (params.from) this.validateDateFormat(params.from, 'from'); if (params.until) this.validateDateFormat(params.until, 'until'); this.validateDateRange(params.from, params.until); const hasSearchCondition = [ params.nameOfHouse, params.nameOfMeeting, params.any, params.speaker, params.from, params.until, params.speechNumber, params.speakerPosition, params.speakerGroup, params.speakerRole, params.speechID, params.issueID, params.sessionFrom, params.sessionTo, params.issueFrom, params.issueTo ].some(p => p !== undefined && p !== null && p !== ''); if (!hasSearchCondition) { throw new errors_1.KokkaiError('At least one search condition parameter is required.', 'ValidationError', ['19007']); } } validateDateFormat(date, fieldName) { const dateRegex = /^\d{4}-\d{2}-\d{2}$/; if (!dateRegex.test(date)) { throw new errors_1.KokkaiError(`"${fieldName}" date must be in YYYY-MM-DD format.`, 'ValidationError'); } } validateDateRange(from, until) { if (from && until && from > until) { throw new errors_1.KokkaiError('Date range is invalid: "from" date cannot be after "until" date.', 'ValidationError'); } } applyDefaultParams(params, defaultMax, maxLimit) { return { ...params, maximumRecords: Math.min(params.maximumRecords ?? defaultMax, maxLimit), }; } serializeParams(params) { const queryParams = {}; for (const key in params) { if (Object.prototype.hasOwnProperty.call(params, key)) { const value = params[key]; if (value !== undefined && value !== null && value !== '') { queryParams[key] = value; } } } queryParams['recordPacking'] = 'json'; // Always enforce JSON response return queryParams; } isErrorResponse(data) { return typeof data === 'object' && data !== null && 'message' in data && !('numberOfRecords' in data); } } exports.KokkaiClient = KokkaiClient;