JSON风格指南

分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow

也欢迎大家转载本篇文章。分享知识,造福人民,实现我们中华民族伟大复兴!

               

https://github.com/darcyliu/google-styleguide/blob/master/JSONStyleGuide.md

JSON风格指南

版本:0.9

英文版:http://google-styleguide.googlecode.com/svn/trunk/jsoncstyleguide.xml

翻译:Darcy Liu

译文状态:草稿

简介

该风格指南是对在Google创建JSON APIs而提供的指导性准则和建议。总体来讲,JSON APIs应遵循JSON.org上的规范。这份风格指南澄清和标准化了特定情况,从而使Google的JSON APIs有一种标准的外观和感觉。这些指南适用于基于RPC和基于REST风格的API的JSON请求和响应。

定义

为了更好地实现这份风格指南的目的,下面几项需要说明:

  • 属性(property) - JSON对象内的键值对(name/value pair)
  • 属性名(property name) - 属性的名称(或键)
  • 属性值(property value) - 分配给属性的值

示例:

// 一组键值对称作一个 "属性""propertyName": "propertyValue"}

Javascript的数字(*number*)包含所有的浮点数,这是一个宽泛的指定。在这份指南中,数字(*number*)指代Javascript中的数字(*number*)类型,而整型(*integer*)则指代整型。

一般准则

注释

JSON对象中不包含注释。

JSON对象中不应该包含注释。该指南中的某些示例含有注释。但这仅仅是为了说明示例。

// 你可能在下面的示例中看到注释,  // 但不要在你的JSON数据中加入注释.  "propertyName": "propertyValue"}

双引号

使用双引号

如果(某个)属性需要引号,则必须使用双引号。所有的属性名必须在双引号内。字符类型的属性值必须使用双引号。其它类型值(如布尔或数字)不应该使用双引号。

扁平化数据 VS 结构层次

不能为了方便而将数据任意分组

JSON中的数据元素应以*扁平化*方式呈现。不能为了方便而将数据任意分组。

在某些情况下,比如描述单一结构的一批属性,因为它被用来保持结构层次,因而是有意义的。但是遇到这些情况还是应当慎重考虑,记住只有语义上有意义的时候才使用它。例如,一个地址可以有表示两种方式,但结构化的方式对开发人员来讲可能更有意义:

扁平化地址:

"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"  }}

属性名准则

属性名格式

选择有意义的属性名

属性名必须遵循以下准则:

  • 属性名应该是具有定义语义的有意义的名称。
  • 属性名必须是驼峰式的,ASCII码字符串。
  • 首字符必须式字母,下划线(*_*)或美元符号(*$*)。
  • 随后的其他字符可以是字母,数字,下划线(*_*)或美元符号(*$*)。
  • 应该避免使用Javascript中的保留关键字(下文附有Javascript保留字清单)

这些准则反映JavaScript标识符命名的指导方针。使JavaScript的客户端可以使用点符号来访问属性。(例如,result.thisIsAnInstanceVariable).

下面是一个对象的一个属性的例子:

"thisPropertyIsAnIdentifier": "identifier value"}

JSON Map中的键名

在JSON Map中键名可以使用任意Unicode字符

当JSON对象作为Map(映射)使用时,属性的名称命名规则并不适用。Map(也称作关联数组)是一个具有任意键/值对的数据类型,这些键/值对通过特定的键来访问相应的值。JSON对象和JSON Map在运行时看起来是一样的;这个特性与API设计相关。当JSON对象被当作map使用时,API文件应当做出说明。

