Skip to content

Commit e6b6ded

Browse files
committed
Docs: Rephrased the Usage section around the concept of valid messages
1 parent 0d8100b commit e6b6ded

File tree

1 file changed

+59
-49
lines changed

1 file changed

+59
-49
lines changed

README.md

+59-49
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ Contents
1414
* [Usage](#usage)<br />
1515
A brief introduction to using the toolset.
1616

17+
* [Valid Message](#valid-message)
18+
* [Toolset](#toolset)
19+
20+
1721
* [Examples](#examples)<br />
1822
A few examples to get you started.
1923

@@ -59,39 +63,41 @@ $> npm install protobufjs [--save --save-prefix=~]
5963
var protobuf = require("protobufjs");
6064
```
6165

66+
**Note** that this library's versioning scheme is not semver-compatible for historical reasons. For guaranteed backward compatibility, always depend on `~6.A.B` instead of `^6.A.B` (hence the `--save-prefix` above).
67+
6268
### Browsers
6369

6470
Development:
71+
6572
```
6673
<script src="//cdn.rawgit.com/dcodeIO/protobuf.js/6.X.X/dist/protobuf.js"></script>
6774
```
6875

6976
Production:
77+
7078
```
7179
<script src="//cdn.rawgit.com/dcodeIO/protobuf.js/6.X.X/dist/protobuf.min.js"></script>
7280
```
7381

74-
**NOTE:** Remember to replace the version tag with the exact [release](https://github.com/dcodeIO/protobuf.js/tags) your project depends upon.
82+
**Remember** to replace the version tag with the exact [release](https://github.com/dcodeIO/protobuf.js/tags) your project depends upon.
7583

76-
The `protobuf` namespace will always be available globally / also supports AMD loaders.
84+
The library supports CommonJS and AMD loaders and also exports globally as `protobuf`.
7785

7886
### Distributions
7987

80-
The library supports both reflection-based and code-based use cases:
88+
Where bundle size is a factor, there are additional stripped-down versions of the [full library][dist-full] (~19kb gzipped) available that exclude certain functionality:
8189

82-
1. Parsing protocol buffer definitions (.proto files) to reflection
83-
2. Loading JSON descriptors to reflection
84-
3. Generating static code without any reflection features
90+
* When working with JSON descriptors (i.e. generated by [pbjs](#pbjs-for-javascript)) and/or reflection only, see the [light library][dist-light] (~16kb gzipped) that excludes the parser. CommonJS entry point is:
8591

86-
Where bundle size is a factor, there is a suitable distribution for each of these:
92+
```js
93+
var protobuf = require("protobufjs/light");
94+
```
8795

88-
| | Gzipped | Downloads | How to require | Description
89-
|---------|---------|------------------------------|---------------------------------|-------------
90-
| full | 18.5kb | [dist][dist-full] | `require("protobufjs")` | All features. Works with everything.
91-
| light | 15.5kb | [dist/light][dist-light] | `require("protobufjs/light")` | All features except tokenizer, parser and bundled common types. Works with JSON definitions, pure reflection and static code.
92-
| minimal | 6.0kb+ | [dist/minimal][dist-minimal] | `require("protobufjs/minimal")` | Just enough to run static code. No reflection.
96+
* When working with statically generated code only, see the [minimal library][dist-minimal] (~6.5kb gzipped) that also excludes reflection. CommonJS entry point is:
9397

94-
In case of doubt it is safe to just use the full library.
98+
```js
99+
var protobuf = require("protobufjs/minimal");
100+
```
95101

96102
[dist-full]: https://github.com/dcodeIO/protobuf.js/tree/master/dist
97103
[dist-light]: https://github.com/dcodeIO/protobuf.js/tree/master/dist/light
@@ -100,12 +106,43 @@ In case of doubt it is safe to just use the full library.
100106
Usage
101107
-----
102108

103-
Each message type provides a set of methods with each method doing just one thing. This avoids unnecessary operations where [performance](#performance) is a concern but also forces a user to perform verification explicitly where necessary - for example when dealing with user input.
109+
Because JavaScript is a dynamically typed language, protobuf.js introduces the concept of a **valid message** in order to provide the best possible [performance](#performance):
110+
111+
### Valid message
112+
113+
> **A valid message is an object not missing any required fields and exclusively using JS types for its fields (properties) that are understood by the wire format writer.**
114+
115+
There are two possible types of valid messages and the encoder is able to work with both of these:
116+
117+
* **Runtime messages** (explicit instances of message classes with default values on their prototype) always (have to) satisfy the requirements of a valid message and
118+
* **Plain JavaScript objects** that just so happen to be composed in a way satisfying the requirements of a valid message as well.
119+
120+
In a nutshell, the wire format writer understands the following types:
121+
122+
| Field type | Expected JS type (create, encode) | Naive conversion (fromObject)
123+
|------------|-----------------------------------|------------------------------
124+
| s-/u-/int32<br />s-/fixed32 | `number` (32 bit integer) | `value | 0` if signed<br /> `value >>> 0` if unsigned
125+
| s-/u-/int64<br />s-/fixed64 | `Long`-like (optimal)<br />`number` (53 bit integer) | `Long.fromValue(value)` with long.js<br />`parseInt(value, 10)` otherwise
126+
| float<br />double | `number` | `Number(value)`
127+
| bool | `boolean` | `Boolean(value)`
128+
| string | `string` | `String(value)`
129+
| bytes | `Uint8Array` (optimal)<br />`Buffer` (optimal under node)<br />`Array.<number>` (8 bit integers) | `base64.decode(value)` if a `string`<br />`Object` with non-zero `.length` is assumed to be buffer-like
130+
| enum | `number` (32 bit integer) | Looks up the numeric id if a `string`
131+
| message | Valid message | `Message.fromObject(value)`
132+
133+
* Explicit `undefined` and `null` are considered as not set if the field is optional.
134+
* Repeated fields are `Array.<T>`.
135+
* Map fields are `Object.<string,T>` with the key being the string representation of the respective value or an 8 characters long binary hash string for `Long`-likes.
136+
* Types marked as *optimal* provide the best performance because no conversion step (i.e. number to low and high bits or base64 string to buffer) is required.
137+
138+
### Toolset
104139

105-
Note that **Message** below refers to any message type. See the next section for the definition of a [valid message](#valid-message).
140+
With that in mind and again for performance reasons, each message class provides a distinct set of methods with each method doing just one thing. This avoids unnecessary assertions / operations where performance is a concern but also forces a user to perform verification (of plain JavaScript objects that *might* just so happen to be a valid message) explicitly where necessary - for example when dealing with user input.
141+
142+
**Note** that `Message` below refers to any message class.
106143

107144
* **Message.verify**(message: `Object`): `null|string`<br />
108-
explicitly performs verification prior to encoding a plain object. Instead of throwing, it returns the error message as a string, if any.
145+
verifies that a **plain JavaScript object** satisfies the requirements of a valid message and thus can be encoded without issues. Instead of throwing, it returns the error message as a string, if any.
109146

110147
```js
111148
var payload = "invalid (not an object)";
@@ -115,7 +152,7 @@ Note that **Message** below refers to any message type. See the next section for
115152
```
116153

117154
* **Message.encode**(message: `Message|Object` [, writer: `Writer`]): `Writer`<br />
118-
is an automatically generated message specific encoder expecting a valid message or plain object. Note that this method does not implicitly verify the message and that it's up to the user to make sure that the data can actually be encoded properly.
155+
encodes a valid message (**runtime message** or valid **plain JavaScript object**). This method does not implicitly verify the message and it's up to the user to make sure that the payload is a valid message.
119156

120157
```js
121158
var buffer = AwesomeMessage.encode(message).finish();
@@ -125,7 +162,7 @@ Note that **Message** below refers to any message type. See the next section for
125162
works like `Message.encode` but additionally prepends the length of the message as a varint.
126163

127164
* **Message.decode**(reader: `Reader|Uint8Array`): `Message`<br />
128-
is an automatically generated message specific decoder. If required fields are missing, it throws a `util.ProtocolError` with an `instance` property set to the so far decoded message. If the wire format is invalid, it throws an `Error`. The result is a runtime message.
165+
decodes a buffer to a **runtime message**. If required fields are missing, it throws a `util.ProtocolError` with an `instance` property set to the so far decoded message. If the wire format is invalid, it throws an `Error`.
129166

130167
```js
131168
try {
@@ -143,22 +180,22 @@ Note that **Message** below refers to any message type. See the next section for
143180
works like `Message.decode` but additionally reads the length of the message prepended as a varint.
144181

145182
* **Message.create**(properties: `Object`): `Message`<br />
146-
quickly creates a new runtime message from known to be valid properties without any conversion being performed. Where applicable, it is recommended to prefer `Message.create` over `Message.fromObject`.
183+
creates a new **runtime message** from a set of properties that satisfy the requirements of a valid message. Where applicable, it is recommended to prefer `Message.create` over `Message.fromObject` because it doesn't perform possibly redundant conversion.
147184

148185
```js
149186
var message = AwesomeMessage.create({ awesomeField: "AwesomeString" });
150187
```
151188

152189
* **Message.fromObject**(object: `Object`): `Message`<br />
153-
converts any plain object to a runtime message. Tries to convert whatever is specified (use `Message.verify` before if necessary).
190+
naively converts any non-valid **plain JavaScript object** to a **runtime message**. See the table above for the exact conversion operations performed.
154191

155192
```js
156193
var message = AwesomeMessage.fromObject({ awesomeField: 42 });
157194
// converts awesomeField to a string
158195
```
159196

160197
* **Message.toObject**(message: `Message` [, options: `ConversionOptions`]): `Object`<br />
161-
converts a runtime message to a plain object.
198+
converts a **runtime message** to an arbitrary **plain JavaScript object** for interoperability with other libraries or storage. The resulting plain JavaScript object *might* still satisfy the requirements of a valid message depending on the actual conversion options specified, but most of the time it does not.
162199

163200
```js
164201
var object = AwesomeMessage.toObject(message, {
@@ -172,37 +209,10 @@ Note that **Message** below refers to any message type. See the next section for
172209
});
173210
```
174211

175-
See also: [ConversionOptions](http://dcode.io/protobuf.js/global.html#ConversionOptions)
176-
177-
In pictures:
212+
For reference, the following diagram aims to display the relationships between the different methods above and the concept of a valid message:
178213

179214
<img alt="Toolset Diagram" src="http://dcode.io/protobuf.js/toolset.svg" />
180215

181-
### Valid message
182-
183-
A valid message is an object not missing any required fields and exclusively using JS types for its fields / properties that are understood by the wire format writer.
184-
185-
* Calling `Message.verify` with any object returns `null` if the object can be encoded as-is and otherwise the error as a string.
186-
* Calling `Message.create` or `Message.encode` must be called with a valid message.
187-
* Calling `Message.fromObject` with any object naively converts all values to the optimal JS type.
188-
189-
| Field type | Expected JS type (create, encode) | Naive conversion (fromObject)
190-
|------------|-----------------------------------|------------------------------
191-
| s-/u-/int32<br />s-/fixed32 | `Number` (32 bit integer) | `value | 0` if signed<br /> `value >>> 0` if unsigned
192-
| s-/u-/int64<br />s-/fixed64 | `Long`-like (optimal)<br />`Number` (53 bit integer) | `Long.fromValue(value)` with long.js<br />`parseInt(value, 10)` otherwise
193-
| float<br />double | `Number` | `Number(value)`
194-
| bool | `Boolean` | `Boolean(value)`
195-
| string | `String` | `String(value)`
196-
| bytes | `Uint8Array` (optimal)<br />`Buffer` (optimal under node)<br />`Array.<Number>` (8 bit integers)<br />`String` (base64) | `base64.decode(value)` if a String<br />`Object` with non-zero `.length` is kept
197-
| enum | `Number` (32 bit integer) | Looks up the numeric id if a string
198-
| message | Valid message | `Message.fromObject(value)`
199-
200-
* Explicit `undefined` and `null` are considered as not set when optional.
201-
* Repeated fields are `Array.<T>`.
202-
* Map fields are `Object.<string,T>` with the key being the string representation of the respective value or an 8 characters long binary hash string for `Long`-likes.
203-
* `String` refers to both objects and values while `Number` refers to values only.
204-
* Types marked as *optimal* provide the best performance because no conversion step (i.e. number to low and high bits or base64 string to buffer) is required.
205-
206216
Examples
207217
--------
208218

0 commit comments

Comments
 (0)