我日常工作的大部分内容是 TypeScript 和 PHP,但背后有一大部分工具 Toolz.dev 我围绕它编写的小服务是 Go,每次连接新的 API 客户端时,我都会撞到同一堵墙。您面前有 JSON 响应,您需要 Go 结构 json.Unmarshal will解码成。用手写那个struct,用很具体的方式来写是乏味的:不难,就是提琴,提琴的位子正是你犯错的地方,所以我在站内建了一个转换器,这是它的指南。
TL;博士: 工具 JSON to Go 结构转换器 json文档解析,并发出描述它的go类型声明,对象变成内联结构,对象数组合并成一个struct,每个字段得到一个
json:"key"标签所以encoding/jsonmap数据正确地回传。字段名称遵循go约定,所以id变成ID並user_url变成UserURL。将整数切换到int64,加omitempty(root)类型,并重命名,它完全运行客户端:无上传,无注册,离线工作。
什么是 JSON to Go 结构转换器?
JSON to Go 结构转换器将 JSON 文档转换为描述它的 Go 类型声明,因此您可以使用标准库解码相同的数据's encoding/json package而不是用手键入struct。json的每个对象都变成一个go结构,每个字段都携带一个 json:"key" tag,将其映射回原来的名称,从值推断出标量类型,一个json字符串变成 string,整数变为 int中,小数点为 的数变为 float64、 true 並 false 变成 bool、和 null 变成 interface{}。
JSON 对象和 Go struct 描述相同的形状,一组带有类型值的命名字段,但 Go 是静态类型,而 JSON 不是,因此 struct 必须前面拼出每个类型。从样本响应中导出这些类型是纯粹的力学,而通过嵌套有效负载手工完成的力学是错误所在。转换器确定性地进行导出,并将编译的类型块发回给您。
问题的两半值得明确,因为它们是一个天真的转换器所犯的错误。第一个是命名:Go 仅编码导出的字段,大写第一个字母的字段,社区 lint 规则希望通用缩写完全大写。第二个是标签: json:"..." 标签必须保留确切的原始密钥或 json.Unmarshal 运行时默默跳过字段,没有错误。要么错,你的解码返回一个充满零值的结构,而一切看起来都很好。该工具为您处理这两个问题。
为什么不手工编写结构呢?
这是诚实的问题,因为对于平坦的三字段对象,手写结构比打开工具更快。转换器在不平坦的响应上赢得一席之地:带有嵌套对象的有效负载、对象数组和二十个字段,其中一半是键 snake_case 有些是缩写词 id、 url、和 api_key。
On a response like that,手写版本有我反复打的三种失败模式,你忘了导出一个字段,所以保持小写和 encoding/json 拒绝填充它。您利用字段但忘记标签,因此 UserName 寻找名为 JSON 的密钥 UserName 并且从未发现 user_name。或者你得错了嵌套,当JSON实际上将字段包装在一个数组中时,将字段声明为普通struct。这些都不是编译错误。它们是运行时惊喜,显示为缺失的数据,你在调试其中一个时会损失比你在生成整个struct时花费的时间更多。
Converter 全部去掉三个,它导出每个字段,它从真实的键写入标签,它读取实际的 JSON 形状,以决定结构和结构片,你粘贴的是你得到的类型。
这是一张桌子上的决定。
| 情况 | 用 | 为什么 |
|---|---|---|
| 具有两个或三个字段的平面对象 | 手写它 | 比打开任何东西都快 |
| 具有许多字段的嵌套 API 响应 | JSON to Go 结构转换器 | 命名和标签是手写结构破裂的地方 |
| 您需要与 TypeScript 相同的形状 | JSON 到 TypeScript 转换器 | 相同的推论,不同的目标语言 |
| 您需要验证模式,而不是类型 | JSON 架构生成器 | Draft-07规则而不是围棋类型 |
Go字段名称为什么和我的JSON键不同?
次绊倒人,值得解释而不是躲起来,Go's encoding/json 仅包装元帅和非元帅 出口 struct字段,意思是名字以大写字母开头的字段。像这样的 JSON 键 user_name 无法映射到未导出的 user_name field,所以这个字段要改名为导出的东西,工具把每个单词都大写,转动 user_name 进入 UserName。
最重要的是,Go 社区's 棉绒工具,即从开始的规则 golint 并继续使用诸如此类的工具 staticcheck、想要用所有大写字母写出共同的首字母。所以 id 变成 ID不是 Id; user_url 变成 UserURL不是 UserUrl;和 html_body 变成 HTMLBody.转换器知道初始化的标准集, ID、 URL、 API、 HTTP、 JSON、 UUID剩下的,并应用它们,因此输出会传递 CI 可能运行的衬里。
使重命名安全的棋子是标签。每个字段都得到一个 json:"user_name" 标签准确地保留原始密钥,因此在运行时 json.Unmarshal 读取 JSON 键 user_name 并写入 UserName field 不管重命名,Go 博客's 在 JSON 和 Go 上的文章记录了这种标签机制,而这也是重命名字段仍然正确解码的原因,如果没有标签,重命名后的 struct 会悄悄地无法填充。
如何处理对象的数量和数组?
推理的两个部分值得仔细研究,因为它们是转换器质量不同的地方。
Numbers first。JSON 有单一的数字类型,但 Go 没有,所以工具必须选择。没有分数部分的值变成 int、或者 int64 如果您打开该选项,则带有小数点的值将成为 float64。有趣的情况是一个将它们混合在一起的数组,就像 [9.5, 8, 7.2]。如果工具将其输入为 []int 它将无法解码 9.5所以它将整个切片加宽到 []float64.任何一个元素强制使用更宽类型的数组,对于所有元素都得到更宽的类型,这是解码每个值的唯一选择。
Arrays of objects 是另一个地方 真正的有效载荷变得有趣 一个 API 几乎从来没有给你一个数组,其中每个对象都有一组相同的键;一个元素有一个其他元素省略的字段,或者一个可空字段在这里存在,那里不存在。如果工具仅从第一个元素生成一个struct,它会丢弃后面出现的键。相反,它会将数组中的每个对象合并到一个struct中,该struct包含任何元素所具有的每个键。如果两个元素给出相同的键不兼容类型,比如一个中的数字和另一个中的字符串,则该字段会回落到 interface{} 而不是工具猜错或彻底失败。结果是单一的结构类型,可以解码整个数组。
如何使用转换器?
Flow是四步,把一个JSON对象或者数组粘贴到输入框中;如果想先看到输出的形状,就加载样本,给根类型起个名字,类似 User 或 ApiResponse并且该工具将其清理为有效的导出 Go 标识符,因此它会按写入的方式进行编译。选择 int 或 int64 对于整数,然后打开 omitempty 如果您希望稍后将 struct 编码回 JSON 时省略零值字段。然后单击"转换"并将该结构复制到您的中 .go 文件。
JSON无效,工具会报告解析器'自己的错误消息,而不是默默失败,因此一个杂散的尾随逗号或一个未引用的密钥很快就会找到。并且因为所有内容都在浏览器中运行,所以你可以粘贴一个真实的API响应,包括一个带有私有字段的响应,而不会离开你的机器。那个客户端模型与站点其余部分的模型相同,在中描述 数据隐私在线工具 指南。
这与其他 JSON 工具如何配合?
JSON to Go 结构转换器是站内 JSON 变压器家族中的一员,它们共享相同的解析核心,当你想先整理 JSON 时,the JSON 格式化程序 will缩进并验证,这在你转换之前是值得做的,这样你就可以读取你即将键入的形状,当你的目标语言是typescript而不是go时,the JSON 到 TypeScript 转换器 运行相同的推理并发出接口。当您需要验证合同而不是语言类型时, JSON 架构生成器 生成 Draft-07 模式,当目的地是 PHP 代码库时, JSON 到 PHP 阵列转换器 写一个数组字面。
连接所有这些的线程是,他们将 JSON 视为结构源,并将该结构翻译成您的代码库所说的任何内容。如果您跨多种语言工作, web开发人员工具包 综述显示了这些棋子如何组合在一起 编码工具指南 涵盖更广泛的格式化和转换器集。
构建 Go 服务的一个有效示例
让我具体一点。不久前,我正在编写一个小型 Go 服务,该服务从第三方 API 中提取数据并重新公开其精简版本。供应商'的响应是一个嵌套对象:一个顶级记录,其中包含一个 owner 子对象,a tags 字符串数组,以及 scores array that,恼人的,根据字段将整数和小数混合在一起手工打字结构意味着得到 owner 嵌套正确,标记每个 snake_case key,并决定如何处理该混合数组。
我将样本响应粘贴到转换器中,以资源命名根类型,并返回一个结构 Owner 作为内联嵌套结构, Tags as []string、和 Scores 正确拓宽至 []float64. X = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 = 1000 id 现场出来了 ID 着一个 json:"id" tag,所以它都传递了 linter,解码了真正的密钥,我直接复制到客户端包中,然后继续逻辑,这就是我真正想花时间的地方,struct 不是工作中有趣的部分,生成它意味着它不再是工作中的任何部分。
I reach for the converster 而不是手写的struct 在这些点上不是懒惰,而是机械部件,导出,标记,嵌套,正是我思考逻辑时弄错的部件,而是将它们卸载到确定性工具,这意味着struct在第一个编译时是正确的,在第一次运行时是正确的解码,在嵌套的有效负载上保存了真正的调试会话,当我需要struct也能在重新编码后生存时,我打开 omitempty 因此,零值不属于输出,标签以 as 形式出现 json:"key,omitempty" 准备好往返了。
有哪些值得了解的极限?
几个诚实的边缘。第一个是 null.A JSON null 它本身不携带类型信息,因此字段为 null 在您的样本中键入为 interface{}。那里没有什么工具可以推断;如果你知道真实类型,粘贴后在编辑器中更改它,或者给转换器提供一个样本,其中该字段有真实值,因此可以导出类型。这是数据的属性,而不是工具的缺点。
2是数字精度,它是JSON解析的属性一般而不是这个转换器具体。工具解析你的JSON与浏览器's JSON解析器,它表示数字为双精度浮动,因此超过大约2到53次方的整数在解析时间失去精确性,在工具看到它们之前生成 int64 场地足够宽 持有 ID大,但如果ID到达的裸JSON数字那么大,解析已经将其四舍五入,对于真正的大整数ID,鲁棒的动作是将它们作为字符串在JSON中携带,这可以保持它们的精确性,并让您将字段键入为 string。
第三,推理是一个起点,而不是福音。该工具为您提供样本支持的类型,但只有您知道在此响应中恰好是整数的字段实际上是可零计数,或者 a float64 应该是一个 json.Number 为了避免精度损失。将输出视为您提炼的正确初稿,而不是刻在石头上的合同。每个 JSON 到类型的生成器(在任何语言中)都是如此。
最后,转换器产生内联嵌套结构,将整个形状保留在一个声明中,您可以粘贴为一个块。这是生成的结构最常见和最可读的样式,也是 Go 生态系统中工具普及的工具。如果您希望为深度重用的子对象有单独的命名类型,那么一旦内联版本在编辑器中,您就可以手工进行重构,并且通常是使用 IDE 的五秒提取。
常见问题
什么是 JSON to Go 结构转换器? JSON to Go struct 转换器将一个 JSON 文档转换为描述它的 Go 类型声明,每个对象都变成一个 struct,每个字段得到一个 json:"key" 标签,并推断出值类型,因此您无需手工编写 struct,即可用编码/json 解编相同的数据。
如何将 JSON 转换为 Go 结构? JSON 粘贴到输入框中,输入根类型的名称,选择整数和标签选项,然后单击转换。该工具使用 json 标签打印 Go 结构定义,您可以直接将其复制到。go 文件中。
Go字段名称为什么和我的JSON键不同? Go只对导出的字段进行编码,因此每个字段名称都大写,并且将常见的首字母缩写做大写以匹配golint。每个字段上的json:"..."标签都保留了原始密钥,因此json。Unmarshal尽管重新命名了字段,仍然正确地映射数据。
JSON 数字如何映射到 Go 类型? 整数变为 int,或者 int64(如果启用该选项),并且具有小数点的数字变为 float64。当数组混合相同位置的整数和小数时,类型会加宽为 float64,因此每个值都适合。
如何处理对象数组? 1个对象数组合并成一个单一的struct,包含任何元素所拥有的每一个密钥,如果两个元素给出相同的密钥不兼容类型,则该字段变为interface{},因此struct仍然覆盖整个数组。
空值会发生什么? JSON null 自己给出的类型信息都不给,所以字段是打为 interface{},如果知道真实类型,粘贴后在编辑器中更改,或者在 JSON 中提供一个非 null 的示例值,这样就可以推断出类型。
我的json是否上传到任何地方? No。转换完全发生在您的浏览器使用JavaScript在您的设备上。您的JSON从未上传,记录或存储,并且一旦页面加载,该工具就一直与断开连接的网络一起工作。
JSON to Go 结构转换器免费吗? Yes。完全免费,没有注册,没有水印,也没有使用上限。将尽可能多的JSON文档转换为Go结构,因为您需要个人或商业项目。