Map的键名不一定要遵循属性名称的命名准则。键名可以包含任意的Unicode字符。客户端可使用maps熟悉的方括号来访问这些属性。(例如result.thumbnails["72"]

// "address" 属性是一个子对象  // 包含地址的各部分.  "address": {    "addressLine1": "123 Anystreet",    "city": "Anytown",    "state": "XX",    "zip": "00000"  },  // "address" 是一个映射  // 含有响应规格所对应的URL,用来映射thumbnail url的像素规格  "thumbnails": {    "72": "http://url.to.72px.thumbnail",    "144": "http://url.to.144px.thumbnail"  }}

保留的属性名称

某些属性名称会被保留以便能在多个服务间相容使用

保留属性名称的详细信息,连同完整的列表,可在本指南后面的内容中找到。服务应按照被定义的语义来使用属性名称。

单数属性名 VS 复数属性名

数组类型应该是复数属性名。其它属性名都应该是单数。

数组通常包含多个条目,复数属性名就反映了这点。在下面这个保留名称中可以看到例子。属性名*items*是复数因为它描述的是一组对象。大多数的其它字段是单数。

当然也有例外,尤其是涉及到数字的属性值的时候。例如,在保留属性名中,*totalItems* 比 totalItem更合理。然后,从技术上讲,这并不违反风格指南,因为 totalItems 可以被看作 totalOfItems, 其中 total 是单数(依照风格指南),*OfItems* 用来限定总数。字段名也可被改为 itemCount,这样看起来更象单数.

// 单数  "author": "lisa"// 一组同胞, 复数  "siblings": [ "bart", "maggie"],  // "totalItem" 看起来并不对  "totalItems": 10//"itemCount" 要好些  "itemCount": 10,}

命名冲突

通过选择新的属性名或将API版本化来避免命名冲突

新的属性可在将来被添加进保留列表中。JSON中不存在命名空间。如果存在命名冲突,可通过选择新的属性名或者版本化来解决这个问题。例如,假设我们由下面的JSON对象开始:

"apiVersion": "1.0""data": {    "recipeName": "pizza",    "ingredients": ["tomatoes", "cheese", "sausage"]  }}

如果我们希望将来把*ingredients*列为保留字,我们可以通过下面两件事情来达成。 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"]  }}

属性值准则

属性值格式

属性值必须是Unicode 的 booleans(布尔), 数字(numbers), 字符串(strings), 对象(objects), 数组(arrays), 或 null.

JSON.org上的标准准确的说明了哪些类型的数据可以作为属性值。这包含Unicode的布尔(booleans), 数字(numbers), 字符串(strings), 对象(objects), 数组(arrays), 或 null。JavaScript表达式是不被接受的。APIs应该支持该准则,并为某个特定的属性选择最合适的数据类型(比如,用numbers代表numbers等)。

好的例子:

"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 函数}

空或Null 属性值

考虑移除空或null值

如果一个属性是可选的或者包含空值或*null*值,考虑从JSON中去掉该属性,除非它的存在有很强的语义原因。

"volume": 10,  // 即使 "balance" 属性值是零, 它也应当被保留,  // 因为 "0" 表示 "均衡"   // "-1" 表示左倾斜和"+1" 表示右倾斜  "balance": 0,  // "currentlyPlaying" 是null的时候可被移除  // "currentlyPlaying": null}

枚举值

枚举值应当以字符串的形式呈现

随着APIs的发展,枚举值可能被添加,移除或者改变。将枚举值当作字符串可以使下游用户幽雅的处理枚举值的变更。

Java代码:

public enum Color WHITEBLACKREDYELLOWBLUE}

JSON对象:

"color": "WHITE"}

属性值数据类型

上面提到,属性值必须是布尔(booleans), 数字(numbers), 字符串(strings), 对象(objects), 数组(arrays), 或 null. 然而在处理某些值时,定义一组标准的数据类型是非常有用的。这些数据类型必须始终是字符串,但是为了便于解析,它们也会以特定的方式被格式化。

日期属性值

日期应该使用RFC3339建议的格式

日期应该是RFC 3339所建议的字符串格式。

"lastUpdate": "2007-11-06T16:34:41.000Z"}

时间间隔属性值

时间间隔应该使用ISO 8601建议的格式

时间间隔应该是ISO 8601所建议的字符串格式。

// 三年, 6个月, 4天, 12小时,  // 三十分钟, 5秒  "duration": "P3Y6M4DT12H30M5S"}

纬度/经度属性值

