225 lines
4.8 KiB
Markdown
225 lines
4.8 KiB
Markdown
# Weather Data API
|
||
|
||
FastAPI 服务,用于接收气象站观测数据并存入 PostgreSQL,同时提供查询接口。
|
||
|
||
## 快速开始
|
||
|
||
### 1. 准备数据库
|
||
|
||
```bash
|
||
createdb weather_data
|
||
```
|
||
|
||
### 2. 配置环境变量
|
||
|
||
复制 `.env.example` 为 `.env` 并填入实际值:
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
```
|
||
|
||
`.env` 内容:
|
||
|
||
```
|
||
DATABASE_HOST=localhost
|
||
DATABASE_PORT=5432
|
||
DATABASE_USER=postgres
|
||
DATABASE_PASSWORD=your_password_here
|
||
DATABASE_NAME=weather_data
|
||
```
|
||
|
||
### 3. 安装依赖
|
||
|
||
```bash
|
||
uv sync
|
||
```
|
||
|
||
### 4. 启动服务
|
||
|
||
```bash
|
||
uv run uvicorn app.main:app --reload
|
||
```
|
||
|
||
服务默认监听 `http://localhost:8000`,访问 `/docs` 查看 Swagger 文档。
|
||
|
||
---
|
||
|
||
## API 端点
|
||
|
||
### GET `/stations` — 列出所有气象站
|
||
|
||
获取所有已知气象站的列表(从观测数据中派生)。
|
||
|
||
成功响应(200):
|
||
|
||
```json
|
||
{
|
||
"stations": [
|
||
{
|
||
"name": "北京站",
|
||
"observation_count": 156,
|
||
"latest_observation_at": "2026-06-19T11:45:00.654321+00:00"
|
||
},
|
||
{
|
||
"name": "上海站",
|
||
"observation_count": 89,
|
||
"latest_observation_at": "2026-06-19T10:30:00.123456+00:00"
|
||
}
|
||
],
|
||
"count": 2
|
||
}
|
||
```
|
||
|
||
### POST `/stations/{station_name}/observations` — 接收气象数据
|
||
|
||
请求体(JSON):
|
||
|
||
```json
|
||
{
|
||
"temperature": 26.5,
|
||
"pressure": 1013.2,
|
||
"relative_humidity": 68.0
|
||
}
|
||
```
|
||
|
||
字段说明:
|
||
|
||
| 字段 | 类型 | 必填 | 说明 |
|
||
|------|------|------|------|
|
||
| `temperature` | float | 否 | 温度(摄氏度) |
|
||
| `pressure` | float | 否 | 气压(hPa) |
|
||
| `relative_humidity` | float | 否 | 相对湿度(%,0-100) |
|
||
|
||
> 气象站名称从 URL 路径中获取,不再出现在请求体中。
|
||
|
||
成功响应(201):
|
||
|
||
```json
|
||
{
|
||
"id": 1,
|
||
"station_name": "北京站",
|
||
"temperature": 26.5,
|
||
"pressure": 1013.2,
|
||
"relative_humidity": 68.0,
|
||
"received_at": "2026-06-19T10:30:00.123456+00:00"
|
||
}
|
||
```
|
||
|
||
`received_at` 由服务端在收到数据时自动记录。
|
||
|
||
### GET `/stations/{station_name}/observations/latest` — 查询最新数据
|
||
|
||
获取指定气象站的最新一条记录:
|
||
|
||
```
|
||
GET /stations/北京站/observations/latest
|
||
```
|
||
|
||
成功响应(200):
|
||
|
||
```json
|
||
{
|
||
"id": 42,
|
||
"station_name": "北京站",
|
||
"temperature": 27.1,
|
||
"pressure": 1012.8,
|
||
"relative_humidity": 65.0,
|
||
"received_at": "2026-06-19T11:45:00.654321+00:00"
|
||
}
|
||
```
|
||
|
||
未找到数据时返回 404。
|
||
|
||
### GET `/stations/{station_name}/observations` — 查询历史数据
|
||
|
||
获取指定时间范围内的所有记录。支持两种查询方式:
|
||
|
||
**按最近 N 小时查询:**
|
||
|
||
```
|
||
GET /stations/北京站/observations?hours=24
|
||
```
|
||
|
||
**按自定义时间范围查询:**
|
||
|
||
```
|
||
GET /stations/北京站/observations?start=2026-06-19T00:00:00&end=2026-06-19T12:00:00
|
||
```
|
||
|
||
**分页查询:**
|
||
|
||
```
|
||
GET /stations/北京站/observations?limit=50&offset=0
|
||
```
|
||
|
||
参数说明:
|
||
|
||
| 参数 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `hours` | int | 从现在往前推 N 小时。如果同时指定了 `start`,则覆盖 `start` |
|
||
| `start` | datetime | 时间范围起点(ISO 8601 格式,UTC),不传则不限制 |
|
||
| `end` | datetime | 时间范围终点(ISO 8601 格式,UTC),不传则默认到当前时刻 |
|
||
| `limit` | int | 返回的最大记录数 |
|
||
| `offset` | int | 跳过的记录数(用于分页),默认 0 |
|
||
|
||
成功响应(200):
|
||
|
||
```json
|
||
{
|
||
"station_name": "北京站",
|
||
"count": 2,
|
||
"records": [
|
||
{
|
||
"id": 42,
|
||
"station_name": "北京站",
|
||
"temperature": 27.1,
|
||
"pressure": 1012.8,
|
||
"relative_humidity": 65.0,
|
||
"received_at": "2026-06-19T11:45:00.654321+00:00"
|
||
},
|
||
{
|
||
"id": 40,
|
||
"station_name": "北京站",
|
||
"temperature": 26.8,
|
||
"pressure": 1013.0,
|
||
"relative_humidity": 67.0,
|
||
"received_at": "2026-06-19T10:30:00.123456+00:00"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
未找到匹配数据时返回空列表,气象站不存在时返回 404。
|
||
|
||
---
|
||
|
||
## 数据库表结构
|
||
|
||
| 列名 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `id` | `BIGSERIAL` | 主键,自增 |
|
||
| `station_name` | `TEXT` | 气象站名称 |
|
||
| `temperature` | `DOUBLE PRECISION` | 温度 |
|
||
| `pressure` | `DOUBLE PRECISION` | 气压 |
|
||
| `relative_humidity` | `DOUBLE PRECISION` | 相对湿度 |
|
||
| `received_at` | `TIMESTAMPTZ` | 数据接收时间(服务端自动填充) |
|
||
|
||
表上有 `(station_name, received_at DESC)` 组合索引,支持按站名和时间的高效查询。
|
||
|
||
---
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
weather-data-api/
|
||
├── .env.example # 配置模板
|
||
├── pyproject.toml # 依赖声明
|
||
├── README.md
|
||
└── app/
|
||
├── __init__.py
|
||
├── config.py # 从 .env 加载数据库配置
|
||
├── database.py # asyncpg 连接池 + 数据库操作
|
||
├── models.py # Pydantic 模型
|
||
└── main.py # FastAPI 应用入口
|
||
```
|