4
4
You love Mongoose for all it's convenience methods and
5
5
valiate-before-saving logic, but but you store complex objects using
6
6
` Schema.Types.Mixed ` which lacks validation in Mongoose, or you just wish
7
- you could validate objects using a richer
7
+ you could validate objects, strings, etc. using a richer
8
8
[ JSON-schema] ( http://json-schema.org/ ) vocabulary than is included with
9
9
Mongoose.
10
10
11
11
## The Solution
12
12
13
13
The ` mongoose-ajv-plugin ` lets you use the awesome [ AJV JSON-Schema
14
14
validation library] [ ajv ] , to validate individual attributes or entire
15
- documents, giving you access to it's rich schema vocabulary and convenience
15
+ documents, giving you access to it's rich extensible schema vocabulary and convenience
16
16
formats like [ email] [ formats ] , [ Date] [ formats ] , [ hostname] [ formats ] , ect.
17
17
18
18
[ ajv ] : https://github.com/epoberezkin/ajv " AJV "
@@ -21,30 +21,87 @@ formats like [email][formats], [Date][formats], [hostname][formats], ect.
21
21
22
22
## Getting Started
23
23
24
+ Import mongoose and add in the ` mongoose-ajv-plugin ` :
24
25
25
- ### Attribute validation
26
+ ``` JavaScript
27
+ var mongoose = require (" mongoose" );
28
+ mongoose .plugin (require (" mongoose-ajv-plugin" ))
29
+ ```
30
+
31
+ Now use your favorite AJV Schema, such as the ` ajv_contact_schema ` defined
32
+ below, to validate entire documents using the ` "ajv-schema" ` keyword, like
33
+ so:
34
+
35
+ ``` JavaScript
36
+ var Contact_schema = new mongoose.Schema ({
37
+ " name" : String ,
38
+ " email" : String ,
39
+ " birthday" : String ,
40
+ // let AJV validate this entire document
41
+ " ajv-schema" : ajv_contact_schema
42
+ });
43
+ ```
26
44
27
- Import Mongoose as usual:
45
+ Or use AJV to validate one or more attributes of a document using the "ajv-schema" option:
28
46
29
47
``` JavaScript
30
- var mongoose = require (' mongoose' );
31
- var Schema = mongoose .Schema ;
32
- // optional; used by the `validate_promise()` convenience function, below.
33
- mongoose .Promise = require (' bluebird' );
48
+ // use AJV to validate fields within a document
49
+ var Player_schema = new Schema ({
50
+ " user_name" : String ,
51
+ " rank" : Number ,
52
+ " ip_address" : {
53
+ " type" : String ,
54
+ // let AJV validate this string attribute
55
+ " ajv-schema" : {
56
+ " type" : ' string' ,
57
+ " format" : ' ipv4' /
58
+ }
59
+ },
60
+ " contact-info" : {
61
+ " type" : Schema .Types .Mixed ,
62
+ // let AJV validate this nested object
63
+ " ajv-schema" : contact_json_schema
64
+ },
65
+ });
34
66
```
35
67
36
- When validating individual attributes, it is sufficient to load the plugin globally:
68
+ ## Using AJV Extension Modules
37
69
70
+ If you wish to extend the Ajv instance used for validation with additional
71
+ [ schemata] ( https://github.com/epoberezkin/ajv#addschemaarrayobjectobject-schema--string-key ) ,
72
+ [ formats] ( https://github.com/epoberezkin/ajv#addformatstring-name-stringregexpfunctionobject-format ) ,
73
+ or [ keywords] ( https://github.com/epoberezkin/ajv#api-addkeyword ) , you can provide your own instance, like so:
38
74
39
75
``` JavaScript
40
- mongoose .plugin (require (' mongoose-ajv-plugin' ));
76
+ // create an Ajv instance
77
+ var Ajv = require (" ajv" );
78
+ var ajv = new Ajv ();
79
+
80
+ // add custom schema, keywords, or formats
81
+ ajv .addSchema (... );
82
+ // or
83
+ ajv .addKewword (... )
84
+ // or
85
+ ajv .addFormat (... )
86
+ // or
87
+ require (" my-ajv-plugin" )(ajv)
88
+
89
+ // use this ajv instance to compile every new validator
90
+ mongoose .plugin (require (" mongoose-ajv-plugin" ,{" ajv" : ajv})
91
+
92
+ // or use this ajv instance to compile validators for an individual
93
+ // mongoose schema
94
+ var my_schema = new mongoose.Schema ({... });
95
+ my_schema .plugin (require (" mongoose-ajv-plugin" ,{" ajv" : ajv})
41
96
` ` `
42
97
98
+ ## Contact JSON schema
43
99
44
- Define a JSON-schema for your favorite attribute:
100
+ And finally, here's the definition of ` ajv_contact_schema` used in the
101
+ above examples:
45
102
46
103
` ` ` JavaScript
47
- var contact_json_schema = {
104
+ var ajv_contact_schema = {
48
105
" type" : " object" ,
49
106
" properties" : {
50
107
" name" : {
@@ -77,184 +134,3 @@ var contact_json_schema = {
77
134
}
78
135
};
79
136
` ` `
80
-
81
- Define a Mongoose schema that includes a ` schema ` attribute, or two:
82
-
83
- ``` JavaScript
84
- // use AJV to validate fields within a document
85
- var Player_schema = new Schema ({
86
- user_name: String ,
87
- rank: Number ,
88
- ip_address: {
89
- type: String , // the mongoose type
90
- schema: { // use AJV to validtae this string
91
- type: ' string' , // the JSON schema Type
92
- format: ' ipv4' // AJV convenience String Format
93
- }
94
- },
95
- contact: {
96
- type: Schema .Types .Mixed ,
97
- schema: contact_json_schema // use AJV to validate this object
98
- },
99
- });
100
- ```
101
- If you didn't load the mongoose-ajv-plugin globally , you'll need to add it to your schema now:
102
-
103
- ``` JavaScript
104
- // add the AJV plugin to the schema
105
- var ajv_plugin = require (' mongoose-ajv-plugin' )
106
- Player_schema .plugin (ajv_plugin);
107
- ```
108
-
109
- Next, create a model and some instances, and validate the instances.
110
-
111
- ``` JavaScript
112
- // Create a model from the schema
113
- var Player = mongoose .model (' Player' , Player_schema);
114
-
115
- var felix = new Player ({
116
- user_name: " Felix" ,
117
- rank: 5 ,
118
- ip_address: " 123.45.67.89" ,
119
- contact: {
120
- name: " Jack" ,
121
- email: " plaza626@email.com" ,
122
- birthday: " 1925-02-08"
123
- }
124
- });
125
-
126
- var oscar = new Player ({
127
- user_name: " Oscar" ,
128
- rank: 7 ,
129
- ip_address: " 123.4.5.678" , // invalid IP address
130
- contact: {
131
- name: " Walter" ,
132
- email: " RedWingsFan@poker.com" ,
133
- birthday: " October 1, 1920" // invalid date format format
134
- },
135
- })
136
-
137
- felix .validate (validate_callback_factory (" Felix" )) // callback based validation *
138
- validate_promise (felix," Felix" ) // promise based validation *
139
- >> Felix passed validation!
140
-
141
- oscar .validate (validate_callback_factory (" Oscar" )) // callback based validation *
142
- validate_promise (oscar," Oscar" ) // promise based validation *
143
- >> Oscar failed validation with message: Player validation failed; ' contact' attribute does not match it' s JSON-schema
144
- ```
145
- \* see `convenience functions` section below.
146
-
147
- Calling [my_model_instance.save()][validate] will cause the validation to occur as well.
148
-
149
- ### Document validation
150
-
151
- Create a schema for your document
152
-
153
- ```JavaScript
154
- var team_json_schema = {
155
- "type":"object",
156
- "properties": {
157
- "team_name": {
158
- "type": "string",
159
- // team names must be between 5 and 30 characters
160
- "minLength": 5,
161
- "maxLength": 30
162
- },
163
- "players": {
164
- "type": "array",
165
- "minItems": 2,
166
- "maxItems": 10,
167
- "items": {
168
- "type": "string"
169
- }
170
- }
171
- }
172
- };
173
- ```
174
-
175
- Then create an Mongoose schema and add the plugin, passing the schema in the
176
- options parameter of [Schema.plugin()][schema-plugin];
177
-
178
- [schema-plugin]: http://mongoosejs.com/docs/api.html#schema_Schema-plugin "Schema Plugin"
179
-
180
- ```JavaScript
181
- var Team_schema = new Schema({
182
- team_name: String,
183
- players: [String],
184
- });
185
- Team_schema.plugin(ajv_plugin,{schema:team_json_schema});
186
- var Team = mongoose.model(' Team' , Team_schema);
187
- ```
188
-
189
- Now Create and validate some instances:
190
-
191
- ```JavaScript
192
- var just_me = new Team({
193
- "team_name": "Just Me",
194
- "players": ["Bridget"] // too few players
195
- })
196
-
197
- var thursday_night_poker = new Team({
198
- "team_name": "ThursdayNightPoker",
199
- "players": ["Oscar","Felix","Speed","Vinnie","Roy","Murray"]
200
- })
201
-
202
- just_me.validate(validate_callback_factory("Just Me")) // callback based validation *
203
- validate_promise(just_me,"Just Me") // promise based validation *
204
- >> Just Me failed validation with message: Team validation failed; instance data does not match the JSON-schema
205
-
206
- thursday_night_poker.validate(validate_callback_factory("Thursday Night Poker")) // callback based validation *
207
- validate_promise(thursday_night_poker,"Thursday Night Poker") // promise based validation *
208
- >> Thursday Night Poker passed validation!
209
- ```
210
- \* see `convenience functions` section below.
211
-
212
- ## Miscellaneous notes
213
-
214
- * Validation with the mongoose-ajv-plugin is invoked when calling
215
- `my_instance.save()` or `my_instance.validate()`. The `mongoose-ajv-plugin`,
216
- is implemented as a `model.pre(' validate' ,...)` method, which, at the time of
217
- this writing, is not invoked by `my_instance.validateSync()`.
218
-
219
- * Like internal Mongoose validators, the AJV-Mongoose plugin does
220
- not validate undefined values. To require values to be defined, use the
221
- built in [`required`](validate-undefined-value) schema attribute.
222
-
223
- [validate-undefined-value]: http://mongoosejs.com/docs/api.html#schematype_SchemaType-required
224
-
225
-
226
- ## Advanced options
227
-
228
- If you want to use multiple schema, you can load up your own ajv instance and
229
- pass it in the options parameter of [Schema.plugin()][schema-plugin]:
230
-
231
- ```JavaScript
232
- var AJV = require(' ajv' ),
233
- ajv = new AJV();
234
- ajv.addSchema(schema, ' mySchema' );
235
- Team_schema.plugin(ajv_plugin,{schema: team_json_schema,ajv: ajv});
236
- ```
237
-
238
- ## Convenience Functions
239
-
240
- ```JavaScript
241
- function validate_callback_factory(name){
242
- return function (err,doc){
243
- if(err){
244
- console.log(name +" passed validation!");
245
- }else{
246
- console.log(name +" failed validation with message: " + err.message);
247
- }
248
- };
249
- }
250
-
251
- function validate_promise (data,name){
252
- data.validate().then(function(x){
253
- console.log(name +" passed validation!");
254
- }) .catch(function(err){
255
- console.log(name +" failed validation with message: " + err.message);
256
- })
257
- }
258
- ```
259
-
260
-
0 commit comments