纬度/经度应该使用ISO 6709建议的格式

纬度/经度应该是ISO 6709所建议的字符串格式。 而且, 它应该更偏好使用 e ±DD.DDDD±DDD.DDDD 角度格式.

// 自由女神像的纬度/经度位置.  "statueOfLiberty": "+40.6894-074.0447"}

JSON结构和保留属性名

为了使APIs保持一致的借口,JSON对象应当使用以下的结构。该结构适用于JSON的请求和响应。在这个结构中,某些属性名将被保留用作特殊用途。这些属性并不是必需的,也就是说,每个保留的属性可能出现零次或一次。但是如果服务需要这些属性,建议遵循该命名条约。下面是一份JSON结构语义表,以Orderly格式呈现(现在已经被纳入 JSONSchema)。你可以在该指南的最后找到关于JSON结构的例子。

objectstring 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?;}*;

JSON对象有一些顶级属性,然后是*data*对象或*error*对象,这两者不会同时出现。下面是这些属性的解释。

顶级保留属性名称

顶级的JSON对象可能包含下面这些属性

apiVersion

属性值类型: 字符串(string)父节点: -

呈现请求中服务API期望的版本,以及在响应中保存的服务API版本。应随时提供*apiVersion*。这与数据的版本无关。将数据版本化应该通过其他的机制来处理,如etag。

示例:

{ "apiVersion": "2.1" }

context

属性值类型: 字符串(string)父节点: -

客户端设置这个值,服务器通过数据作出回应。这在JSON-P和批处理中很有用,用户可以使用*context*将响应与请求关联起来。该属性是顶级属性,因为不管响应是成功还是有错误,*context*总应当被呈现出来。*context*不同于*id*在于*context*由用户提供而*id*由服务分配。

示例:

请求 #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" 部分。  }}

id

属性值类型: 字符串(string)父节点: -

服务提供用于识别响应的标识(无论请求是成功还是有错误)。这对于将服务日志和单独收到的响应对应起来很有用。

示例:

{ "id": "1" }

method

属性值类型: 字符串(string)父节点: -

表示对数据即将执行,或已被执行的操作。在JSON请求的情况下,*method*属性可以用来指明对数据进行何种操作。在JSON响应的情况下,*method*属性表明对数据进行了何种操作。

一个JSON-RPC请求的例子,其中*method*属性表示要在*params*上执行的操作:

"method": "people.get""params": {    "userId": "@me",    "groupId": "@self"  }}

params

属性值类型: 对象(object)父节点: -

这个对象作为输入参数的映射发送给RPC请求。它可以和*method*属性一起用来执行RPC功能。若RPC方法不需要参数,则可以省略该属性。

示例:

"method": "people.get""params": {    "userId": "@me",    "groupId": "@self"  }}

data

属性值类型: 对象(object)父节点: -

包含响应的所有数据。该属性本身拥有许多保留属性名,下面会有相应的说明。服务可以自由地将自己的数据添加到这个对象。一个JSON响应要么应当包含一个*data*对象,要么应当包含*error*对象,但不能两者都包含。如果*data*和*error*同时出现,则*error*对象优先。

error

属性值类型: 对象(object)父节点: -

表明错误发生,提供错误的详细信息。错误的格式支持从服务返回一个或多个错误。一个JSON响应可以有一个*data*对象或者一个*error*对象,但不能两者都包含。如果*data*和*error*都出现,*error*对象优先。

示例:

