# API / 模块合约 > 本文定义第三方 API、统一响应和内部模块合约的目标形状。实现前可细化,但不要在代码里另起一套不兼容接口。 ## 通用约定 - 传输:HTTPS JSON。 - 编码:UTF-8 JSON。 - 时间格式:`YYYY-MM-DD` 用于业务日期,时间戳使用 ISO 8601。 - 第三方鉴权:待定,推荐 `Authorization: Bearer ` 或 `X-App-Key` + `X-Signature`。 - 每个响应包含 `trace_id`。 - 每个 API 请求都生成一个 archive 文件,保存 API 和 CHIS 请求 / 响应,详见 [架构设计](04-architecture.md) 的请求归档文件章节。 成功响应: ```json { "ok": true, "trace_id": "TRACE_ID", "data": {} } ``` 错误响应: ```json { "ok": false, "trace_id": "TRACE_ID", "error": { "code": "bad_request", "message": "请求参数不正确" } } ``` ## 第三方 API ### `POST /api/v1/health-checks/query-detail` 用途:查询 CHIS 中某次体检详情。第一版用于验证 CHIS 登录、Redis 会话、通用请求和查询链路。 第一版请求要求调用方传全参数: ```json { "account_ref": "chis-account-alias", "healthCheck": "0000000000481718", "phrId": "44162511100102877", "idCard": "440000********1234", "checkDate": "2014-06-05" } ``` 说明: - `healthCheck + phrId + idCard` 用于调用 CHIS `getHMNIListOfHTML`。 - `idCard + checkDate` 用于调用 CHIS `getCheckInfoDetail`。 - 当前资料不能证明只传 `healthCheck` 就能查完整详情;后续任务会验证反查链路。 成功响应: ```json { "ok": true, "trace_id": "TRACE_ID", "data": { "healthCheck": "0000000000481718", "detail": {}, "check_info": {} } } ``` ### `POST /api/v1/health-checks/submit` 用途:提交单条体检数据到 CHIS。 请求示例(字段待后续业务样例细化): ```json { "request_id": "third-party-unique-id", "source": "third-party-system", "account_ref": "chis-account-alias", "person": { "id_card": "440000********1234", "name": "张三" }, "check_date": "2026-07-04", "health_check": { "height": 170, "weight": 65 } } ``` 成功响应: ```json { "ok": true, "trace_id": "TRACE_ID", "data": { "request_id": "third-party-unique-id", "idempotent": false, "chis_result": { "code": 200, "message": "success" } } } ``` 重复提交响应: ```json { "ok": true, "trace_id": "TRACE_ID", "data": { "request_id": "third-party-unique-id", "idempotent": true, "chis_result": { "code": 200, "message": "success" } } } ``` ## 错误码 | code | HTTP | 说明 | | --- | --- | --- | | `unauthorized` | 401 | 第三方鉴权失败 | | `forbidden` | 403 | 第三方无权限使用该账号或机构 | | `bad_request` | 400 | 请求体格式错误或必填字段缺失 | | `invalid_health_check_data` | 400 | 体检字段校验失败 | | `missing_health_check_query_params` | 400 | 查询体检详情缺少 `healthCheck`、`phrId`、`idCard` 或 `checkDate` | | `chis_login_failed` | 502 | CHIS 登录失败 | | `chis_session_invalid` | 502 | CHIS 会话无效且重登失败 | | `chis_request_failed` | 502 | CHIS 业务接口失败 | | `chis_timeout` | 504 | CHIS 请求超时 | | `idempotency_conflict` | 409 | 相同幂等键对应不同请求体 | ## 内部模块合约 ### `ChisLoginClient.from_config(config).login(username, password)` 输入: ```python username: str password: str ``` 输出: ```python ChisLoginSession( cookie=str, jsessionid=str, role_id=str, role_name=str, user_name=str, roles_result=dict, apps_result=dict, ) ``` 职责: - 从 `CHIS_BASE_URL`、`CHIS_PUBLIC_KEY`、`CHIS_PROXY` 创建登录客户端。 - 调用 `logon/myRoles`,使用 SM2 加密密码和时间戳 `d`。 - 优先选择 `责任医生助理` 或 `责任医生` 角色。 - 调用 `logon/myApps` 获取应用上下文。 - 从 `Set-Cookie` 提取 `JSESSIONID`,组装 CHIS cookie。 - 登录失败、缺少允许角色、缺少 cookie 时抛出 `ChisLoginError`,错误对象包含稳定 `code`。 ### `ChisLoginClient.get_lander_info(cookie)` 输入: ```python cookie: str ``` 输出:CHIS `chis.myPageService / getLanderInfo` 原始字典响应。 职责: - 使用已有 CHIS cookie 调用 `*.jsonRequest?`。 - 请求体固定为 `serviceId=chis.myPageService`、`serviceAction=getLanderInfo`、`method=execute`。 - 成功时返回当前账号信息响应。 - CHIS 返回非 200 业务码时抛出 `ChisLoginError(code="chis_session_invalid")`,用于判断会话无效。 ### `RedisChisSessionStore` 职责: - 使用 Redis key `chis:session:{account_ref}` 保存 CHIS 会话对象。 - `save(account_ref, session)` 按 `expires_at` 计算 TTL 并调用 Redis `setex`。 - `get(account_ref)` 只返回未过期会话;发现过期会话时删除缓存并返回 `None`。 - `delete(account_ref)` 清理指定账号引用的缓存。 - 会话 JSON 包含 `base_url`、`uid`、`role_id`、`manage_unit`、`cookies`、`login_at`、`expires_at`、`last_validated_at`,不得包含明文密码。 ### `ChisSessionManager.ensure_session(account_ref)` 输入: ```python account_ref: str ``` 输出: ```python ChisSession( cookies=dict, uid=str, role_id=str | None, manage_unit=str | None, expires_at=datetime, ) ``` 职责: - 优先读取 Redis 有效会话。 - 会话不存在或验证失败时登录 CHIS。 - 登录成功后缓存会话。 - 不返回明文密码。 ### `ChisCrypto.sm2_encrypt(public_key, raw_text)` 职责: - 使用配置中的 CHIS public key 加密密码和时间戳 `d`。 - 兼容已有 `hans_chis.sm2.sm2_encrypt` 行为:`gmssl.sm2.CryptSM2(mode=0)`,返回带 `04` 前缀的十六进制密文。 - 不记录明文和密文到普通业务日志。 ### `HealthCheckQueryClient.get_detail(session, health_check, phr_id, id_card)` 输出:CHIS `getHMNIListOfHTML` 的标准化结果。 职责: - 组装 `chis.healthCheckService / getHMNIListOfHTML` 请求。 - 不做第三方鉴权。 - 不保存数据。 ### `HealthCheckQueryClient.get_check_info(session, id_card, check_date)` 输出:CHIS `getCheckInfoDetail` 的标准化结果。 职责: - 组装 `chis.healthCheckService / getCheckInfoDetail` 请求。 - 身份证号日志脱敏。 ### `HealthCheckMapper.to_chis_payload(input_model, session_context)` 输入:内部体检标准模型和 CHIS 会话上下文。 输出:CHIS `*.jsonRequest` 请求体。 职责: - 字段映射。 - 字典值转换。 - 默认值和空值处理。 - 不访问网络,不访问 Redis。 ### `ChisClient.json_request(session, payload)` 职责: - 发送 CHIS `*.jsonRequest`。 - 携带 cookie 和 header。 - 根据配置处理出站代理:`CHIS_PROXY` 为空直连;有值时为 CHIS HTTP 请求设置同一个 SOCKS5 代理。 - 处理 timeout、CHIS 错误、未登录。 - 返回标准化 CHIS 响应对象。