SPB Git

spb/qwhpi Public

QHPI — Quebec Housing Price Index: quality-adjusted, hierarchically pooled housing price indexes.

Python 63.9% TypeScript 25.4% CSS 5.5% TeX 3.5% SQL 0.8% Makefile 0.5% Dockerfile 0.5%
4.5 KB · 167 lines typescript
Raw Blame History
1/**2 * =============================================================================3 * QWHPI — Quebec Weekly Housing Price Index4 * Author  : Simon-Pierre Boucher5 * Contact : contact@spboucher.ai6 * File    : web/lib/api.ts7 * Purpose : Typed API client for the QHPI monthly FastAPI service.8 * =============================================================================9 */1011export const API_BASE =12  process.env.NEXT_PUBLIC_API_URL ?? "http://localhost:8080";1314export interface Observation {15  period: string;16  index: number | null;17  index_smoothed: number;18  representative_value: number | null;19  transactions: number;20  effective_sample_size: number | null;21  monthly_pct: number | null;22  three_month_pct: number | null;23  six_month_pct: number | null;24  yoy_pct: number | null;25  lower_95: number;26  upper_95: number;27  reliability_grade: string;28  shrinkage_weight: number | null;29  is_partial_month: boolean;30}3132export interface SeriesResponse {33  geography: string;34  geography_name: string;35  geography_level: string;36  property_type: string;37  model_version: string;38  data_vintage: string;39  total_observations: number;40  observations: Observation[];41}4243export interface LatestResponse {44  geography: string;45  geography_name: string;46  property_type: string;47  period: string;48  latest_index: number;49  representative_value: number | null;50  monthly_change: number | null;51  three_month_change: number | null;52  yoy_change: number | null;53  transactions: number;54  reliability: string;55  lower_95: number;56  upper_95: number;57  is_partial_month: boolean;58  data_vintage: string;59}6061export interface GeographyNode {62  geography_id: string;63  geography_name: string;64  geography_level: string;65  property_types: string[];66}6768export interface MapCell {69  geography_id: string;70  geography_name: string;71  value: number | null;72  reliability_grade: string;73  transactions: number;74}7576async function get<T>(path: string): Promise<T> {77  const res = await fetch(`${API_BASE}${path}`, {78    headers: { Accept: "application/json" },79  });80  if (!res.ok) throw new Error(`${res.status} ${res.statusText} — ${path}`);81  return res.json() as Promise<T>;82}8384export const fetchSeries = (g: string, t: string) =>85  get<SeriesResponse>(`/v1/index?geography=${g}&type=${t}`);8687export const fetchLatest = (g: string, t: string) =>88  get<LatestResponse>(`/v1/index/latest?geography=${g}&type=${t}`);8990export const fetchGeographies = () =>91  get<{ published_series: GeographyNode[]; data_vintage: string }>(92    "/v1/geographies",93  );9495export const fetchMap = (metric: string, type: string, period?: string) =>96  get<{ metric: string; period: string; cells: MapCell[] }>(97    `/v1/map?metric=${metric}&level=region&type=${type}` +98      (period ? `&period=${period}` : ""),99  );100101export const csvUrl = (g: string, t: string) =>102  `${API_BASE}/v1/index?geography=${g}&type=${t}&format=csv`;103104export interface SeriesStats {105  geography: string;106  property_type: string;107  period: string;108  index: number;109  representative_value: number | null;110  lower_95: number;111  upper_95: number;112  reliability_grade: string;113  monthly_pct: number | null;114  three_month_pct: number | null;115  six_month_pct: number | null;116  yoy_pct: number | null;117  since_2021_pct: number;118  cagr_pct: number;119  peak_index: number;120  peak_period: string;121  drawdown_pct: number;122  months_since_peak: number;123  at_record_high: boolean;124  volatility_12m_pct: number;125  momentum_3m_ann_pct: number;126  yoy_rank: number | null;127  yoy_rank_of: number;128  volume_12m: number;129  volume_yoy_pct: number | null;130  dollar_volume_12m: number;131  assessment_gap: number | null;132  effective_sample_size: number | null;133  spark: number[];134}135136export interface OverviewRow {137  geography_id: string;138  geography_name: string;139  period: string;140  index: number;141  monthly_pct: number | null;142  three_month_pct: number | null;143  six_month_pct: number | null;144  yoy_pct: number | null;145  since_2021_pct: number;146  drawdown_pct: number;147  at_record_high: boolean;148  volume_12m: number;149  representative_value: number | null;150  reliability_grade: string;151  spark: number[];152}153154export const fetchStats = (g: string, t: string) =>155  get<SeriesStats>(`/v1/stats?geography=${g}&type=${t}`);156157export const fetchOverview = (level: string, t: string) =>158  get<{ period: string; rows: OverviewRow[] }>(159    `/v1/stats/overview?level=${level}&type=${t}`,160  );161162export const reportUrl = (specs: string[]) =>163  `${API_BASE}/v1/report?series=${specs.join(",")}`;164165export const marketReportUrl = (t: string) =>166  `${API_BASE}/v1/report/market?type=${t}`;167