"apiVersion": "2.0""error": {    "code": 404,    "message": "File Not Found",    "errors": [{      "domain": "Calendar",      "reason": "ResourceNotFoundException",      "message": "File Not Found    }]  }}

data对象的保留属性名

JSON对象的*data*属性可能包含以下属性。

data.kind

属性值类型: 字符串(sting)父节点: data

kind属性是对某个特定的对象存储何种类型的信息的指南。可以把它放在*data*层次,或*items*的层次,或其它任何有助于区分各类对象的对象中。如果*kind*对象被提供,它应该是对象的第一个属性(详见下面的_属性顺序_部分)。

示例:

// "Kind" indicates an "album" in the Picasa API.{"data": {"kind": "album"}}

data.fields

属性值类型: 字符串(string)父节点: data

表示做了部分GET之后响应中出现的字段,或做了部分PATCH之后出现在请求中的字段。该属性仅在做了部分GET请求/批处理时存在,且不能为空。

示例:

"data": {    "kind": "user",    "fields": "author,id",    "id": "bart",    "author": "Bart"  }}   

data.etag

属性值类型: 字符串(string)父节点: data

响应时提供etag。关于GData APIs中的ETags详情可以在这里找到:http://code.google.com/apis/gdata/docs/2.0/reference.html#ResourceVersioning

示例:

{"data": {"etag": "W/"C0QBRXcycSp7ImA9WxRVFUk.""}}

data.id

属性值类型: 字符串(string)父节点: data

一个全局唯一标识符用于引用该对象。*id*属性的具体细节都留给了服务。

示例:

{"data": {"id": "12345"}}

data.lang

属性值类型: 字符串(string)(格式由BCP 47指定)父节点: data (或任何子元素)

表示该对象内其他属性的语言。该属性模拟HTML的*lang*属性和XML的*xml:lang*属性。值应该时BCP 47中定义的一种语言值。如果一个单一的JSON对象包含的数据有多种语言,服务负责制定和标明的lang属性的适当位置。

示例:

{"data": {  "items": [    { "lang": "en",      "title": "Hello world!" },    { "lang": "fr",      "title": "Bonjour monde!" }  ]}}

data.updated

属性值类型: 字符串(string)(格式由RFC 3339指定)父节点: data

指明条目更新的最后日期/时间(RFC 3339),由服务规定。

示例:

{"data": {"updated": "2007-11-06T16:34:41.000Z"}}

data.deleted

属性值类型: 布尔(boolean)父节点: data (或任何子元素)

一个标记元素,当出现时,表示包含的条目已被删除。如果提供了删除属性,它的值必须为*true*;为*false*会导致混乱,应该避免。

示例:

{"data": {  "items": [    { "title": "A deleted entry",      "deleted": true    }  ]}}

data.items

属性值类型: 数组(array)父节点: data

属性名*items*被保留用作表示一组条目(例如,Picasa中的图片,YouTube中的视频)。这种结构的目的是给与当前结果相关的集合提供一个标准位置。例如,知道页面上的*items*是数组,JSON输出便可能插入一个通用的分页系统。如果*items*存在,它应该是*data*对象的最后一个属性。(详见下面的_属性顺序_部分)。

示例:

"data": {    "items": [      { /* Object #1 */ },      { /* Object #2 */ },      ...    ]  }}

用于分页的保留属性名

下面的属性位于*data*对象中,用来给一列数据分页。一些语言和概念是从OpenSearch规范中借鉴过来的。

下面的分页数据允许各种风格的分页,包括:

  • 上一页/下一页 - 允许用户在列表中前进和后退,一次一页。*nextLink* 和*previousLink*属性 (下面的"链接保留属性名"部分有描述) 用于这种风格的分页。
  • 基于索引的分页 - 允许用户直接跳到条目列表的某个条目位置。例如,要从第200个条目开始载入10个新的条目,开发者可以给用户提供一个URL的查询字符串*?startIndex=200*。
  • 基于页面的分页 - 允许用户直接跳到条目内的具体页。这跟基于索引的分页很类似,但节省了开发者额外的步骤,不需再为新一页的条目计算条目索引。例如,开发人员可以直接跳到第20页,而不是跳到第200条条目。基于页面分页的网址,可以使用查询字符串*?page=1*或*?page=20*。*pageIndex*和 totalPages 属性用作这种风格的分页.

在这份指南的最后可以找到如何使用这些属性来实现分页的例子。

data.currentItemCount

属性值类型: 整数(integer)父节点: data

结果集中的条目数目。应该与items.length相等,并作为一个便利属性提供。例如,假设开发者请求一组搜索条目,并且要求每页10条。查询集共有14条。第一个条目页将会有10个条目,因此*itemsPerPage*和*currentItemCount*都应该等于10。下一页的条目还剩下4条;*itemsPerPage*仍然是10,但是*currentItemCount*是4.

示例:

"data": {    // "itemsPerPage" 不需要与 "currentItemCount" 匹配    "itemsPerPage": 10,    "currentItemCount": 4  }}

data.itemsPerPage

属性值类型: 整数(integer)父节点: data

items结果的数目。未必是data.items数组的大小;如果我们查看的是最后一页,data.items的大小可能小于*itemsPerPage*。但是,data.items的大小不应超过*itemsPerPage*。

示例:

"data": {    "itemsPerPage": 10  }}

data.startIndex

属性值类型: 整数(integer)父节点: data

data.items中第一个条目的索引。为了一致,*startIndex*应从1开始。例如,第一组items中第一条的*startIndex*应该是1。如果用户请求下一组数据,*startIndex*可能是10。

示例:

"data": {    "startIndex": 1  }}

