网易首页 > 网易号 > 正文 申请入驻

一个类型定义,同时管住前端和后端:路由类型如何让两边不再对不上

0
分享至

一个接口的请求和响应,通常要在两个地方各写一遍:服务端写一遍处理逻辑,客户端再写一遍调用代码。两边只要有一处对不上,就得等到运行时才炸出来。TeamTavern 这个找游戏队友的网站,把这件事换了个做法——浏览器端和 API 服务端都写在同一个 PureScript 代码库里,由同一次 spago build 编译。

真正值得说的是两边怎么对话:每一个 HTTP 接口就是一个类型,服务端的处理函数和客户端的调用都从这个类型推导出来。路由库用的是 Jarilo,属于 purescript-bklaric。熟悉 Haskell 的 Servant 的话,这套思路会眼熟。


一个路由就是一个类型

先看登录玩家用的那个路由。它被声明成一个类型:向 /sessions 发一个 POST,带 JSON 请求体,应答是 204 No Content,或者一个 400 并携带三种原因之一,或者 500。没有别的可能。

请求体本身也是一个类型,用 Variant 描述两种登录方式:一种是邮箱或昵称加密码,一种是 Discord 的 accessToken。400 的三种原因同样是类型:unknownPlayer、wrongPassword、unknownDiscord。

这里没有 StartSession 类型的值。这些片段都是裸的类型级数据声明的,PostJson_、NoContent 这些只是少数几个底层构造的类型同义词。带路径参数的路由长这样:games 后面接一个字符串的 handle,再接 posts,再接一个整数的 id。

每个路由单独放在 Routes/ 下的一个模块里,紧挨着它请求体和响应体的 record、variant 类型。Server/ 和 Client/ 都从那里导入。

服务端:一张处理函数的记录表

所有路由被合并成一个大类型,每个路由挂在一个名字下。服务端就是一次调用,接收这个类型,外加一张记录表,每个名字对应一个处理函数。

serve 带一个约束 JunctionRouter junction handlers,并且有一条从路由到记录表的函数依赖。于是编译器能从 AllRoutes 反推出记录表的类型:它有哪些字段、每个处理函数收到什么、允许返回什么。

对 viewPost 来说,path 就是 handle 字符串加 id 整数,因为路由捕获了一个叫 handle 的字符串和一个叫 id 的整数。路由器在处理函数跑起来之前就已经把路径段解析成了整数,一个 /games/valorant/posts/abc 这样的请求,在代码看到它之前就已经被应答了。对 startSession 来说,body 就是已经解码好的请求体 variant。

返回类型也是同样推出来的。由此带来两个结果。

第一,处理函数的错误类型是 Void,它不能失败。内部出的任何问题,都必须变成这个路由声明的某个响应。实际上每个处理函数都被包在一个小函数里,把它的类型化错误转成对应的响应,并且只在它是 internal 那一种时才记日志。

第二,responseRow 精确地装着这个路由声明的那些响应。StartSession 没有 404,所以一个想给它回 notFound 的处理函数根本编译不过。同样,AllRoutes 里有一个路由却没有对应处理函数的服务端,也编译不过。

客户端:同一个类型,反着读

在客户端,一次请求就是对 fetch 的调用,把路由当作代理传进去。又是函数依赖在干活:路由决定方法、用路径和查询记录拼出 URL、编码请求体并设置 Content-Type。

调用一个帖子的接口时,传入 handle 和 id。漏掉 id,或者把 id 当成字符串传进去,都编译不过。

拿回来的东西是一个 Variant,每个声明的响应对应一个分支,JSON 体已经按路由的类型解码好了。从登录页用 Discord 登录,代码大致是这样:调用 StartSession,注入 discord 分支和 accessToken,然后对结果做匹配——noContent 就跳回去,badRequest 里的 unknownDiscord 就带着 nickname 跳到昵称页面,其余情况报错。

页面给新玩家预填的 nickname,正是服务端放进 unknownDiscord 里的那个字段。客户端对这个载荷的理解不可能和服务端跑偏,因为它的定义只有一份。

改动一次会怎样

这个网站有 47 个路由。当其中一个发生变化时,编译器会找出这次改动牵动的地方:

改一个响应体里的字段名,构造它的处理函数和每一个读它的页面都编译不过。加一个路径捕获,这个路由的每一次 fetchPath 调用都少一个字段。删掉一个响应,返回它的处理函数和按名字匹配它的页面都编译不过。往 AllRoutes 里加一个路由,服务端在它有处理函数之前构建不起来。

有一种情况编译器不会强制。给一个路由加一个响应,只要现有客户端代码用的是 onMatch 加一个默认分支,就仍然编译得过。这是一个取舍:换成 match 会让每个调用点都穷尽,代价是到处都要把 internal 写出来。

类型到此为止的地方

路由类型描述的是服务端和客户端之间传递的东西。它管不到的东西也值得说清楚:它不保证处理函数内部真的按声明的语义去做事,也不保证数据库查询、邮件发送这些副作用正确。类型能保证的是两边对接口形状的理解一致,而不是接口背后的行为正确。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
姐姐名古屋载誉归来何锦櫶染黄发接机 盼下次大赛金童玉女一起闪耀

姐姐名古屋载誉归来何锦櫶染黄发接机 盼下次大赛金童玉女一起闪耀

劲爆体坛
2026-10-01 09:55:03
“穿个底裤就出门了?”宝妈穿瑜伽短裤接孩子,网友:我一个女的都不好意看!

