概念定义
两两集成需要每对一份映射——随系统数二次增长。规范枢纽格式让每个系统只映射到枢纽:线性数量的映射、一套共享词汇,以及唯一一处强制语义的地方。它是“公共协议”在数据侧的对应物。
工作机制
模型以系统中立方式定义实体、标识符、枚举与不变量:生产方翻译出站,消费方翻译入站。模式注册中心跨版本校验兼容性;映射代码集中在一处做集中测试,而非散落各对之间。
使用场景
三个以上系统交换同类实体、发布节奏各异的 B2B 数据流、聚合异构源的分析平台。仅两个系统一次性集成不值得引入这层间接。
常见误区
委员会式设计容易膨胀:应追逐最小稳定语义,其余做版本化扩展。过度抽象的模型不可读,欠规范的模型则让每个映射方各自发明语义。标识符策略——谁拥有规范主键——是错伤最久的决策;无版本闸门的破坏性变更会同时打断所有消费者。
代码示例
import Ajv from 'ajv';
import addFormats from 'ajv-formats';
const ajv = new Ajv({ allErrors: true, coerceTypes: true, removeAdditional: true });
addFormats(ajv);
const schemas = {
CreateUser: {
type: 'object',
additionalProperties: false,
required: ['email', 'role'],
properties: {
email: { type: 'string', format: 'email' },
role: { type: 'string', enum: ['admin', 'editor', 'viewer'] },
display_name: { type: 'string', maxLength: 60 },
},
},
};
const validate = ajv.compile({
$ref: '#/components/schemas/CreateUser',
components: { schemas },
});
function schemaMiddleware(validator) {
return (req, res, next) => {
if (!validator(req.body)) {
return res.status(400).json({
error: 'schema validation failed',
details: (validator.errors ?? []).map((e) => ({
path: e.instancePath || e.params?.missingProperty ?? '',
message: e.message,
})),
});
}
next();
};
}
const ok = validate({ email: '[email protected]', role: 'editor' });
const bad = validate({ email: 'not-an-email', role: 'hacker', extra: 1 });
console.log('valid:', ok, 'errors:', bad ? 0 : validate.errors.length);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum OrderState {
Draft,
Placed,
Paid,
Shipped,
Cancelled,
}
#[derive(Debug, PartialEq, Eq)]
enum TransitionError {
InvalidTransition {
from: OrderState,
event: &'static str,
},
}
struct Order {
state: OrderState,
}
impl Order {
fn new() -> Self {
Self {
state: OrderState::Draft,
}
}
fn apply(&mut self, event: &'static str) -> Result<OrderState, TransitionError> {
use OrderState::*;
let next = match (self.state, event) {
(Draft, "place") => Placed,
(Placed, "pay") => Paid,
(Paid, "ship") => Shipped,
(Draft | Placed, "cancel") => Cancelled,
(_, _) => {
return Err(TransitionError::InvalidTransition {
from: self.state,
event,
});
}
};
self.state = next;
Ok(next)
}
}
fn main() {
let mut order = Order::new();
assert_eq!(
order.apply("pay"),
Err(TransitionError::InvalidTransition {
from: OrderState::Draft,
event: "pay",
})
);
assert_eq!(order.apply("place"), Ok(OrderState::Placed));
assert_eq!(order.apply("pay"), Ok(OrderState::Paid));
assert_eq!(
order.apply("cancel"),
Err(TransitionError::InvalidTransition {
from: OrderState::Paid,
event: "cancel",
})
);
assert_eq!(order.apply("ship"), Ok(OrderState::Shipped));
assert_eq!(
order.apply("ship"),
Err(TransitionError::InvalidTransition {
from: OrderState::Shipped,
event: "ship",
})
);
println!("final state: {:?}", order.state);
}