diff --git a/db/fruit_db.js b/db/fruit_db.js new file mode 100644 index 0000000000000000000000000000000000000000..a3aec6672cf3d9dcd45d94e2af1854259da37e32 --- /dev/null +++ b/db/fruit_db.js @@ -0,0 +1,10 @@ +module.exports = fruit_db = [ + { "name": "Apple", "colors": ["red", "green", "yellow"], "inSeason": true }, + { "name": "Orange", "colors": ["orange"], "inSeason": true }, + { "name": "Grapes", "colors": ["purple", "green"], "inSeason": false }, + { "name": "Lime", "colors": ["green"], "inSeason": false }, + { "name": "Banana", "colors": ["yellow"], "inSeason": false }, + { "name": "Watermelon", "colors": ["red"], "inSeason": false }, + { "name": "Blueberry", "colors": ["blue"], "inSeason": true }, + { "name": "Coconut", "colors": ["white"], "inSeason": true } +] \ No newline at end of file diff --git a/get.rest b/get.rest index 0a092833f18442cf7364d28e898dc4609ae32a1e..0472ce41d1c0759bff5712c550bc2b9e117611dc 100644 --- a/get.rest +++ b/get.rest @@ -1,24 +1,28 @@ @host = http://127.0.0.1:3000 -GET {{host}}/fruit?name=b HTTP/1.1 +### +GET {{host}}/fruit HTTP/1.1 ### -GET {{host}}/fruit?name=b&inSeason=true HTTP/1.1 +GET {{host}}/fruit?name=a HTTP/1.1 ### -GET {{host}}/fruit?colors=red HTTP/1.1 +GET {{host}}/fruit?inSeason=false&name=b HTTP/1.1 ### -GET {{host}}/fruit?limit=4 HTTP/1.1 +GET {{host}}/fruit?colors=green,red HTTP/1.1 + +### +GET {{host}}/fruit?limit=2&offset=2 HTTP/1.1 ### GET {{host}}/fruit?limit=3&offset=1&name=b HTTP/1.1 ### -GET {{host}}/fruit?offset=3 HTTP/1.1 +GET {{host}}/fruit?offset=7 HTTP/1.1 ### -GET {{host}}/fruit HTTP/1.1 +GET {{host}}/fruit?ahag=1&name=b HTTP/1.1 ### GET https://apiest.herokuapp.com/fruit diff --git a/index.js b/index.js index 9e9265ea2642bdd957f8dfddaf5a49abad9e782d..6871227d09538bb146b72f60a5ab27fdd7ddf591 100644 --- a/index.js +++ b/index.js @@ -1,95 +1,32 @@ +// set up web server and begin listening + const express = require('express') const app = express() -const qs = require('qs') -const https = require('https') - -const fruit_db = [ - { "name": "Apple", "colors": ["red", "green", "yellow"], "inSeason": true }, - { "name": "Orange", "colors": ["orange"], "inSeason": true }, - { "name": "Grapes", "colors": ["purple", "green"], "inSeason": false }, - { "name": "Lime", "colors": ["green"], "inSeason": false }, - { "name": "Banana", "colors": ["yellow"], "inSeason": false }, - { "name": "Watermelon", "colors": ["red"], "inSeason": false }, - { "name": "Blueberry", "colors": ["blue"], "inSeason": true }, - { "name": "Coconut", "colors": ["white"], "inSeason": true } -] - -const default_search_model = { - - model: 1, - offset: 0, - limit: 5 -} - -const fruit_mixin = { - - inSeason: null, - colors: null, - name: null -} - -let fruit_model = { ...default_search_model, ...fruit_mixin } - -const parse_qs = ( qs_object_input, model_input ) => { - - let object = { ...qs_object_input } - let results = [ ...fruit_db ] - - if( object.colors ){ - object.colors = qs_object_input.colors.split(',') - } - - if( !model_input ){ let model = default_search_model } - - let query_object = { ...model_input } - - Object.assign(query_object, object) - - //5 parameters: offset, limit, inSeason, color, name - - if ( query_object.name ){ - let regex = new RegExp('^'+query_object.name.toLowerCase()+'') - results = results.filter( - fruit => fruit.name.toLowerCase().match(regex) - ) - } - - if( query_object.colors ){ +const PORT = process.env.PORT || 3000 - results = results.filter( - fruit => fruit.colors.some( - c => query_object.colors.includes(c) - ) - ) - } +app.listen( PORT, ( err )=>{ + if( err ){ console.log( err )} + console.log(`Server running on ${PORT}`) +}) - if( query_object.inSeason ){ +// import API specific modules - results = results.filter( - fruit => fruit.inSeason - ) - } - - if( query_object.offset ){ +const query_sanitizer = require('./js/query_sanitizer') +const parse_query_into_results = require('./js/parse_query_into_results') - results = results.slice( query_object.offset ) - } +// import DB - results = results.slice( 0, query_object.limit ) +const fruit_db = require('./db/fruit_db') - return results -} +// API app.get('/fruit', (req,res)=>{ - let model = fruit_model - let qs_object = qs.parse(req._parsedUrl.query) - res.json( parse_qs( qs_object, model ) ) -}) - -const PORT = process.env.PORT || 3000 - -app.listen(PORT, (err)=>{ - console.log("%c Server running", "color: green") + let { params, response } = query_sanitizer( req.query ) + if( response.code === 400 ){ + res.status(response.code).send({ error: response.string }) + } else { + res.json( parse_query_into_results( params, fruit_db ) ) + } }) \ No newline at end of file diff --git a/js/parse_query_into_results.js b/js/parse_query_into_results.js new file mode 100644 index 0000000000000000000000000000000000000000..33b0656c83fe1664781e42b6bdda9246e5ea6cc4 --- /dev/null +++ b/js/parse_query_into_results.js @@ -0,0 +1,49 @@ +module.exports = parse_query_into_results = ( query_params, db ) => { + + let fruit_db = db + let params = { ...query_params } + + //5 parameters: offset, limit, inSeason, color, name + + let results = [ ...fruit_db ] + + if ( params.name ){ + + let name = params.name.toLowerCase() + + results = results.filter( + fruit => fruit.name.toLowerCase().slice(0,name.length) === name + ) + } + + if( params.colors ){ + + results = results.filter( + fruit => fruit.colors.some( + color => params.colors.includes( color ) + ) + ) + } + + if( params.inSeason === "true" ){ // inSeason set to "true" + + results = results.filter( + fruit => fruit.inSeason + ) + + } else if ( params.inSeason === "false" ){// inSeason set to "false" + + results = results.filter( + fruit => !fruit.inSeason + ) + } + + if( params.offset ){ + + results = results.slice( params.offset ) + } + + results = results.slice( 0, params.limit ) + + return results +} diff --git a/js/query_sanitizer.js b/js/query_sanitizer.js new file mode 100644 index 0000000000000000000000000000000000000000..66975fba1cc3adaf78a9c2e022761ea434be492c --- /dev/null +++ b/js/query_sanitizer.js @@ -0,0 +1,47 @@ +module.exports = query_sanitizer = ( req_query ) => { + + const base_params = { + limit: 5, + } + + const response = { + code: '', + string: '' + } + + let query_params = { ...req_query } + + if( query_params.offset ){ + + let offset = Number( query_params.offset ) + if( !Number.isInteger( offset ) || offset < 0 || offset > ( fruit_db.length - 1 ) ){ + response.code = 400 + response.string = + `Offset must be an integer value between 0 and ${ fruit_db.length - 1 }.` + } + } + + if( query_params.limit ){ + + let limit = Number( query_params.limit ) + if( !Number.isInteger( limit ) || limit < 1 || limit > ( fruit_db.length ) ){ + response.code = 400 + response.string = + `Limit must be an integer value between 1 and ${ fruit_db.length }.` + } + } + + if( query_params.inSeason ){ + + let inSeason = query_params.inSeason + if(inSeason !== "true" && inSeason !== "false"){ + response.code = 400 + response.string = + `inSeason must be set to either true or false` + } + } + + let params = Object.assign( base_params, query_params ) + + return { params, response } +} \ No newline at end of file diff --git a/package.json b/package.json index 6abd673bac4e541635b60d85558ea99e4c0f4476..614ef251d1e91e864b7c7eb82f86c1f6448e3b86 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,6 @@ "license": "ISC", "dependencies": { "express": "^4.17.1", - "https": "^1.0.0", - "parse": "^2.15.0", "qs": "^6.9.4", "regex": "^0.1.1" }