“穿个底裤就出门了?”宝妈穿瑜伽短裤接孩子,网友:我一个女的都不好意看!

林林先生
2026-10-02 07:45:07
维蒂尼亚:主教练的工作已经起作用了,效果非常明显

维蒂尼亚:主教练的工作已经起作用了,效果非常明显

懂球帝
2026-10-02 05:40:12
朝鲜核爆后的隐患越来越重:地下六次核试验对中国也产生了影响

朝鲜核爆后的隐患越来越重:地下六次核试验对中国也产生了影响

莫地方
2026-10-01 20:01:56
80岁黄百鸣狱中表现良好获减刑,曝已低调出狱与家人共度中秋

80岁黄百鸣狱中表现良好获减刑,曝已低调出狱与家人共度中秋

动物奇奇怪怪
2026-10-01 12:11:41
哈佛大学研究发现:人生回报率最高的,是每天坚持这两个习惯

哈佛大学研究发现:人生回报率最高的,是每天坚持这两个习惯

心理观察局
2026-07-01 07:37:28
"45秒,全没了!"柏林宣布退出申办,奥运会从顶级IP沦为财政噩梦

"45秒,全没了!"柏林宣布退出申办,奥运会从顶级IP沦为财政噩梦

云居历史
2026-09-28 15:40:23
空姐被逼下跪求踹后续:东航发声明,知情人曝内幕,本人已上班

空姐被逼下跪求踹后续:东航发声明,知情人曝内幕,本人已上班

寒士之言本尊
2026-10-01 17:40:08
1988年援藏干部叛逃者周述武临终遗言,死后务必将骨灰送回故乡

1988年援藏干部叛逃者周述武临终遗言,死后务必将骨灰送回故乡

舆图看世界
2026-10-01 09:30:11
一夫一妻制逐渐难维持!社会学家分析:未来3种模式将成为主流

一夫一妻制逐渐难维持!社会学家分析:未来3种模式将成为主流

王二哥老搞笑
2026-09-24 07:26:29
国乒新情报:10月2日,孙颖莎未退赛!国乒2人一轮游,今天抽签!

国乒新情报:10月2日,孙颖莎未退赛!国乒2人一轮游,今天抽签!

老嗮说体育
2026-10-02 07:19:58
无敌! 9月车企销量 比亚迪46万 吉利29万 长城11万 零跑10万 鸿蒙3.7万

无敌! 9月车企销量 比亚迪46万 吉利29万 长城11万 零跑10万 鸿蒙3.7万

阿芒娱乐说
2026-10-02 01:24:09
部分葡萄牙球迷看台拼字声援:热苏斯,我们爱你

部分葡萄牙球迷看台拼字声援:热苏斯,我们爱你

懂球帝
2026-10-02 04:06:36
贺子珍始终坚信,朱道来就是自己在战乱中失散的儿子;可朱道来后来却坦言,当年他并没有把全部实情说出来。

贺子珍始终坚信,朱道来就是自己在战乱中失散的儿子;可朱道来后来却坦言,当年他并没有把全部实情说出来。

人生录
2026-10-01 16:39:34
31岁老板娘晒纹身:3个孩子侧脸加老公首字母,藏了5年

31岁老板娘晒纹身:3个孩子侧脸加老公首字母,藏了5年

时光慢旅人
2026-10-01 00:36:11
炸锅!29年首次黑八诞生,自由人淘汰山猫,韩旭登顶亚洲得分榜

炸锅!29年首次黑八诞生,自由人淘汰山猫,韩旭登顶亚洲得分榜

体育大朋说
2026-10-01 12:24:30
武汉十一长江烟花秀背后的经济大账

武汉十一长江烟花秀背后的经济大账

匹夫来搞笑
2026-10-02 01:22:26
华为Mate90三款怎么选?5999元起,别交智商税

华为Mate90三款怎么选?5999元起,别交智商税

小蜜情感说
2026-10-01 04:46:09
万万没想到!今年国庆节降价最狠的5种商品,香烟居然也榜上有名

万万没想到!今年国庆节降价最狠的5种商品,香烟居然也榜上有名

你在偷看谁
2026-10-01 20:37:34
苹果 iOS 26.7.1正式版已推送:更新关10个设置,系统流畅度暴涨20%

苹果 iOS 26.7.1正式版已推送:更新关10个设置,系统流畅度暴涨20%

辉哥说动漫
2026-10-01 07:18:49
2026-10-02 08:47:00
报错免疫体
报错免疫体
一名在需求评审和数据异常中反复横跳的产品运营。
180文章数 70关注度
往期回顾 全部

科技要闻

“分手”15天后,华为与赛力斯签约新五年

头条要闻

有关伊朗制裁问题 中国在联大投下反对票

头条要闻

有关伊朗制裁问题 中国在联大投下反对票

体育要闻

“今天的表现,我们可以昂首离开球场”

娱乐要闻

奚梦瑶晒四太豪礼!22只龙凤镯近300万

财经要闻

智谱发上亿Token 能挽回开发者信任吗?

汽车要闻

2027款极氪001将于明年一季度上市 现款猎装同步推新配色

态度原创

家居
数码
房产
亲子
教育

家居要闻

2026建博会(广州) 公装联探展交流活动

数码要闻

8月扫地机器人均价创年内低点!石头科技线上销额登顶

房产要闻

4000+/平!华侨城,直接把海口楼市的地板给掀了!

亲子要闻

鼓吹国外选精生子,收割大龄剩女的又一利器

教育要闻

六年级竞赛题:难住不少真学霸

无障碍浏览 进入关怀版