├── .gitignore ├── config.js ├── db.json ├── endpoints ├── items.js ├── login.js ├── me.js ├── register.js └── users.js ├── index.js ├── middlewares ├── addIdAndTimeStamps.js └── jwt_validation.js ├── package.json ├── readme.md └── utils └── validations.js /.gitignore: -------------------------------------------------------------------------------- 1 | # env files 2 | .env 3 | .env.local 4 | .env.*.local 5 | 6 | # npm 7 | node_modules 8 | package-lock.json 9 | *.gz 10 | 11 | # Logs 12 | logs 13 | *.log 14 | npm-debug.log* 15 | yarn-debug.log* 16 | yarn-error.log* 17 | 18 | # Optional eslint cache 19 | .eslintcache 20 | 21 | # production 22 | build 23 | dist 24 | 25 | # OS X 26 | .DS_Store* 27 | Icon? 28 | ._* 29 | 30 | # Windows 31 | Thumbs.db 32 | ehthumbs.db 33 | Desktop.ini 34 | 35 | # Linux 36 | .directory 37 | *~ 38 | 39 | # Coveralls 40 | coverage 41 | 42 | # Benchmarking 43 | benchmarks/graphs -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | /* Ojo: Esto es mejor manejarlo en una variable de entorno y usar una palabra secreta más fuerte, sin embargo para fines didácticos de poder clonar y desplegar rápidamente este servidor de prueba se maneja en un archivo de configuración */ 2 | const secret = 'your-secret-key' 3 | 4 | module.exports = { 5 | secret 6 | } 7 | -------------------------------------------------------------------------------- /db.json: -------------------------------------------------------------------------------- 1 | { 2 | "users": [ 3 | { 4 | "id": "1c311551-074a-4226-9758-f0780c427612", 5 | "first_name": "Dr.", 6 | "last_name": "Strange", 7 | "gender": "M", 8 | "email": "drstrange@marvel.com", 9 | "password": "$2b$10$eWUUn0pa93FvCflMfAoOi.pia5mX0XZo3vFIseZApqdIpjURSUpJO", 10 | "role": "CUSTOMER", 11 | "createdAt": 1672949755981, 12 | "updatedAt": 1672949755981 13 | }, 14 | { 15 | "id": "7f545390-fd8f-4412-b7b3-4e267586751f", 16 | "first_name": "Clark", 17 | "last_name": "Kent", 18 | "gender": "M", 19 | "email": "superman@dc.com", 20 | "password": "$2b$10$rk4MklBt2DtAq4Fh/okYYul54DSJWh1z2jRf9qIWKuygOEQI2FR5C", 21 | "role": "ADMIN", 22 | "createdAt": 1674323738966, 23 | "updatedAt": 1674323738966 24 | } 25 | ], 26 | "items": [ 27 | { 28 | "isActive": true, 29 | "id": "5fbc19a65a3f794d72471163", 30 | "product_name": "Awesome Granite Bacon", 31 | "description": "The beautiful range of Apple Naturalé that has an exciting mix of natural ingredients. With the Goodness of 100% Natural Ingredients", 32 | "price": 962, 33 | "category": "Kids", 34 | "brand": "Osinski - Prosacco", 35 | "sku": "e9cbfac1-301a-42c3-b94a-711a39dc7ed1", 36 | "createdAt": "2020-11-23T20:20:54.245Z", 37 | "updatedAt": "2020-11-23T20:20:54.245Z", 38 | "__v": 0, 39 | "image": "https://i.pinimg.com/originals/eb/83/be/eb83be580847bcdc4c8f403c8085d3c8.jpg" 40 | }, 41 | { 42 | "isActive": true, 43 | "id": "5fbc19a65a3f794d72471164", 44 | "product_name": "Unbranded Steel Fish", 45 | "description": "Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support", 46 | "price": 643, 47 | "category": "Shoes", 48 | "brand": "Kuvalis Inc", 49 | "sku": "0b3c4d2c-2bf6-4410-80f3-890f8fe6f334", 50 | "createdAt": "2020-11-23T20:20:54.246Z", 51 | "updatedAt": "2020-11-23T20:20:54.246Z", 52 | "__v": 0, 53 | "image": "https://i.pinimg.com/originals/ee/f3/f4/eef3f4858339074c0bba500abfbf6850.jpg" 54 | }, 55 | { 56 | "isActive": true, 57 | "id": "5fbc19a65a3f794d72471165", 58 | "product_name": "Fantastic Steel Fish", 59 | "description": "New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart", 60 | "price": 214, 61 | "category": "Computers", 62 | "brand": "Corwin - Herzog", 63 | "sku": "cd03b5a9-47d3-46ad-9845-a01a2a785945", 64 | "createdAt": "2020-11-23T20:20:54.246Z", 65 | "updatedAt": "2020-11-23T20:20:54.246Z", 66 | "__v": 0, 67 | "image": "https://i.pinimg.com/originals/c5/a2/63/c5a263ec113f5844df57d1000257992d.jpg" 68 | }, 69 | { 70 | "isActive": true, 71 | "id": "5fbc19a65a3f794d72471167", 72 | "product_name": "Intelligent Granite Pizza", 73 | "description": "The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design", 74 | "price": 939, 75 | "category": "Grocery", 76 | "brand": "Bruen, O'Hara and Feil", 77 | "sku": "cb6f07e1-a9ad-4647-8ed1-d928c60a6c8f", 78 | "createdAt": "2020-11-23T20:20:54.246Z", 79 | "updatedAt": "2020-11-23T20:20:54.246Z", 80 | "__v": 0, 81 | "image": "https://m.media-amazon.com/images/S/aplus-seller-content-images-us-east-1/ATVPDKIKX0DER/A11EBA8L6AALBZ/B075BLK652/XOS9mvpeQuKV._UX835_TTW__.jpg" 82 | }, 83 | { 84 | "isActive": true, 85 | "id": "5fbc19a65a3f794d72471166", 86 | "product_name": "Small Soft Shoes", 87 | "description": "The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design", 88 | "price": 511, 89 | "category": "Automotive", 90 | "brand": "Thompson LLC", 91 | "sku": "7de3782a-cfc5-43f3-aca7-0eff0adf688c", 92 | "createdAt": "2020-11-23T20:20:54.246Z", 93 | "updatedAt": "2020-11-23T20:20:54.246Z", 94 | "__v": 0, 95 | "image": "https://images-na.ssl-images-amazon.com/images/I/71PAHeADLQL._AC_UY500_.jpg" 96 | }, 97 | { 98 | "isActive": true, 99 | "id": "5fbc19a65a3f794d72471168", 100 | "product_name": "Tasty Rubber Gloves", 101 | "description": "The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design", 102 | "price": 616, 103 | "category": "Automotive", 104 | "brand": "Franecki LLC", 105 | "sku": "18123dd7-196b-412a-b162-d6879c0f6580", 106 | "createdAt": "2020-11-23T20:20:54.246Z", 107 | "updatedAt": "2020-11-23T20:20:54.246Z", 108 | "__v": 0, 109 | "image": "https://images-na.ssl-images-amazon.com/images/I/61lRZu-f21L._AC_SX466_.jpg" 110 | }, 111 | { 112 | "isActive": true, 113 | "id": "5fbc19a65a3f794d72471169", 114 | "product_name": "Small Steel Fish", 115 | "description": "The beautiful range of Apple Naturalé that has an exciting mix of natural ingredients. With the Goodness of 100% Natural Ingredients", 116 | "price": 517, 117 | "category": "Toys", 118 | "brand": "O'Conner, Kuhic and Parisian", 119 | "sku": "7b07c497-9336-4db0-80fc-b6a288f27835", 120 | "createdAt": "2020-11-23T20:20:54.246Z", 121 | "updatedAt": "2020-11-23T20:20:54.246Z", 122 | "__v": 0, 123 | "image": "https://ae01.alicdn.com/kf/HTB1n_XrPFXXXXbgXFXXq6xXFXXXR/1pc-Stainless-Steel-Fish-Scales-Planing-Scales-Kitchen-Supplies-Small-Scales-Scraper-Fish-Tool.jpg" 124 | }, 125 | { 126 | "isActive": true, 127 | "id": "5fbc19a65a3f794d7247116c", 128 | "product_name": "Practical Cotton Fish", 129 | "description": "The automobile layout consists of a front-engine design, with transaxle-type transmissions mounted at the rear of the engine and four wheel drive", 130 | "price": 304, 131 | "category": "Tools", 132 | "brand": "O'Connell, Kunde and Veum", 133 | "sku": "3301d5e5-5565-4a58-a28b-891d5ea6e4cf", 134 | "createdAt": "2020-11-23T20:20:54.246Z", 135 | "updatedAt": "2020-11-23T20:20:54.246Z", 136 | "__v": 0, 137 | "image": "https://www.cardinalhealth.com/content/dam/corp/products/professional-products/search-engine/search-curity-practical-cotton-roll-2287.jpg" 138 | }, 139 | { 140 | "isActive": true, 141 | "id": "5fbc19a65a3f794d7247116a", 142 | "product_name": "Practical Wooden Ball", 143 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 144 | "price": 252, 145 | "category": "Health", 146 | "brand": "Bradtke LLC", 147 | "sku": "efa3b464-82cc-4cfc-97ec-4d60f8d0afa2", 148 | "createdAt": "2020-11-23T20:20:54.246Z", 149 | "updatedAt": "2020-11-23T20:20:54.246Z", 150 | "__v": 0, 151 | "image": "https://images-na.ssl-images-amazon.com/images/I/51K1-HZ5OiL._AC_SX466_.jpg" 152 | }, 153 | { 154 | "isActive": true, 155 | "id": "5fbc19a65a3f794d7247116b", 156 | "product_name": "Small Frozen Table", 157 | "description": "New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart", 158 | "price": 987, 159 | "category": "Sports", 160 | "brand": "Heaney, O'Keefe and Heller", 161 | "sku": "958471a4-a707-4979-bcad-62fd5b556834", 162 | "createdAt": "2020-11-23T20:20:54.246Z", 163 | "updatedAt": "2020-11-23T20:20:54.246Z", 164 | "__v": 0, 165 | "image": "https://target.scene7.com/is/image/Target/GUEST_f546c66a-45d9-4b2d-92a0-e9420a0ea6ac?wid=488&hei=488&fmt=pjpeg" 166 | }, 167 | { 168 | "isActive": true, 169 | "id": "5fbc19a65a3f794d7247116e", 170 | "product_name": "Tasty Concrete Chips", 171 | "description": "The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J", 172 | "price": 610, 173 | "category": "Sports", 174 | "brand": "Cormier - Cummerata", 175 | "sku": "3eff9630-a23f-4358-a257-6488238c568b", 176 | "createdAt": "2020-11-23T20:20:54.246Z", 177 | "updatedAt": "2020-11-23T20:20:54.246Z", 178 | "__v": 0, 179 | "image": "https://images-na.ssl-images-amazon.com/images/I/61lRZu-f21L._AC_SX466_.jpg" 180 | }, 181 | { 182 | "isActive": true, 183 | "id": "5fbc19a65a3f794d7247116f", 184 | "product_name": "Practical Metal Shirt", 185 | "description": "New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart", 186 | "price": 57, 187 | "category": "Outdoors", 188 | "brand": "Hickle - Gusikowski", 189 | "sku": "0824bc8e-5ef7-4d7c-9b68-1e455aa62bcf", 190 | "createdAt": "2020-11-23T20:20:54.246Z", 191 | "updatedAt": "2020-11-23T20:20:54.246Z", 192 | "__v": 0, 193 | "image": "https://vangogh.teespring.com/v3/image/12EVK10jQxRf-PlivW0xr0YToz4/480/560.jpg" 194 | }, 195 | { 196 | "isActive": true, 197 | "id": "5fbc19a65a3f794d72471176", 198 | "product_name": "Sleek Granite Pants", 199 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 200 | "price": 153, 201 | "category": "Jewelery", 202 | "brand": "Nolan, Schmidt and Effertz", 203 | "sku": "07df9e82-bf7f-4cee-bd5e-65bdd1894fff", 204 | "createdAt": "2020-11-23T20:20:54.246Z", 205 | "updatedAt": "2020-11-23T20:20:54.246Z", 206 | "__v": 0, 207 | "images": "https://i.pinimg.com/originals/f4/fb/89/f4fb89e0b418002bd8d6953138990840.jpg" 208 | }, 209 | { 210 | "isActive": true, 211 | "id": "5fbc19a65a3f794d72471170", 212 | "product_name": "Fantastic Granite Bacon", 213 | "description": "The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality", 214 | "price": 730, 215 | "category": "Movies", 216 | "brand": "Tromp Group", 217 | "sku": "7bf61a0c-79ee-4c2b-96fc-25c59b60ed47", 218 | "createdAt": "2020-11-23T20:20:54.246Z", 219 | "updatedAt": "2020-11-23T20:20:54.246Z", 220 | "__v": 0, 221 | "image": "https://thumbs.dreamstime.com/b/crisp-fried-bacon-plate-above-grey-granite-background-table-crisp-fried-bacon-plate-above-grey-granite-background-103030258.jpg" 222 | }, 223 | { 224 | "isActive": true, 225 | "id": "5fbc19a65a3f794d72471171", 226 | "product_name": "Tasty Soft Gloves", 227 | "description": "New ABC 13 9370, 13.3, 5th Gen CoreA5-8250U, 8GB RAM, 256GB SSD, power UHD Graphics, OS 10 Home, OS Office A & J 2016", 228 | "price": 49, 229 | "category": "Movies", 230 | "brand": "Kessler - Kunze", 231 | "sku": "1575b702-a1a5-4353-a7ee-22819d58d9e9", 232 | "createdAt": "2020-11-23T20:20:54.246Z", 233 | "updatedAt": "2020-11-23T20:20:54.246Z", 234 | "__v": 0, 235 | "image": "https://images-na.ssl-images-amazon.com/images/I/61ZCzwCRVjL._AC_SX522_.jpg" 236 | }, 237 | { 238 | "isActive": true, 239 | "id": "5fbc19a65a3f794d72471174", 240 | "product_name": "Refined Fresh Car", 241 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 242 | "price": 213, 243 | "category": "Industrial", 244 | "brand": "Auer LLC", 245 | "sku": "d6887b22-748c-4efc-9f40-3bfde0ad9a87", 246 | "createdAt": "2020-11-23T20:20:54.246Z", 247 | "updatedAt": "2020-11-23T20:20:54.246Z", 248 | "__v": 0, 249 | "image": "https://www.ld-aromaticos.com/imagenes/productos/Fresh%20New%20Car-Spray%2060%20ml-Coche%20nuevo.jpg" 250 | }, 251 | { 252 | "isActive": true, 253 | "id": "5fbc19a65a3f794d7247117b", 254 | "product_name": "Sleek Metal Chips", 255 | "description": "The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J", 256 | "price": 735, 257 | "category": "Grocery", 258 | "brand": "Lueilwitz, Terry and Hane", 259 | "sku": "0e113f62-3566-4cc3-83ce-bc0db2255721", 260 | "createdAt": "2020-11-23T20:20:54.246Z", 261 | "updatedAt": "2020-11-23T20:20:54.246Z", 262 | "__v": 0 263 | }, 264 | { 265 | "isActive": true, 266 | "id": "5fbc19a65a3f794d72471175", 267 | "product_name": "Intelligent Rubber Sausages", 268 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 269 | "price": 673, 270 | "category": "Music", 271 | "brand": "Feeney, Waelchi and Tillman", 272 | "sku": "c1460b0b-ce27-40e8-99dd-14d4d9d0f176", 273 | "createdAt": "2020-11-23T20:20:54.246Z", 274 | "updatedAt": "2020-11-23T20:20:54.246Z", 275 | "__v": 0, 276 | "images": "https://images-na.ssl-images-amazon.com/images/I/51tUmnnQSlL._AC_SL1001_.jpg" 277 | }, 278 | { 279 | "isActive": true, 280 | "id": "5fbc19a65a3f794d72471173", 281 | "product_name": "Intelligent Metal Table", 282 | "description": "The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J", 283 | "price": 711, 284 | "category": "Computers", 285 | "brand": "Price - Kreiger", 286 | "sku": "e9103f86-ef38-4ff1-bb0e-ce55698411c0", 287 | "createdAt": "2020-11-23T20:20:54.246Z", 288 | "updatedAt": "2020-11-23T20:20:54.246Z", 289 | "__v": 0, 290 | "image": "https://www.furnituremanila.com.ph/wp-content/uploads/2016/10/KD-7113-4-metal-table.jpg" 291 | }, 292 | { 293 | "isActive": true, 294 | "id": "5fbc19a65a3f794d72471179", 295 | "product_name": "Refined Frozen Shirt", 296 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 297 | "price": 604, 298 | "category": "Baby", 299 | "brand": "Crooks - Waelchi", 300 | "sku": "0711b95f-6a94-441f-80a1-dfc8dc30d5d9", 301 | "createdAt": "2020-11-23T20:20:54.246Z", 302 | "updatedAt": "2020-11-23T20:20:54.246Z", 303 | "__v": 0 304 | }, 305 | { 306 | "isActive": true, 307 | "id": "5fbc19a65a3f794d7247117e", 308 | "product_name": "Handmade Granite Ball", 309 | "description": "The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J", 310 | "price": 217, 311 | "category": "Health", 312 | "brand": "Gusikowski LLC", 313 | "sku": "7b83c187-2f2b-4564-bf95-d9c3f9a67149", 314 | "createdAt": "2020-11-23T20:20:54.246Z", 315 | "updatedAt": "2020-11-23T20:20:54.246Z", 316 | "__v": 0 317 | }, 318 | { 319 | "isActive": true, 320 | "id": "5fbc19a65a3f794d7247117a", 321 | "product_name": "Rustic Soft Cheese", 322 | "description": "Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support", 323 | "price": 237, 324 | "category": "Kids", 325 | "brand": "Terry, Graham and Maggio", 326 | "sku": "3a3617a4-8067-4014-bcb8-8b6f1446271f", 327 | "createdAt": "2020-11-23T20:20:54.246Z", 328 | "updatedAt": "2020-11-23T20:20:54.246Z", 329 | "__v": 0 330 | }, 331 | { 332 | "isActive": true, 333 | "id": "5fbc19a65a3f794d72471180", 334 | "product_name": "Sleek Rubber Computer", 335 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 336 | "price": 196, 337 | "category": "Tools", 338 | "brand": "Fadel - Yundt", 339 | "sku": "f84cb15c-625a-4cdf-afe1-43d5d3ee5989", 340 | "createdAt": "2020-11-23T20:20:54.246Z", 341 | "updatedAt": "2020-11-23T20:20:54.246Z", 342 | "__v": 0 343 | }, 344 | { 345 | "isActive": true, 346 | "id": "5fbc19a65a3f794d72471178", 347 | "product_name": "Incredible Rubber Tuna", 348 | "description": "The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design", 349 | "price": 28, 350 | "category": "Outdoors", 351 | "brand": "Goodwin, Blick and Corwin", 352 | "sku": "15f8ddae-ee00-4f1b-83fb-ca542f22d485", 353 | "createdAt": "2020-11-23T20:20:54.246Z", 354 | "updatedAt": "2020-11-23T20:20:54.246Z", 355 | "__v": 0 356 | }, 357 | { 358 | "isActive": true, 359 | "id": "5fbc19a65a3f794d7247117f", 360 | "product_name": "Gorgeous Soft Keyboard", 361 | "description": "Boston's most advanced compression wear technology increases muscle oxygenation, stabilizes active muscles", 362 | "price": 752, 363 | "category": "Shoes", 364 | "brand": "Barton Inc", 365 | "sku": "684e4d4d-bf44-4a80-afc8-60d570269a2f", 366 | "createdAt": "2020-11-23T20:20:54.246Z", 367 | "updatedAt": "2020-11-23T20:20:54.246Z", 368 | "__v": 0 369 | }, 370 | { 371 | "isActive": true, 372 | "id": "5fbc19a65a3f794d72471183", 373 | "product_name": "Small Concrete Pants", 374 | "description": "New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart", 375 | "price": 278, 376 | "category": "Jewelery", 377 | "brand": "Carroll Inc", 378 | "sku": "ab0f6521-50c3-46df-b6da-b64c003f99f6", 379 | "createdAt": "2020-11-23T20:20:54.246Z", 380 | "updatedAt": "2020-11-23T20:20:54.246Z", 381 | "__v": 0 382 | }, 383 | { 384 | "isActive": true, 385 | "id": "5fbc19a65a3f794d72471185", 386 | "product_name": "Rustic Fresh Computer", 387 | "description": "Boston's most advanced compression wear technology increases muscle oxygenation, stabilizes active muscles", 388 | "price": 657, 389 | "category": "Grocery", 390 | "brand": "Waelchi - Zulauf", 391 | "sku": "cd1c32b3-bb64-4908-a83f-1944ab282785", 392 | "createdAt": "2020-11-23T20:20:54.246Z", 393 | "updatedAt": "2020-11-23T20:20:54.246Z", 394 | "__v": 0 395 | }, 396 | { 397 | "isActive": true, 398 | "id": "5fbc19a65a3f794d7247117d", 399 | "product_name": "Licensed Steel Salad", 400 | "description": "New range of formal shirts are designed keeping you in mind. With fits and styling that will make you stand apart", 401 | "price": 179, 402 | "category": "Toys", 403 | "brand": "Thiel, Hackett and Medhurst", 404 | "sku": "55673a96-3924-49f1-9de0-c37fd8593705", 405 | "createdAt": "2020-11-23T20:20:54.246Z", 406 | "updatedAt": "2020-11-23T20:20:54.246Z", 407 | "__v": 0 408 | }, 409 | { 410 | "isActive": true, 411 | "id": "5fbc19a65a3f794d7247118a", 412 | "product_name": "Refined Metal Tuna", 413 | "description": "The slim & simple Maple Gaming Keyboard from Dev Byte comes with a sleek body and 7- Color RGB LED Back-lighting for smart functionality", 414 | "price": 529, 415 | "category": "Health", 416 | "brand": "Quitzon, Metz and Luettgen", 417 | "sku": "d8bbfb98-9e4f-40a5-bf79-2ab7faae82f6", 418 | "createdAt": "2020-11-23T20:20:54.247Z", 419 | "updatedAt": "2020-11-23T20:20:54.247Z", 420 | "__v": 0 421 | }, 422 | { 423 | "isActive": true, 424 | "id": "5fbc19a65a3f794d72471182", 425 | "product_name": "Intelligent Granite Keyboard", 426 | "description": "Carbonite web goalkeeper gloves are ergonomically designed to give easy fit", 427 | "price": 840, 428 | "category": "Toys", 429 | "brand": "Feil, Carroll and Shanahan", 430 | "sku": "9408a5f6-77e4-4ba5-a173-81a4a7e31bcb", 431 | "createdAt": "2020-11-23T20:20:54.246Z", 432 | "updatedAt": "2020-11-23T20:20:54.246Z", 433 | "__v": 0 434 | }, 435 | { 436 | "isActive": true, 437 | "id": "5fbc19a65a3f794d72471184", 438 | "product_name": "Gorgeous Granite Soap", 439 | "description": "The Football Is Good For Training And Recreational Purposes", 440 | "price": 176, 441 | "category": "Grocery", 442 | "brand": "Runte, Little and Collins", 443 | "sku": "e02d7168-5226-40d8-8131-60d5d9fd135f", 444 | "createdAt": "2020-11-23T20:20:54.246Z", 445 | "updatedAt": "2020-11-23T20:20:54.246Z", 446 | "__v": 0 447 | }, 448 | { 449 | "isActive": true, 450 | "id": "5fbc19a65a3f794d72471188", 451 | "product_name": "Handmade Metal Pizza", 452 | "description": "Carbonite web goalkeeper gloves are ergonomically designed to give easy fit", 453 | "price": 523, 454 | "category": "Beauty", 455 | "brand": "Veum Group", 456 | "sku": "9386614a-4929-4459-9ef4-0cdf31144712", 457 | "createdAt": "2020-11-23T20:20:54.247Z", 458 | "updatedAt": "2020-11-23T20:20:54.247Z", 459 | "__v": 0 460 | }, 461 | { 462 | "isActive": true, 463 | "id": "5fbc19a65a3f794d7247118f", 464 | "product_name": "Intelligent Granite Keyboard", 465 | "description": "The beautiful range of Apple Naturalé that has an exciting mix of natural ingredients. With the Goodness of 100% Natural Ingredients", 466 | "price": 67, 467 | "category": "Shoes", 468 | "brand": "Kiehn, Heathcote and Roberts", 469 | "sku": "d9c6a142-aad5-40bb-9d71-5130ce4c7a80", 470 | "createdAt": "2020-11-23T20:20:54.247Z", 471 | "updatedAt": "2020-11-23T20:20:54.247Z", 472 | "__v": 0 473 | }, 474 | { 475 | "isActive": true, 476 | "id": "5fbc19a65a3f794d72471187", 477 | "product_name": "Handmade Rubber Towels", 478 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 479 | "price": 771, 480 | "category": "Games", 481 | "brand": "Lindgren - Bauch", 482 | "sku": "8df8b7a2-3f0c-4dc0-a22b-17fd0b888630", 483 | "createdAt": "2020-11-23T20:20:54.247Z", 484 | "updatedAt": "2020-11-23T20:20:54.247Z", 485 | "__v": 0 486 | }, 487 | { 488 | "isActive": true, 489 | "id": "5fbc19a65a3f794d7247118d", 490 | "product_name": "Intelligent Metal Shoes", 491 | "description": "Carbonite web goalkeeper gloves are ergonomically designed to give easy fit", 492 | "price": 803, 493 | "category": "Music", 494 | "brand": "Schowalter, Smitham and Ward", 495 | "sku": "9f83997a-7500-405b-a20a-9409d91a26a4", 496 | "createdAt": "2020-11-23T20:20:54.247Z", 497 | "updatedAt": "2020-11-23T20:20:54.247Z", 498 | "__v": 0 499 | }, 500 | { 501 | "isActive": true, 502 | "id": "5fbc19a65a3f794d72471189", 503 | "product_name": "Incredible Cotton Hat", 504 | "description": "The beautiful range of Apple Naturalé that has an exciting mix of natural ingredients. With the Goodness of 100% Natural Ingredients", 505 | "price": 775, 506 | "category": "Health", 507 | "brand": "Ferry and Sons", 508 | "sku": "b4036f0a-9988-4c56-ad0f-192d573a4654", 509 | "createdAt": "2020-11-23T20:20:54.247Z", 510 | "updatedAt": "2020-11-23T20:20:54.247Z", 511 | "__v": 0 512 | }, 513 | { 514 | "isActive": true, 515 | "id": "5fbc19a65a3f794d7247118e", 516 | "product_name": "Handmade Metal Bacon", 517 | "description": "New ABC 13 9370, 13.3, 5th Gen CoreA5-8250U, 8GB RAM, 256GB SSD, power UHD Graphics, OS 10 Home, OS Office A & J 2016", 518 | "price": 51, 519 | "category": "Games", 520 | "brand": "Marvin and Sons", 521 | "sku": "ebf8c2a1-58ea-44df-b5bb-416bd489225a", 522 | "createdAt": "2020-11-23T20:20:54.247Z", 523 | "updatedAt": "2020-11-23T20:20:54.247Z", 524 | "__v": 0 525 | }, 526 | { 527 | "isActive": true, 528 | "id": "5fbc19a65a3f794d72471192", 529 | "product_name": "Tasty Soft Shirt", 530 | "description": "The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design", 531 | "price": 445, 532 | "category": "Garden", 533 | "brand": "Williamson, Langworth and Kautzer", 534 | "sku": "36fc1158-46d3-45fa-b702-75fc396f26bd", 535 | "createdAt": "2020-11-23T20:20:54.247Z", 536 | "updatedAt": "2020-11-23T20:20:54.247Z", 537 | "__v": 0 538 | }, 539 | { 540 | "isActive": true, 541 | "id": "5fbc19a65a3f794d72471194", 542 | "product_name": "Sleek Granite Chair", 543 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 544 | "price": 329, 545 | "category": "Music", 546 | "brand": "Flatley and Sons", 547 | "sku": "715f2331-d317-4671-8e48-7ca2e2986a25", 548 | "createdAt": "2020-11-23T20:20:54.247Z", 549 | "updatedAt": "2020-11-23T20:20:54.247Z", 550 | "__v": 0 551 | }, 552 | { 553 | "isActive": true, 554 | "id": "5fbc19a65a3f794d7247118c", 555 | "product_name": "Gorgeous Soft Car", 556 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 557 | "price": 356, 558 | "category": "Home", 559 | "brand": "Wuckert - Hagenes", 560 | "sku": "4fdb9932-c3c1-4535-b5be-31ff89eb7fc1", 561 | "createdAt": "2020-11-23T20:20:54.247Z", 562 | "updatedAt": "2020-11-23T20:20:54.247Z", 563 | "__v": 0 564 | }, 565 | { 566 | "isActive": true, 567 | "id": "5fbc19a65a3f794d72471191", 568 | "product_name": "Ergonomic Concrete Bacon", 569 | "description": "The automobile layout consists of a front-engine design, with transaxle-type transmissions mounted at the rear of the engine and four wheel drive", 570 | "price": 450, 571 | "category": "Sports", 572 | "brand": "Lang - Dibbert", 573 | "sku": "ca5547fc-35a8-4a4a-9a96-93d19dc67393", 574 | "createdAt": "2020-11-23T20:20:54.247Z", 575 | "updatedAt": "2020-11-23T20:20:54.247Z", 576 | "__v": 0 577 | }, 578 | { 579 | "isActive": true, 580 | "id": "5fbc19a65a3f794d72471193", 581 | "product_name": "Rustic Rubber Keyboard", 582 | "description": "The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design", 583 | "price": 489, 584 | "category": "Computers", 585 | "brand": "Ward Inc", 586 | "sku": "70710d95-1924-4766-9012-2a347160d44a", 587 | "createdAt": "2020-11-23T20:20:54.247Z", 588 | "updatedAt": "2020-11-23T20:20:54.247Z", 589 | "__v": 0 590 | }, 591 | { 592 | "isActive": true, 593 | "id": "5fbc19a65a3f794d7247116d", 594 | "product_name": "Generic Steel Gloves", 595 | "description": "Carbonite web goalkeeper gloves are ergonomically designed to give easy fit", 596 | "price": 738, 597 | "category": "Electronics", 598 | "brand": "Kling, Ernser and Kemmer", 599 | "sku": "98f925d0-0ad1-4613-8c21-73d36d9384cd", 600 | "createdAt": "2020-11-23T20:20:54.246Z", 601 | "updatedAt": "2020-11-23T20:20:54.246Z", 602 | "__v": 0, 603 | "image": "https://images-na.ssl-images-amazon.com/images/I/81zKlvChO6L._AC_SY355_.jpg" 604 | }, 605 | { 606 | "isActive": true, 607 | "id": "5fbc19a65a3f794d72471172", 608 | "product_name": "Awesome Granite Computer", 609 | "description": "Boston's most advanced compression wear technology increases muscle oxygenation, stabilizes active muscles", 610 | "price": 946, 611 | "category": "Garden", 612 | "brand": "Sporer, Emard and Emard", 613 | "sku": "48a457ae-6c09-4561-9e2e-120bf3ff1c55", 614 | "createdAt": "2020-11-23T20:20:54.246Z", 615 | "updatedAt": "2020-11-23T20:20:54.246Z", 616 | "__v": 0, 617 | "image": "https://www.collinsdictionary.com/images/full/computer_49399603.jpg" 618 | }, 619 | { 620 | "isActive": true, 621 | "id": "5fbc19a65a3f794d72471177", 622 | "product_name": "Tasty Frozen Bike", 623 | "description": "Ergonomic executive chair upholstered in bonded black leather and PVC padded seat and back for all-day comfort and support", 624 | "price": 716, 625 | "category": "Toys", 626 | "brand": "Willms, Brown and Bartell", 627 | "sku": "1e72fdb0-fdf7-433a-bcf0-b78ee99e55eb", 628 | "createdAt": "2020-11-23T20:20:54.246Z", 629 | "updatedAt": "2020-11-23T20:20:54.246Z", 630 | "__v": 0 631 | }, 632 | { 633 | "isActive": true, 634 | "id": "5fbc19a65a3f794d7247117c", 635 | "product_name": "Refined Frozen Shoes", 636 | "description": "The Apollotech B340 is an affordable wireless mouse with reliable connectivity, 12 months battery life and modern design", 637 | "price": 425, 638 | "category": "Outdoors", 639 | "brand": "Pouros, Steuber and Reynolds", 640 | "sku": "d884f878-f131-4a94-88b1-54ff9d03a540", 641 | "createdAt": "2020-11-23T20:20:54.246Z", 642 | "updatedAt": "2020-11-23T20:20:54.246Z", 643 | "__v": 0 644 | }, 645 | { 646 | "isActive": true, 647 | "id": "5fbc19a65a3f794d72471181", 648 | "product_name": "Ergonomic Fresh Chair", 649 | "description": "Andy shoes are designed to keeping in mind durability as well as trends, the most stylish range of shoes & sandals", 650 | "price": 178, 651 | "category": "Computers", 652 | "brand": "Ebert - Bosco", 653 | "sku": "b5342e25-d1f7-4ba0-bd7b-bdb54f143fa0", 654 | "createdAt": "2020-11-23T20:20:54.246Z", 655 | "updatedAt": "2020-11-23T20:20:54.246Z", 656 | "__v": 0 657 | }, 658 | { 659 | "isActive": true, 660 | "id": "5fbc19a65a3f794d72471186", 661 | "product_name": "Sleek Concrete Hat", 662 | "description": "The automobile layout consists of a front-engine design, with transaxle-type transmissions mounted at the rear of the engine and four wheel drive", 663 | "price": 83, 664 | "category": "Kids", 665 | "brand": "Balistreri, Towne and Hermann", 666 | "sku": "c72c4638-636d-48e6-85e1-871c3c121c3a", 667 | "createdAt": "2020-11-23T20:20:54.247Z", 668 | "updatedAt": "2020-11-23T20:20:54.247Z", 669 | "__v": 0 670 | }, 671 | { 672 | "isActive": true, 673 | "id": "5fbc19a65a3f794d7247118b", 674 | "product_name": "Refined Cotton Fish", 675 | "description": "Carbonite web goalkeeper gloves are ergonomically designed to give easy fit", 676 | "price": 754, 677 | "category": "Music", 678 | "brand": "Raynor, Altenwerth and Glover", 679 | "sku": "50ed6705-d146-4435-b0a8-70f5a5b788fd", 680 | "createdAt": "2020-11-23T20:20:54.247Z", 681 | "updatedAt": "2020-11-23T20:20:54.247Z", 682 | "__v": 0 683 | }, 684 | { 685 | "isActive": true, 686 | "id": "5fbc19a65a3f794d72471190", 687 | "product_name": "Handmade Rubber Chips", 688 | "description": "The Nagasaki Lander is the trademarked name of several series of Nagasaki sport bikes, that started with the 1984 ABC800J", 689 | "price": 899, 690 | "category": "Books", 691 | "brand": "Lakin LLC", 692 | "sku": "04e64f0b-8884-4093-9392-0e34edd00832", 693 | "createdAt": "2020-11-23T20:20:54.247Z", 694 | "updatedAt": "2020-11-23T20:20:54.247Z", 695 | "__v": 0 696 | }, 697 | { 698 | "isActive": true, 699 | "id": "5fbc19a65a3f794d72471195", 700 | "product_name": "Awesome Rubber Fish", 701 | "description": "The Football Is Good For Training And Recreational Purposes", 702 | "price": 612, 703 | "category": "Grocery", 704 | "brand": "Dicki LLC", 705 | "sku": "53049c67-5903-40fc-bc70-c6a9d1071868", 706 | "createdAt": "2020-11-23T20:20:54.247Z", 707 | "updatedAt": "2020-11-23T20:20:54.247Z", 708 | "__v": 0 709 | } 710 | ] 711 | } -------------------------------------------------------------------------------- /endpoints/items.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router() 2 | const { validateToken } = require('../middlewares/jwt_validation') 3 | const { secret } = require('../config.js') 4 | 5 | router.post('/', validateToken(secret), (req, res) => { 6 | const { role } = req.user // Obtener el rol del usuario desde el token decodificado 7 | 8 | if (role !== 'ADMIN') { 9 | return res.status(403).send({ message: 'Forbidden. Only ADMIN can create items.' }) 10 | } 11 | 12 | const item = req.body 13 | router.db.get('items').push(item).write() 14 | res.send({ message: 'Item created successfully' }) 15 | }) 16 | 17 | module.exports = router 18 | -------------------------------------------------------------------------------- /endpoints/login.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require('bcrypt') 2 | const jwt = require('jsonwebtoken') 3 | const { validateEmail } = require('../utils/validations') 4 | const router = require('express').Router() 5 | const { secret } = require('../config.js') 6 | 7 | /* root: /login */ 8 | router.post('/', (req, res) => { 9 | const { email, password } = req.body 10 | 11 | if (!email || !password) { 12 | res.sendStatus(400) 13 | return 14 | } 15 | 16 | if (!validateEmail(email)) { 17 | res.status(400).send({ message: 'Invalid email format' }) 18 | return 19 | } 20 | 21 | const users = router.db.getState().users 22 | const user = users.find((user) => user.email === email) 23 | 24 | if (user) { 25 | bcrypt.compare(password, user.password, (err, result) => { 26 | if (result) { 27 | const token = jwt.sign({ id: user.id, role: user.role }, secret) 28 | res.send({ token }) 29 | } else { 30 | res.status(401).send(err) 31 | } 32 | }) 33 | } else { 34 | res.sendStatus(404) 35 | } 36 | }) 37 | 38 | module.exports = router 39 | -------------------------------------------------------------------------------- /endpoints/me.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router() 2 | const { validateToken } = require('../middlewares/jwt_validation') 3 | const { secret } = require('../config.js') 4 | 5 | router.get('/', validateToken(secret), (req, res) => { 6 | const { id } = req.user // Obtener el ID del usuario desde el token decodificado 7 | 8 | const users = router.db.getState().users 9 | 10 | const user = users.find(u => u.id === id) 11 | 12 | if (!user) { 13 | return res.status(404).send({ message: 'User not found' }) 14 | } 15 | 16 | const { password, ...userRest } = user // Remover el campo "password" de la información del usuario 17 | res.send(userRest) // Enviar todos los atributos del usuario, sin el campo "password" 18 | }) 19 | 20 | module.exports = router 21 | -------------------------------------------------------------------------------- /endpoints/register.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const bcrypt = require('bcrypt') 3 | const { validateEmail } = require('../utils/validations') 4 | const router = require('express').Router() 5 | 6 | /* root: /register */ 7 | router.post('/', (req, res) => { 8 | const { 9 | id, 10 | first_name, 11 | last_name, 12 | birth_date, 13 | gender, 14 | email, 15 | password, 16 | role, 17 | createdAt, 18 | updatedAt 19 | } = req.body 20 | 21 | if (!email || !password || (gender !== 'M' && gender !== 'F')) { 22 | res.sendStatus(400) 23 | return 24 | } 25 | 26 | if (!validateEmail(email)) { 27 | res.status(400).send({ message: 'Invalid email format' }) 28 | return 29 | } 30 | 31 | const users = router.db.getState().users 32 | 33 | const user = users.find((user) => user.email === email) 34 | if (!user) { 35 | bcrypt.hash(password, 10, (err, hashedPassword) => { 36 | if (err) { console.log(err.stack) } 37 | const user = { 38 | id, 39 | first_name, 40 | last_name, 41 | gender, 42 | birth_date, 43 | email, 44 | password: hashedPassword, 45 | role: role || 'CUSTOMER', 46 | createdAt, 47 | updatedAt 48 | } 49 | router.db.get('users').push(user).write() 50 | res.status(201).send({ message: 'User created successfully' }) 51 | }) 52 | } else { 53 | res.status(403).send({ message: 'Duplicated email' }) 54 | } 55 | }) 56 | 57 | module.exports = router 58 | -------------------------------------------------------------------------------- /endpoints/users.js: -------------------------------------------------------------------------------- 1 | const router = require('express').Router() 2 | const { validateToken } = require('../middlewares/jwt_validation') 3 | const { secret } = require('../config.js') 4 | 5 | router.get('/:id', validateToken(secret), (req, res) => { 6 | const { role } = req.user // Obtener el rol del usuario desde el token decodificado 7 | 8 | if (role !== 'ADMIN') { 9 | return res.status(403).send({ message: 'Forbidden. Only ADMIN can view user data.' }) 10 | } 11 | 12 | const users = router.db.getState().users 13 | const user = users.find(u => u.id === req.params.id) 14 | 15 | if (!user) return res.status(404).send('User not found') 16 | 17 | const { password, ...userRest } = user // Remuevo el password de la información del usuario que devolverá la API 18 | 19 | res.send(userRest) // Envío todos los atributos del usuario, sin el password 20 | }) 21 | 22 | router.get('/', validateToken(secret), (req, res) => { 23 | const { role } = req.user // Obtener el rol del usuario desde el token decodificado 24 | 25 | if (role !== 'ADMIN') { 26 | return res.status(403).send({ message: 'Forbidden. Only ADMIN can list users.' }) 27 | } 28 | 29 | const users = router.db.getState().users 30 | // Elimino el campo password de la lista de usuarios que devolverá la API 31 | const usersWithoutPassword = users.map(user => { 32 | const { password, ...userRest } = user 33 | return userRest 34 | }) 35 | 36 | res.send(usersWithoutPassword) // Envío todos los atributos del usuario, sin el password 37 | }) 38 | 39 | module.exports = router 40 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | const jsonServer = require('json-server') 3 | const path = require('path') 4 | const server = jsonServer.create() 5 | const router = jsonServer.router(path.join(__dirname, 'db.json')) 6 | 7 | const addIdAndTimeStamps = require('./middlewares/addIdAndTimeStamps') 8 | 9 | const loginEndpoint = require('./endpoints/login') 10 | const registerEndpoint = require('./endpoints/register') 11 | const itemsEndpoint = require('./endpoints/items') 12 | const usersEndpoint = require('./endpoints/users') 13 | const meEndpoint = require('./endpoints/me') 14 | 15 | const PORT = process.env.PORT || 3000 16 | 17 | server.use(jsonServer.defaults()) 18 | server.use(jsonServer.bodyParser) 19 | 20 | // Middleware para añadir id y timestamps a los objetos que se crean 21 | server.use(addIdAndTimeStamps) 22 | 23 | // Middleware para redireccionar '/users/me' a '/me', ya que json-server no soporta rutas anidadas 24 | server.use((req, res, next) => { 25 | if (req.url === '/users/me') { 26 | req.url = '/me' 27 | } 28 | next() 29 | }) 30 | 31 | // Pasa la instancia de router.db a los endpoints 32 | usersEndpoint.db = router.db 33 | itemsEndpoint.db = router.db 34 | loginEndpoint.db = router.db 35 | registerEndpoint.db = router.db 36 | meEndpoint.db = router.db 37 | 38 | // Ruta '/login' manejada por el endpoint login.js 39 | server.use('/login', loginEndpoint) 40 | 41 | // Ruta '/register' manejada por el endpoint register.js 42 | server.use('/register', registerEndpoint) 43 | 44 | // Ruta '/items' manejada por el endpoint items.js 45 | server.use('/items', itemsEndpoint) 46 | 47 | // Rutas '/users/:id' y '/users' manejadas por el endpoint users.js 48 | server.use('/users', usersEndpoint) 49 | 50 | // Ruta '/me' manejada por el endpoint me.js 51 | server.use('/me', meEndpoint) 52 | 53 | server.use(router) 54 | 55 | // Levantamos el servidor 56 | server.listen(PORT, () => { 57 | console.log('JSON Server is running on http://localhost:' + PORT) 58 | }) 59 | -------------------------------------------------------------------------------- /middlewares/addIdAndTimeStamps.js: -------------------------------------------------------------------------------- 1 | const { v4: uuidv4 } = require('uuid') 2 | 3 | const addIdAndTimeStamps = (req, res, next) => { 4 | if (req.method === 'POST') { 5 | req.body.id = uuidv4() 6 | req.body.createdAt = Date.now() 7 | req.body.updatedAt = Date.now() 8 | } 9 | next() 10 | } 11 | 12 | module.exports = addIdAndTimeStamps 13 | -------------------------------------------------------------------------------- /middlewares/jwt_validation.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken') 2 | 3 | function validateToken (secret) { 4 | return (req, res, next) => { 5 | const { authorization } = req.headers 6 | console.log(authorization) 7 | if (!authorization || !authorization.startsWith('Bearer ')) { 8 | res.sendStatus(400) 9 | return 10 | } 11 | const token = authorization.slice(7) 12 | try { 13 | const payload = jwt.verify(token, secret) 14 | req.user = payload 15 | next() 16 | } catch (error) { 17 | res.sendStatus(401) 18 | } 19 | } 20 | } 21 | 22 | module.exports = { 23 | validateToken 24 | } 25 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-server-jwt", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1", 11 | "dev": "nodemon ./index.js", 12 | "start": "node ./index.js" 13 | }, 14 | "author": "César Guerra", 15 | "license": "ISC", 16 | "dependencies": { 17 | "bcrypt": "^5.1.1", 18 | "json-server": "^0.17.4", 19 | "jsonwebtoken": "^9.0.2", 20 | "uuid": "^11.1.0" 21 | }, 22 | "devDependencies": { 23 | "nodemon": "^3.1.10", 24 | "standard": "^17.1.2" 25 | }, 26 | "eslintConfig": { 27 | "extends": [ 28 | "./node_modules/standard/eslintrc.json" 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Mock de API con Autenticación usando JWT 2 | 3 | El objetivo es crear un mock de una API Rest de eCommerce que haga uso de autenticación con JWT y cuente con algunas rutas protegidas. 4 | 5 | Para usarlo: 6 | 1) Haz git clone del repositorio: `git clone https://github.com/warderer/json-server-jwt.git` 7 | 2) Desde la terminal, recuerda entrar a la carpeta del proyecto: `cd json-server-jwt` 8 | 3) Instala las dependencias con el comando: `npm install` 9 | 4) Ejecuta el servidor con el comando: `npm run start` 10 | 11 | ## Despliegue en Render (opcional) 12 | Si lo deseas puedes hacer deployment de este repositorio en tu cuenta de Render: 13 | 1) Crea una cuenta en [Render](https://render.com/) e inicia sesión. 14 | 2) Una vez iniciada la sesión, ve a la página de "Dashboard", y luego ubica el apartado de "Web Services" y haz click en el botón "New Web Service". 15 | 3) En la siguiente pantalla de "Create a New Service", utiliza la segunda opción "Public Web Repository", coloca en la casilla la url del repo de github (https://github.com/warderer/json-server-jwt) y haz click en el botón "Continue". 16 | 4) En la siguiente pantalla de "You are deploying a web service for warderer/json-server-jwt" deberás rellenar la siguiente información: 17 | - **Name:** Nombre del proyecto, sin espacios ni carácteres especiales. Debe ser único ya que la url se generará a partir de esto. 18 | - **Region:** Ubicación físical del servidor. Elije el más cercano a tu ubicación o deja el valor por defecto. 19 | - **Branch:** Debe estar en main. 20 | - **Runtime:** Elige Node. 21 | - **Build Command:** Escribe: npm install 22 | - **Start Command:** Escribe: npm run start 23 | - **Instance Type:** Deja la opción por defecto de "Free" (Gratis). 24 | 5) Finalmente haz click en el botón de Create Web Service al final de la página y a esperar que se haga el deployment. 25 | 6) Una vez terminado el deployment, podrás ver la URL para acceder a tu API en la esquina superior izquierda de la pantalla de la página de Render. 26 | 27 | **Nota: Recuerda que en el plan gratuito de Render, si el servidor pasa mucho tiempo en inactividad se "dormirá" por lo que cuando hagas una primera petición este puede tardar un poco en contestar por que esta "levantandose", después de esto responderá normal mientras siga en uso (permanezca despierto).** 28 | 29 | ## Endpoints 30 | Por defecto el servidor se ejecuta en: http://localhost:3000 31 | 32 | Donde existen las rutas de `items` y de `users` 33 | 34 | ### users 35 | 36 | #### Register 37 | `POST` 38 | `/register` 39 | 40 | ``` 41 | { 42 | "first_name": "Dr.", 43 | "last_name": "Strange", 44 | "gender": "M", 45 | "email": "drstrange@marvel.com", 46 | "password": "multiverso", 47 | "role": "CUSTOMER" 48 | } 49 | ``` 50 | Al crearse un registro, automaticamente la API creará los campos `id`, `createdAt` y `updatedAt`. 51 | Si no se especifica un `role`, como por ejemplo `ADMIN`, entonces por defecto será `CUSTOMER`. 52 | El correo es único, si se repite devolverá error al intentar registrar uno ya creado anteriormente. 53 | 54 | #### Login 55 | `POST` 56 | `/login` 57 | ``` 58 | { 59 | "email": "drstrange@marvel.com", 60 | "password": "multiverso" 61 | } 62 | ``` 63 | Al iniciar sesión se devolvera un JWT que contiene, entre otras cosas el `id` y `role` del usuario en el payload. 64 | 65 | #### getAllUsers 66 | `GET` 67 | `/users` 68 | 69 | `headers: AUTHORIZATION` 70 | `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjFjMzExNTUxLTA3NGEtNDIyNi05NzU4LWYwNzgwYzQyNzYxMiIsInJvbGUiOiJDVVNUT01FUiIsImlhdCI6MTY3NDk2MDMxNH0.5Ee8qu7YYcv0Egc2MOj8PQKMA0QHEf3shn0gnZuR-iA` 71 | 72 | Solo un usuario de `type: "ADMIN"` puede visualizar el listado de usuarios. 73 | 74 | #### getOneUser 75 | `GET` 76 | `/users/:id` 77 | 78 | `headers: AUTHORIZATION` 79 | `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjFjMzExNTUxLTA3NGEtNDIyNi05NzU4LWYwNzgwYzQyNzYxMiIsInJvbGUiOiJDVVNUT01FUiIsImlhdCI6MTY3NDk2MDMxNH0.5Ee8qu7YYcv0Egc2MOj8PQKMA0QHEf3shn0gnZuR-iA` 80 | 81 | Solo un usuario de `type: "ADMIN"` puede visualizar el detalle de un usuario por id. 82 | 83 | #### me 84 | `GET` 85 | `/users/me` 86 | 87 | `headers: AUTHORIZATION` 88 | `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjFjMzExNTUxLTA3NGEtNDIyNi05NzU4LWYwNzgwYzQyNzYxMiIsInJvbGUiOiJDVVNUT01FUiIsImlhdCI6MTY3NDk2MDMxNH0.5Ee8qu7YYcv0Egc2MOj8PQKMA0QHEf3shn0gnZuR-iA` 89 | 90 | Devolverá la información del usuario actual de acuerdo al Token proporcionado. 91 | 92 | ### items 93 | 94 | #### createItem 95 | `POST` 96 | `/items` 97 | 98 | `headers: AUTHORIZATION` 99 | `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjFjMzExNTUxLTA3NGEtNDIyNi05NzU4LWYwNzgwYzQyNzYxMiIsInJvbGUiOiJDVVNUT01FUiIsImlhdCI6MTY3NDk2MDMxNH0.5Ee8qu7YYcv0Egc2MOj8PQKMA0QHEf3shn0gnZuR-iA` 100 | 101 | ``` 102 | { 103 | "product_name": "Awesome Granite Bacon", 104 | "description": "The beautiful range of Apple Naturalé that has an exciting mix of natural ingredients. With the Goodness of 100% Natural Ingredients", 105 | "price": 962, 106 | "category": "Kids", 107 | "brand": "Osinski - Prosacco", 108 | "sku": "e9cbfac1-301a-42c3-b94a-711a39dc7ed1", 109 | "image": "https://i.pinimg.com/originals/eb/83/be/eb83be580847bcdc4c8f403c8085d3c8.jpg" 110 | } 111 | ``` 112 | Debe haberse iniciado sesión y enviar el token en la cabecera de la petición para que pueda ser creado un producto. 113 | 114 | #### getAllItems 115 | `GET` 116 | `/items` 117 | Lista todos los Items. 118 | 119 | #### GetOneItem 120 | `GET` 121 | `/items/:id` 122 | Devuelve un solo item de acuerdo al id proporcionado. 123 | 124 | ## Usuarios de prueba 125 | Por defecto la API ya viene con 2 usuarios para poder comenzar a probar inmediatamente: 126 | 127 | ### Usuario tipo "CUSTOMER" 128 | ``` 129 | { 130 | "email": "drstrange@marvel.com", 131 | "password": "multiverso" 132 | } 133 | ``` 134 | 135 | ### Usuario tipo "ADMIN" 136 | ``` 137 | { 138 | "email": "superman@dc.com", 139 | "password": "superman" 140 | } 141 | ``` 142 | -------------------------------------------------------------------------------- /utils/validations.js: -------------------------------------------------------------------------------- 1 | function validateEmail (email) { 2 | const re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ 3 | return re.test(String(email).toLowerCase()) 4 | } 5 | 6 | module.exports = { 7 | validateEmail 8 | } 9 | --------------------------------------------------------------------------------