data.totalItemsx

属性值类型: 整数(integer)父节点: data

当前集合中可用的总条目数。例如,如果用户有100篇博客文章,响应可能只包含10篇,但是*totalItems*应该是100。

示例:

"data": {    "totalItems": 100  }}

data.pagingLinkTemplate

属性值类型: 字符串(string)父节点: data

URL模板指出用户可以如何计算随后的分页链接。URL模板中也包含一些保留变量名:表示要载入的条目的*{index}*,和要载入的页面的*{pageIndex}*。

示例:

"data": {    "pagingLinkTemplate": "http://www.google.com/search/hl=en&q=chicago+style+pizza&start={index}&sa=N"  }}

data.pageIndex

属性值类型: 整数(integer)父节点: data

条目的当前页索引。为了一致,*pageIndex*应从1开始。例如,第一页的*pageIndex*是1。*pageIndex*也可以通过基于条目的分页而计算出来*pageIndex = floor(startIndex / itemsPerPage) + 1*。

示例:

"data": {    "pageIndex": 1  }}

data.totalPages

属性值类型: 整数(integer)父节点: data

当前结果集中的总页数。*totalPages*也可以通过上面基于条目的分页属性计算出来: totalPages = ceiling(totalItems / itemsPerPage).

示例:

"data": {    "totalPages": 50  }}

用于链接的保留属性名

下面的属性位于*data*对象中,用来表示对其他资源的引用。有两种形式的链接属性:1)对象,它可以包含任何种类的引用(比如JSON-RPC对象),2)URL字符串,表示资源的URIs(后缀总为'Link')。

data.self / data.selfLink

属性值类型: 对象(object)/字符串(string)父节点: data

自身链接可以用于取回条目数据。比如,在用户的Picasa相册中,条目中的每个相册对象都会包含一个*selfLink*用于检索这个相册的相关数据。

示例:

"data": {    "self": { },    "selfLink": "http://www.google.com/feeds/album/1234"  }}

data.edit / data.editLink

属性值类型: 对象(object)/字符串(string)父节点: data

编辑链接表明用户可以发送更新或删除请求。这对于REST风格的APIs很有用。该链接仅在用户能够更新和删除该条目时提供。

示例:

"data": {    "edit": { },    "editLink": "http://www.google.com/feeds/album/1234/edit"  }}

data.next / data.nextLink

属性值类型: 对象(object)/字符串(string)父节点: data

该下一页链接标明如何取得更多数据。它指明载入下一组数据的位置。它可以同*itemsPerPage*,*startIndex* 和 totalItems 属性一起使用用于分页数据。

示例:

"data": {    "next": { },    "nextLink": "http://www.google.com/feeds/album/1234/next"  }}

data.previous / data.previousLink

属性值类型: 对象(object)/字符串(string)父节点: data

该上一页链接标明如何取得更多数据。它指明载入上一组数据的位置。它可以连同*itemsPerPage*,*startIndex* 和 totalItems 属性用于分页数据。

示例:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值