-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
286 lines (236 loc) · 11.8 KB
/
index.html
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSDoc: Home</title>
<script src="scripts/prettify/prettify.js"> </script>
<script src="scripts/prettify/lang-css.js"> </script>
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
<link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css">
</head>
<body>
<div id="main">
<h1 class="page-title">Home</h1>
<h3> </h3>
<section>
<article><h1>Fluent JSON validator</h1>
<ul>
<li><a href="https://github.com/Semmu/fluent-json-validator"><strong>GitHub repository</strong></a></li>
<li><a href="https://semmu.github.io/fluent-json-validator"><strong>Online API docs</strong></a></li>
<li><a href="https://www.npmjs.com/package/fluent-json-validator"><strong>NPM package site</strong></a></li>
</ul>
<p>An easy-to-use, expressive, and composable JSON object validator, with a fluent builder pattern interface!</p>
<pre class="prettyprint source lang-javascript"><code>// this is what you want to validate:
// coming from the user, read from a file, sent back by some API, etc.
const person = {
name: 'John Doe',
age: 42,
hobbies: ['eating', 'coding', 'sleeping'],
favoriteNumberOrColor: 'green'
};
// this is the structure you want your data to have:
const personSchema = is.Object({
name: is.String(),
nickname: is.optional().String(),
// ^ nickname may be missing, but if not, it must be a string.
age: is.Number().Which(
age => age > 10
// ^ age must be more than 10.
),
hobbies: is.ArrayOf(
is.String().Which(
hobby => hobby !== 'illegal activities'
// ^ hobbies can't include illegal activities!
)
),
favoriteNumberOrColor: is.OneOf([is.Number(), is.String()])
});
// and this is how you check if it matches or not:
personSchema.validate(person); // == true
</code></pre>
<h2>Features</h2>
<ul>
<li>Lightweight, since it has <strong>no dependencies!</strong></li>
<li>Has a <strong>small and simple API</strong>, only a handful of methods.</li>
<li>Can validate <strong>primitive types, arrays</strong> (<code>is.ArrayOf</code>) and even <strong>variable types</strong> (<code>is.OneOf</code>)!</li>
<li>Can validate <strong>any arbitrary JSON object structure</strong>, just mix'n'match the needed validators (<code>is.Object</code>)!</li>
<li>Schemas are <strong>reusable and composable</strong> for validating complex data structures painlessly!</li>
<li>Can be used for <strong>formal</strong><sup>1</sup> and <strong>functional</strong><sup>1</sup> validation as well (<code>is.Which</code>)!</li>
</ul>
<p><sup>1</sup>: I may be using slightly incorrect words, but by formal validation I mean <em>the subject has the desired structure</em>, and by functional validation I mean <em>the subject itself also satisfies additional arbitrary requirements</em>.</p>
<h2>Installation</h2>
<pre class="prettyprint source lang-bash"><code>npm install fluent-json-validator
</code></pre>
<h2>Usage / how-to / tutorial</h2>
<p>First, of course you need to import the library itself:</p>
<pre class="prettyprint source lang-javascript"><code>import { is } from 'fluent-json-validator'
</code></pre>
<p>Then you can create validators like this:</p>
<pre class="prettyprint source lang-javascript"><code>const stringValidator = is.String();
</code></pre>
<p>These validators can then validate objects passed to them like this:</p>
<pre class="prettyprint source lang-javascript"><code>stringValidator.validate('some string') // true
stringValidator.validate(42) // false
</code></pre>
<p>Of course this whole expression can be written on one single line if you prefer compact solutions:</p>
<pre class="prettyprint source lang-javascript"><code>is.String().validate('some string') // still true
is.String().validate(42) // still false
</code></pre>
<p>If some data may not be present, you can use optional validators, which accept missing/undefined data:</p>
<pre class="prettyprint source lang-javascript"><code>const isOptionalNumber = is.optional().Number() // or is.Number().optional()
isOptionalNumber.validate(42) // true
isOptionalNumber.validate() // true
isOptionalNumber.validate('NaN') // false
</code></pre>
<p>As for primitive data types, we have validators for strings, numbers and booleans:</p>
<pre class="prettyprint source lang-javascript"><code>const stringValidator = is.String()
const numberValidator = is.Number()
const boolValidator = is.Boolean()
stringValidator.validate('more string') // true
numberValidator.validate(42) // true
boolValidator.validate(true) // true
</code></pre>
<p>And for complex/compound data types, i.e. objects, we have the object validator:</p>
<pre class="prettyprint source lang-javascript"><code>const objectValidator = is.Object({
someKey: is.String()
})
</code></pre>
<p>This object validator needs a parameter which describes the desired schema of the subject. It must contain the same properties as the subject you want to validate, and it must be made up of other validators.</p>
<p>Using this is very similar to the primitive data type validators:</p>
<pre class="prettyprint source lang-javascript"><code>const someObject = {
someKey: 'this is some string'
}
objectValidator.validate(someObject) // true
const otherObject = {
someKey: 42
}
objectValidator.validate(otherObject) // false
</code></pre>
<p>(Of course the above expressions can be written on one line as well. Excercise left for the reader.)</p>
<p>For arrays, you can use the array validator:</p>
<pre class="prettyprint source lang-javascript"><code>const arrayValidator = is.ArrayOf(is.Number())
</code></pre>
<p>This one also needs a parameter: a validator, which is going to check all the elements of the array, like this:</p>
<pre class="prettyprint source lang-javascript"><code>arrayValidator.validate([1, 2, 3]) // true
arrayValidator.validate(['some', 'string']) // false
arrayValidator.validate([1, 2, 'impostor']) // false
</code></pre>
<p>If you happen to have some data which could have different types, you can validate that as well:</p>
<pre class="prettyprint source lang-javascript"><code>const variableValidator = is.OneOf([is.String(), is.Number()])
</code></pre>
<p>This validator needs an array of validators, and the subject will need to match against at least one of them.</p>
<pre class="prettyprint source lang-javascript"><code>variableValidator.validate('some string') // true
variableValidator.validate(42) // also true
variableValidator.validate(true) // false
</code></pre>
<p>Lastly, if you need to check for functional requirements, you can do that too:</p>
<pre class="prettyprint source lang-javascript"><code>const ageValidator = is.Number().Which(value => value >= 18)
</code></pre>
<p>It needs a lambda/function as a parameter, which will receive the subject to validate, and must return a boolean.</p>
<p>Using it does not require anything special:</p>
<pre class="prettyprint source lang-javascript"><code>ageValidator.validate(18) // true
ageValidator.validate(5) // false
</code></pre>
<p>And if you need to validate complex data structures, you can compose big validators from smaller ones, like:</p>
<pre class="prettyprint source lang-javascript"><code>const isPerson = is.Object({
name: is.String(),
gender: is.optional().String(),
age: is.Number()
})
const isLocation = is.Object({
longitude: is.Number(),
latitude: is.Number()
})
// the compound validator.
const isCompany = is.Object({
owner: isPerson,
employees: is.ArrayOf(isPerson),
location: isLocation
})
isCompany.validate({
owner: {
name: 'John Doe',
gender: 'male',
age: 42
},
employees: [
{
name: 'Some Dude',
// note: gender is missing!
age: 18
}, {
name: 'Another Individual',
gender: 'mystery',
age: 99
}
],
location: {
longitude: 42,
latitude: 3.14
}
}) // true
</code></pre>
<p>This is actually a very simple example compared to what you can do with this library.</p>
<p>For example you can have an array of values, in which all of them must meet a functional requirement:</p>
<pre class="prettyprint source lang-javascript"><code>const diceRolls = is.ArrayOf(is.Number().Which(value => value > 0 && value < 7))
diceRolls.validate([1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1]) // true
diceRolls.validate([1, 6, 3]) // true
diceRolls.validate([9]) // false
diceRolls.validate(['over 9000']) // false
</code></pre>
<p>And also you can have a functional requirement which ensures e.g. cross-referencing in complex schemas:</p>
<pre class="prettyprint source lang-javascript"><code>const isFood = is.Object({
name: is.String(),
calories: is.Number()
})
const validator = is.Object({
foods: is.ArrayOf(isFood),
favoriteFoodName: is.String()
}).Which(obj => obj.foods.filter(food => food.name == obj.favoriteFoodName).length == 1)
// ^ == there exists one and only one food which has the name of favoriteFoodName.
console.log(validator.validate({
foods: [
{
name: 'apple',
calories: 52
},
{
name: 'pizza',
calories: 266
}
],
favoriteFoodName: 'apple'
})) // true
</code></pre>
<p>In this example above we have a list of foods (with names and calories), and a favorite food, which must exist in the said foods array.</p>
<p>Also don't forget to check the <a href="./tests.js">countless tests</a> for inspiration, especially the <a href="./tests.js#L285">complex ones</a> at the end!</p>
<h2>API docs</h2>
<p>In the <a href="docs/"><code>docs/</code></a> folder and also hosted on <a href="https://semmu.github.io/fluent-json-validator">GitHub Pages</a>. (Don't forget to check the right sidebar of the site!)</p>
<h2>Testing</h2>
<p>Testcases are listed in <a href="./tests.js"><code>tests.js</code></a>. Run them with</p>
<pre class="prettyprint source lang-bash"><code>npm test
</code></pre>
<h2>Note about code quality (?)</h2>
<p>This project most probably does not follow the current Javascript standards and coding style embraced by the global community, thus some people may find the source code weird and/or outright hideous. As I'm not primarily a Javascript developer (and I don't intend to become one) the current implementation is a solution that I could come up with, which works and has the API that I dreamed of.</p>
<p>If you have ideas how to improve the library internals (without breaking the public API) feel free to open an issue or PR to discuss it! I'm open for improvements and constructive criticism.</p>
<h2>But why?</h2>
<p>Because there is no other JSON object validator with a builder pattern interface like this one. Okay, there is actually <a href="https://www.npmjs.com/package/superstruct">Superstruct</a>, but I didn't know about it when I started developing this, and also it is much-much bigger with many features I personally don't need.</p>
<p>So I created this library as a smaller alternative.</p>
<h2>License</h2>
<p>MIT</p></article>
</section>
</div>
<nav>
<h2><a href="index.html">Home</a></h2><h3>Namespaces</h3><ul><li><a href="is.html">is</a></li></ul><h3>Classes</h3><ul><li><a href="is.__validationUnit.html">__validationUnit</a></li></ul>
</nav>
<br class="clear">
<footer>
Documentation generated by <a href="https://github.com/jsdoc/jsdoc">JSDoc 3.6.6</a> on Sat Mar 13 2021 20:15:25 GMT+0100 (Central European Standard Time)
</footer>
<script> prettyPrint(); </script>
<script src="scripts/linenumber.js"> </script>
</body>
</html>