|
3 | 3 | <a href=https://github.com/protocolbuffers/protocolbuffers.github.io/edit/main/content/programming-guides/json.md class=td-page-meta--edit target=_blank rel=noopener><i class="fa-solid fa-pen-to-square fa-fw"></i> Edit this page</a> |
4 | 4 | <a href="https://github.com/protocolbuffers/protocolbuffers.github.io/new/main/content/programming-guides/json.md?filename=change-me.md&value=---%0Atitle%3A+%22Long+Page+Title%22%0AlinkTitle%3A+%22Short+Nav+Title%22%0Aweight%3A+100%0Adescription%3A+%3E-%0A+++++Page+description+for+heading+and+indexes.%0A---%0A%0A%23%23+Heading%0A%0AEdit+this+template+to+create+your+new+page.%0A%0A%2A+Give+it+a+good+name%2C+ending+in+%60.md%60+-+e.g.+%60getting-started.md%60%0A%2A+Edit+the+%22front+matter%22+section+at+the+top+of+the+page+%28weight+controls+how+its+ordered+amongst+other+pages+in+the+same+directory%3B+lowest+number+first%29.%0A%2A+Add+a+good+commit+message+at+the+bottom+of+the+page+%28%3C80+characters%3B+use+the+extended+description+field+for+more+detail%29.%0A%2A+Create+a+new+branch+so+you+can+preview+your+new+file+and+request+a+review+via+Pull+Request.%0A" class=td-page-meta--child target=_blank rel=noopener><i class="fa-solid fa-pen-to-square fa-fw"></i> Create child page</a> |
5 | 5 | <a href="https://github.com/protocolbuffers/protocolbuffers.github.io/issues/new?title=ProtoJSON%20Format" class=td-page-meta--issue target=_blank rel=noopener><i class="fa-solid fa-list-check fa-fw"></i> Create documentation issue</a> |
6 | | -<a href=https://github.com/protocolbuffers/protobuf/issues/new class=td-page-meta--project-issue target=_blank rel=noopener><i class="fa-solid fa-list-check fa-fw"></i> Create project issue</a></div><div class=td-toc><nav id=TableOfContents><ul><li><a href=#non-goals-arbitrary-json-schema>Cannot Represent Some JSON schemas</a></li><li><a href=#non-goals-highly-efficient>Not as efficient as the binary wire format</a></li><li><a href=#non-goals-optimal-schema-evolution>Does not have as good schema-evolution guarantees as binary wire format</a></li></ul><ul><li><a href=#field-representation>Representation of each type</a></li><li><a href=#field-names>Field names as JSON keys</a></li><li><a href=#presence>Presence and default-values</a></li><li><a href=#null-values>Null values</a></li><li><a href=#duplicate-values>Duplicate values</a></li><li><a href=#out-of-range-numeric-values>Out of range numeric values</a></li><li><a href=#any>Any</a><ul><li><a href=#any-normal-messages>Normal messages</a></li><li><a href=#any-special-cases>Special-cased well-known types</a></li></ul></li><li><a href=#json-wire-safety>ProtoJSON Wire Safety</a><ul><li><a href=#wire-unsafe>JSON Wire-unsafe Changes</a></li><li><a href=#wire-safe>JSON Wire-safe Changes</a></li><li><a href=#conditionally-safe>JSON Wire-compatible Changes (Conditionally safe)</a></li></ul></li><li><a href=#rfc3339>RFC 3339 Clarifications</a><ul><li><a href=#rfc3339-timestamp>Timestamps</a></li><li><a href=#rfc3339-duration>Durations</a></li></ul></li><li><a href=#json-options>JSON Options</a></li></ul></nav></div></aside><main class="col-12 col-md-9 col-xl-8 ps-md-5" role=main><nav aria-label=breadcrumb class=td-breadcrumbs><ol class=breadcrumb><li class=breadcrumb-item><a href=/programming-guides/>Programming Guides</a></li><li class="breadcrumb-item active" aria-current=page>ProtoJSON Format</li></ol></nav><div class=td-content><h1>ProtoJSON Format</h1><div class=lead>Covers how to use the Protobuf to JSON conversion utilities.</div><header class=article-meta></header><p>Protobuf supports a canonical encoding in JSON, making it easier to share data |
| 6 | +<a href=https://github.com/protocolbuffers/protobuf/issues/new class=td-page-meta--project-issue target=_blank rel=noopener><i class="fa-solid fa-list-check fa-fw"></i> Create project issue</a></div><div class=td-toc><nav id=TableOfContents><ul><li><a href=#non-goals>Non-goals of the Format</a><ul><li><a href=#non-goals-arbitrary-json-schema>Cannot Represent Some JSON schemas</a></li><li><a href=#non-goals-highly-efficient>Not as efficient as the binary wire format</a></li><li><a href=#non-goals-optimal-schema-evolution>Does not have as good schema-evolution guarantees as binary wire format</a></li></ul></li><li><a href=#format>Format Description</a><ul><li><a href=#field-representation>Representation of each type</a></li><li><a href=#field-names>Field names as JSON keys</a></li><li><a href=#presence>Presence and default-values</a></li><li><a href=#null-values>Null values</a></li><li><a href=#duplicate-values>Duplicate values</a></li><li><a href=#out-of-range-numeric-values>Out of range numeric values</a></li></ul></li><li><a href=#any>Any</a><ul><li><a href=#any-normal-messages>Normal messages</a></li><li><a href=#any-special-cases>Special-cased well-known types</a></li></ul></li><li><a href=#json-wire-safety>ProtoJSON Wire Safety</a><ul><li><a href=#wire-unsafe>JSON Wire-unsafe Changes</a></li><li><a href=#wire-safe>JSON Wire-safe Changes</a></li><li><a href=#conditionally-safe>JSON Wire-compatible Changes (Conditionally safe)</a></li></ul></li><li><a href=#rfc3339>RFC 3339 Clarifications</a><ul><li><a href=#rfc3339-timestamp>Timestamps</a></li><li><a href=#rfc3339-duration>Durations</a></li></ul></li><li><a href=#json-options>JSON Options</a></li></ul></nav></div></aside><main class="col-12 col-md-9 col-xl-8 ps-md-5" role=main><nav aria-label=breadcrumb class=td-breadcrumbs><ol class=breadcrumb><li class=breadcrumb-item><a href=/programming-guides/>Programming Guides</a></li><li class="breadcrumb-item active" aria-current=page>ProtoJSON Format</li></ol></nav><div class=td-content><h1>ProtoJSON Format</h1><div class=lead>Covers how to use the Protobuf to JSON conversion utilities.</div><header class=article-meta></header><p>Protobuf supports a canonical encoding in JSON, making it easier to share data |
7 | 7 | with systems that do not support the standard protobuf binary wire format.</p><p>This page specifies the format, but a number of additional edge cases which |
8 | 8 | define a conformant ProtoJSON parser are covered in the Protobuf Conformance |
9 | | -Test Suite and are not exhaustively detailed here.</p><h1 id=non-goals>Non-goals of the Format</h1><h2 id=non-goals-arbitrary-json-schema>Cannot Represent Some JSON schemas</h2><p>The ProtoJSON format is designed to be a JSON representation of schemas which |
| 9 | +Test Suite and are not exhaustively detailed here.</p><h2 id=non-goals>Non-goals of the Format</h2><h3 id=non-goals-arbitrary-json-schema>Cannot Represent Some JSON schemas</h3><p>The ProtoJSON format is designed to be a JSON representation of schemas which |
10 | 10 | are expressible in the Protobuf schema language.</p><p>It may be possible to represent many pre-existing JSON schemas as a Protobuf |
11 | 11 | schema and parse it using ProtoJSON, but it is not designed to be able to |
12 | 12 | represent arbitrary JSON schemas.</p><p>For example, there is no way to express in Protobuf schema to write types that |
13 | 13 | may be common in JSON schemas like <code>number[][]</code> or <code>number|string</code>.</p><p>It is possible to use <code>google.protobuf.Struct</code> and <code>google.protobuf.Value</code> types |
14 | 14 | to allow arbitrary JSON to be parsed into a Protobuf schema, but these only |
15 | | -allow you to capture the values as schemaless unordered key-value maps.</p><h2 id=non-goals-highly-efficient>Not as efficient as the binary wire format</h2><p>ProtoJSON Format is not as efficient as binary wire format and never will be.</p><p>The converter uses more CPU to encode and decode messages and (except in rare |
16 | | -cases) encoded messages consume more space.</p><h2 id=non-goals-optimal-schema-evolution>Does not have as good schema-evolution guarantees as binary wire format</h2><p>ProtoJSON format does not support unknown fields, and it puts field and enum |
| 15 | +allow you to capture the values as schemaless unordered key-value maps.</p><h3 id=non-goals-highly-efficient>Not as efficient as the binary wire format</h3><p>ProtoJSON Format is not as efficient as binary wire format and never will be.</p><p>The converter uses more CPU to encode and decode messages and (except in rare |
| 16 | +cases) encoded messages consume more space.</p><h3 id=non-goals-optimal-schema-evolution>Does not have as good schema-evolution guarantees as binary wire format</h3><p>ProtoJSON format does not support unknown fields, and it puts field and enum |
17 | 17 | value names into encoded messages which makes it much harder to change those |
18 | 18 | names later. Removing fields is a breaking change that will trigger a parsing |
19 | | -error.</p><p>See <a href=#json-wire-safety>JSON Wire Safety</a> below for more details.</p><h1 id=format>Format Description</h1><h2 id=field-representation>Representation of each type</h2><p>The following table shows how data is represented in JSON files.</p><table><thead><tr><th>Protobuf type</th><th>JSON</th><th>JSON example</th><th>Notes</th></tr></thead><tbody><tr><td>message</td><td>object</td><td><code>{"fooBar": v, "g": null, ...}</code></td><td>Generates JSON objects.<p>Keys are serialized as lowerCamelCase of field name. See |
| 19 | +error.</p><p>See <a href=#json-wire-safety>JSON Wire Safety</a> below for more details.</p><h2 id=format>Format Description</h2><h3 id=field-representation>Representation of each type</h3><p>The following table shows how data is represented in JSON files.</p><table><thead><tr><th>Protobuf type</th><th>JSON</th><th>JSON example</th><th>Notes</th></tr></thead><tbody><tr><td>message</td><td>object</td><td><code>{"fooBar": v, "g": null, ...}</code></td><td>Generates JSON objects.<p>Keys are serialized as lowerCamelCase of field name. See |
20 | 20 | <a href=#field-names>Field Names</a> for more special cases regarding mapping of field names |
21 | 21 | to object keys.<p>Well-known types have special representations, as described in the <a href=#wkt>Well-known types table</a>.<p><code>null</code> is valid for any field and leaves the field unset. See <a href=null-values>Null Values</a> for clarification about the semantic behavior of null values.</td></tr><tr><td>enum</td><td>string</td><td><code>"FOO_BAR"</code></td><td>The name of the enum value as specified in proto is used. Parsers |
22 | 22 | accept both enum names and integer values.</td></tr><tr><td>map<K,V></td><td>object</td><td><code>{"k": v, ...}</code></td><td>All keys are converted to strings (object keys in JSON can only be strings).</td></tr><tr><td>repeated V</td><td>array</td><td><code>[v, ...]</code></td><td></td></tr><tr><td>bool</td><td>true, false</td><td><code>true, false</code></td><td></td></tr><tr><td>string</td><td>string</td><td><code>"Hello World!"</code></td><td></td></tr><tr><td>bytes</td><td>base64 string</td><td><code>"YWJjMTIzIT8kKiYoKSctPUB+"</code></td><td>JSON value will be the data encoded as a string using standard base64 |
|
40 | 40 | type, except that <code>null</code> is allowed and preserved during data |
41 | 41 | conversion and transfer.</td></tr><tr><td>FieldMask</td><td>string</td><td><code>"f.fooBar,h"</code></td><td>See <code>field_mask.proto</code>.</td></tr><tr><td>ListValue</td><td>array</td><td><code>[foo, bar, ...]</code></td><td></td></tr><tr><td>Value</td><td>value</td><td></td><td>Any JSON value. Check |
42 | 42 | <a href=/reference/protobuf/google.protobuf#value>google.protobuf.Value</a> |
43 | | -for details.</td></tr><tr><td>NullValue</td><td>null</td><td></td><td>JSON null. Special case of the <a href=#null-values>null parsing behavior</a>.</td></tr><tr><td>Empty</td><td>object</td><td><code>{}</code> <b>(not special cased)</b></td><td>An empty JSON object</td></tr></tbody></table><h2 id=field-names>Field names as JSON keys</h2><p>Message field names are mapped to lowerCamelCase to be used as JSON object keys. |
| 43 | +for details.</td></tr><tr><td>NullValue</td><td>null</td><td></td><td>JSON null. Special case of the <a href=#null-values>null parsing behavior</a>.</td></tr><tr><td>Empty</td><td>object</td><td><code>{}</code> <b>(not special cased)</b></td><td>An empty JSON object</td></tr></tbody></table><h3 id=field-names>Field names as JSON keys</h3><p>Message field names are mapped to lowerCamelCase to be used as JSON object keys. |
44 | 44 | If the <code>json_name</code> field option is specified, the specified value will be used |
45 | 45 | as the key instead.</p><p>Parsers accept both the lowerCamelCase name (or the one specified by the |
46 | 46 | <code>json_name</code> option) and the original proto field name. This allows for a |
|
49 | 49 | back by all spec parsers.</p><p><code>\0 (nul)</code> is not allowed within a <code>json_name</code> value. For more on why, see |
50 | 50 | <a href=/news/2023-04-28#json-name>Stricter validation |
51 | 51 | for json_name</a>. Note that <code>\0</code> is still considered a legal character within |
52 | | -the value of a <code>string</code> field.</p><h2 id=presence>Presence and default-values</h2><p>When generating JSON-encoded output from a protocol buffer, if a field supports |
| 52 | +the value of a <code>string</code> field.</p><h3 id=presence>Presence and default-values</h3><p>When generating JSON-encoded output from a protocol buffer, if a field supports |
53 | 53 | presence, serializers must emit the field value if and only if the corresponding |
54 | 54 | hazzer would return true.</p><p>If the field doesn’t support field presence and has the default value (for |
55 | 55 | example any empty repeated field) serializers should omit it from the output. An |
56 | 56 | implementation may provide options to include fields with default values in the |
57 | | -output.</p><h2 id=null-values>Null values</h2><p>Serializers should not emit <code>null</code> values.</p><p>Parsers accept <code>null</code> as a legal value for any field, with the following |
| 57 | +output.</p><h3 id=null-values>Null values</h3><p>Serializers should not emit <code>null</code> values.</p><p>Parsers accept <code>null</code> as a legal value for any field, with the following |
58 | 58 | behavior:</p><ul><li>Any key validity checking should still occur (disallowing unknown fields).</li><li>The field should remain unset, as though it was not present in the input at |
59 | 59 | all (hazzers should still return false where applicable).</li></ul><p>The implication of this is that a <code>null</code> value for an implicit presence field |
60 | 60 | will behave the identically to the behavior to the default value of that field, |
|
64 | 64 | handled as a sentinel-present value for this type, and so a field of this type |
65 | 65 | must be handled by serializers and parsers under the standard presence behavior. |
66 | 66 | This behavior correspondingly allows <code>google.protobuf.Struct</code> and |
67 | | -<code>google.protobuf.Value</code> to losslessly round trip arbitrary JSON.</p><h2 id=duplicate-values>Duplicate values</h2><p>Serializers must never serialize the same field multiple times, nor multiple |
| 67 | +<code>google.protobuf.Value</code> to losslessly round trip arbitrary JSON.</p><h3 id=duplicate-values>Duplicate values</h3><p>Serializers must never serialize the same field multiple times, nor multiple |
68 | 68 | different cases in the same oneof in the same JSON object.</p><p>Parsers should accept the same field being duplicated, and the last value |
69 | 69 | provided should be retained. This also applies to “alternate spellings” of the |
70 | 70 | same field name.</p><p>If implementations cannot maintain the necessary information about field order |
71 | 71 | it is preferred to reject inputs with duplicate keys rather than have an |
72 | 72 | arbitrary value win. In some implementations maintaining field order of objects |
73 | 73 | may be impractical or infeasible, so it is strongly recommended that systems |
74 | 74 | avoid relying on specific behavior for duplicate fields in ProtoJSON where |
75 | | -possible.</p><h2 id=out-of-range-numeric-values>Out of range numeric values</h2><p>When parsing a numeric value, if the number that is is parsed from the wire |
| 75 | +possible.</p><h3 id=out-of-range-numeric-values>Out of range numeric values</h3><p>When parsing a numeric value, if the number that is is parsed from the wire |
76 | 76 | doesn’t fit in the corresponding type, the parser should fail to parse.</p><p>This includes any negative number for <code>uint32</code>, and numbers less than <code>INT_MIN</code> |
77 | 77 | or larger than <code>INT_MAX</code> for <code>int32</code>.</p><p>Values with nonzero fractional portions are not allowed for integer-typed |
78 | 78 | fields. Zero fractional portions are accepted. For example <code>1.0</code> is valid for an |
|
0 commit comments