JSON风格指南
JSON(Javascript Object Notation)是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,也采用了类似c语言家族(包括c、c++、java、JavaScript、python等)的习惯。这些特性使得JSON称为理想的数据交换语言,易于阅读和编写,同时也易于机器解析和生成。
该风格指南是对在google创建JSON APIs而提供的指导性准则和建议,总体来说,JSON APIs符合JSON.org的规范。这份风格指南澄清和标准化了特定情况。
一、一般准则
1.注释
JSON对象中不应该包括注释。
2.双引号
如果某个属性需要引号,则必须使用双引号。所以的属性名都必须在双引号内,字符类型的属性值必须使用双引号。其他类型值,比如 布尔或者数字,不应该使用双引号。
3.扁平化数据 VS 结构层次
不能为了方便而将数据任意分组。JSOIN中的数据应该以扁平化的方式呈现,不能为了方便而将数据任意分组。但在某些情况下,比如描述单一结构的一批属性,因为它被用来保持结构层次,因而是有意义的。但是遇到这种情况还是应当慎重你考虑,记住只有语义上有意义的时候才使用它。例如,一个地址可以有两种方式,但结构化的方式对开发人员更有意义:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 扁平化地址: { "company" : "Google" , "website" : "http://www.google.com/" , "addressLine1" : "111 8th Ave" , "addressLine2" : "4th Floor" , "state" : "NY" , "city" : "New York" , "zip" : "10011" } 结构化地址: { "company" : "Google" , "website" : "http://www.google.com/" , "address" : { "line1" : "111 8th Ave" , "line2" : "4th Floor" , "state" : "NY" , "city" : "New York" , "zip" : "10011" } } |
二、属性名规则
1.属性名格式
选择有意义的属性名
属性名必须遵守以下准则:
- 属性名应该是具有定义语义的有意义的名称
- 属性名必须是驼峰式的 ASCII码字符串
- 首字符必须是字母,下划线_ 或者是 $ 符号
- 随后的其他字符可以是字母、数字、下划线或者$
- 应该避免使用javascript中的保留关键字
1 2 3 | { "thisPropertyIsAnIdentifier" : "identifier value" } |
2.JSON MAP中的键名
在JSON MAP中键名可以使用任意的Unicode字符。
但JSON对象作为MAP使用时,属性的名称命名规范并不使用。MAP是一个具有任意键值对的数据类型。MAP的键名不一定要遵循属性名称的命名准则,键名可以包含任意的unicode字符。客户端可以使用maps熟悉的方括号来访问这些属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | { // "address" 属性是一个子对象 // 包含地址的各部分. "address" : { "addressLine1" : "123 Anystreet" , "city" : "Anytown" , "state" : "XX" , "zip" : "00000" }, // "thumbnails" 是一个映射 // 含有响应规格所对应的URL,用来映射thumbnail url的像素规格 "thumbnails" : { "72" : "http://url.to.72px.thumbnail" , "144" : "http://url.to.144px.thumbnail" } } |
3.单数属性名 VS 复数属性名
数组类型应该是复数属性名,其他属性名都应该是单数。
1 2 3 4 5 6 7 8 9 10 | { // 单数 "author" : "lisa" , // 一组同胞, 复数 "siblings" : [ "bart" , "maggie" ], // "totalItem" 看起来并不对 "totalItems" : 10, // 但 "itemCount" 要好些 "itemCount" : 10, } |
4.命名冲突
通过选择新的属性名或API版本化来避免命名冲突
新的属性可能在将来被添加进保留列表中,JSON中不存在命名空间,如果存在命名冲突,可以通过选择新的属性名或者版本化来解决这个问题。例如,假设我们从下面的对象开始:
1 2 3 4 5 6 7 | { "apiVersion" : "1.0" , "data" : { "recipeName" : "pizza" , "ingredients" : [ "tomatoes" , "cheese" , "sausage" ] } } |
如果我们希望将来把ingredients列为保留字,我们可以通过下面两件事情来达成。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 1.选一个不同的名字 { "apiVersion" : "1.0" , "data" : { "recipeName" : "pizza" , "ingredientsData" : "Some new property" , "ingredients" : [ "tomatoes" , "cheese" , "sausage" ] } } 2.在主版本上重新命名属性 { "apiVersion" : "2.0" , "data" : { "recipeName" : "pizza" , "ingredients" : "Some new property" , "recipeIngredients" : [ "tomatos" , "cheese" , "sausage" ] } } |
三、属性值准则
1.属性值格式
属性值必须是unicode的布尔、数字、字符串、对象、数组或者null。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 好的例子: { "canPigsFly" : null , // null "areWeThereYet" : false , // boolean "answerToLife" : 42, // number "name" : "Bart" , // string "moreData" : {}, // object "things" : [] // array } 不好的例子: { "aVariableName" : aVariableName, // Bad - JavaScript 标识符 "functionFoo" : function() { return 1; } // Bad - JavaScript 函数 } |
2.空或null的属性值
如果一个属性是可选的或者包含空值或null值,考虑从JSON中去掉该属性,除非它的存在有很强的语义。
1 2 3 4 5 6 7 8 9 10 11 | { "volume" : 10, // 即使 "balance" 属性值是零, 它也应当被保留, // 因为 "0" 表示 "均衡" // "-1" 表示左倾斜和"+1" 表示右倾斜 "balance" : 0, // "currentlyPlaying" 是null的时候可被移除 // "currentlyPlaying": null } |
3.枚举值
枚举值应该以字符串的形式出现。随着APIs的发展,枚举值可能被添加,移除或者改变。将枚举值当做字符串可以使下游用户优雅的处理枚举值的变更。
1 2 3 4 5 6 7 8 9 10 11 12 13 | Java代码: public enum Color { WHITE, BLACK, RED, YELLOW, BLUE } JSON对象: { "color" : "WHITE" } |
四、JSON结构和保留属性名
为了使APIs保持一致的借口,JSON对象应当使用以下的结构。该结构适用于JSON的请求和响应。在这个结构中,某些属性名将被保留用作特殊用途。这些属性并不是必需的,也就是说,每个保留的属性可能出现零次或一次。但是如果服务需要这些属性,建议遵循该命名条约。下面是一份JSON结构语义表,以Orderly格式呈现(现在已经被纳入 JSONSchema)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | object { string apiVersion?; string context?; string id?; string method?; object { string id? }* params ?; object { string kind?; string fields?; string etag?; string id?; string lang?; string updated?; # date formatted RFC 3339 boolean deleted?; integer currentItemCount?; integer itemsPerPage?; integer startIndex?; integer totalItems?; integer pageIndex?; integer totalPages?; string pageLinkTemplate /^https?:/ ?; object {}* next?; string nextLink?; object {}* previous?; string previousLink?; object {}* self?; string selfLink?; object {}* edit?; string editLink?; array [ object {}*; ] items?; }* data?; object { integer code?; string message?; array [ object { string domain?; string reason?; string message?; string location?; string locationType?; string extendedHelp?; string sendReport?; }*; ] errors?; }* error?; }*; |
一些顶级保留属性名(限于篇幅,只列出少量几个):
(1) apiVersion
属性值类型:字符串
父节点:-
呈现请求中服务API期望的版本,以及在响应中保存的服务API版本。应随时提供apiVersion。这与数据的版本无关,将数据版本花应该通过其他机制来完成,比如etag。示例: {"apiVersion" : "2.1"}
(2) context
属性值类型:字符串
父节点:-
客户端设置这个值,服务器通过数据做出回应。这在JSON-P和批处理中很有用,用户可以使用context将响应与请求关联起来,该属性是顶级属性,因为不管响应是成功还是有错误,context总应该被呈现出来。context不同于id在cointext由用户提供而id由服务器分配。
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 请求 #1: http: //www.google.com/myapi?context=bart 请求 #2: http: //www.google.com/myapi?context=lisa 响应 #1: { "context" : "bart" , "data" : { "items" : [] } } 响应 #2: { "context" : "lisa" , "data" : { "items" : [] } } 公共的JavaScript处理器通过编码同时处理以下两个响应: function handleResponse(response) { if (response.result.context == "bart" ) { // 更新页面中的 "Bart" 部分。 } else if (response.result.context == "lisa" ) { // 更新页面中的 "Lisa" 部分。 } } |
(3)id
属性值类型:字符串
父节点:-
服务提供用于识别响应的标识(无论是请求成功还是有错误)。这对于将服务日志和单独收到的响应对应起来很有用。示例: {"id" : "1"}
(4)method
属性值类型:字符串
父节点:-
表示对数据即将执行或者已经被执行的动作。在JSON请求的情况下,method属性可以用来指明对数据进行何种操作。一个JSON-RPC请求的例子,其中method属性表示要在params上执行的操作:
1 2 3 4 5 6 7 | { "method" : "people.get" , "params" : { "userId" : "@me" , "groupId" : "@self" } } |
(5)params
属性值类型:对象
父节点:-
这个对象作为输入参数的映射发送给RPC请求。它可以和method属性一起用来执行RPC功能。若RPC方法不需要参数,则可以省略该属性。
1 2 3 4 5 6 7 | { "method" : "people.get" , "params" : { "userId" : "@me" , "groupId" : "@self" } } |
(6)data
属性值类型:对象
父节点:-
包含响应的所有数据。giant属性本身拥有许多保留属性名。服务可以自由的将自己的数据添加到这个对象,一个JSON响应要么应该包含一个data对象,要么应该包含一个error对象,但是不能两者都包含。如果data和error同时出现,则error对象优先。
(7)error
属性值类型:对象
父节点:-
表明错误发生,提供错误的详细信息。错误的格式支持从一个服务返回一个或多个错误。一个JSON响应可以有一个data对象或者一个error对象,但不能两者都包含。如果data和error都出现,则error优先。
1 2 3 4 5 6 7 8 9 10 11 12 | { "apiVersion" : "2.0" , "error" : { "code" : 404, "message" : "File Not Found" , "errors" : [{ "domain" : "Calendar" , "reason" : "ResourceNotFoundException" , "message" : "File Not Found }] } } |
五、示例
以下为 Youtube JSON API响应对象的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | { "apiVersion" : "2.0" , "data" : { "updated" : "2010-02-04T19:29:54.001Z" , "totalItems" : 6741, "startIndex" : 1, "itemsPerPage" : 1, "items" : [ { "id" : "BGODurRfVv4" , "uploaded" : "2009-11-17T20:10:06.000Z" , "updated" : "2010-02-04T06:25:57.000Z" , "uploader" : "docchat" , "category" : "Animals" , "title" : "From service dog to SURFice dog" , "description" : "Surf dog Ricochets inspirational video ..." , "tags" : [ "Surf dog" , "dog surfing" , "dog" , "golden retriever" , ], "thumbnail" : { "default" : "http://i.ytimg.com/vi/BGODurRfVv4/default.jpg" , "hqDefault" : "http://i.ytimg.com/vi/BGODurRfVv4/hqdefault.jpg" }, "player" : { "default" : "http://www.youtube.com/watch?v=BGODurRfVv4&feature=youtube_gdata" , "mobile" : "http://m.youtube.com/details?v=BGODurRfVv4" }, "content" : { "1" : "rtsp://v5.cache6.c.youtube.com/CiILENy73wIaGQn-Vl-0uoNjBBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp" , "5" : "http://www.youtube.com/v/BGODurRfVv4?f=videos&app=youtube_gdata" , "6" : "rtsp://v7.cache7.c.youtube.com/CiILENy73wIaGQn-Vl-0uoNjBBMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp" }, "duration" : 315, "rating" : 4.96, "ratingCount" : 2043, "viewCount" : 1781691, "favoriteCount" : 3363, "commentCount" : 1007, "commentsAllowed" : true } ] } } |
分页示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | { "apiVersion" : "2.1" , "id" : "1" , "data" : { "query" : "chicago style pizza" , "time" : "0.1" , "currentItemCount" : 10, "itemsPerPage" : 10, "startIndex" : 11, "totalItems" : 2700000, "nextLink" : "http://www.google.com/search?hl=en&q=chicago+style+pizza&start=20&sa=N" "previousLink" : "http://www.google.com/search?hl=en&q=chicago+style+pizza&start=0&sa=N" , "pagingLinkTemplate" : "http://www.google.com/search/hl=en&q=chicago+style+pizza&start={index}&sa=N" , "items" : [ { "title" : "Pizz'a Chicago Home Page" // More fields for the search results } // More search results ] } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】博客园2025新款「AI繁忙」系列T恤上架,前往周边小店选购
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步