diff --git a/index.js b/index.js index b26f649..6e68f7a 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ const express = require('express'); const axios = require('axios'); const redis = require('redis'); const cors = require('cors'); +const { param, validationResult } = require('express-validator'); const app = express(); const redisConfig = { @@ -19,7 +20,7 @@ client.on('error', (err) => { app.use(cors()); function LeagueSeason(leagueID, year) { - this.params = {league: leagueID, season: year} + this.params = { league: leagueID, season: year } this.headers = { 'x-rapidapi-host': process.env.API_HOST, 'x-rapidapi-key': process.env.API_KEY, @@ -98,39 +99,52 @@ app.get('/championship', async (req, res) => { } }); -app.get('/v2/:league/:year', async (req, res) => { - const league = req.params.league; - const year = req.params.year; - const query = league + year; - try { - client.get(query, async (err, leagueTable) => { - if (err) throw err; +app.get('/v2/:league/:year', + [ + // League id must be one of these + param('league').isIn(['39', '40', '41', '42']), + // Year must be no earlier than 2018 + param('year').isIn(['2018', '2019', '2020', '2021']), + ], + async (req, res) => { + // Validate + const errors = validationResult(req); + if (!errors.isEmpty()) { + return res.status(422).json({ errors: errors.array() }); + } + // Begin method + const league = req.params.league; + const year = req.params.year; + const query = league + year; + try { + client.get(query, async (err, leagueTable) => { + if (err) throw err; - // Return cached league table if present - if (leagueTable) { - res.status(200).send({ - table: JSON.parse(leagueTable), - message: 'data retrieved from cache', - }); - } else { - // Fetch from the API - reqSeason = new LeagueSeason(league, year); - const leagueTable = await axios.get( - 'https://v3.football.api-sports.io/standings', - reqSeason - ); - // Save result to cache - client.setex(query, 43200, JSON.stringify(leagueTable.data)); - // Return data from API - res.status(200).send({ - table: leagueTable.data, - message: 'cache miss', - }); - } - }); - } catch (err) { - res.status(500).send({ message: err.message }); - } + // Return cached league table if present + if (leagueTable) { + res.status(200).send({ + table: JSON.parse(leagueTable), + message: 'data retrieved from cache', + }); + } else { + // Fetch from the API + reqSeason = new LeagueSeason(league, year); + const leagueTable = await axios.get( + 'https://v3.football.api-sports.io/standings', + reqSeason + ); + // Save result to cache + client.setex(query, 43200, JSON.stringify(leagueTable.data)); + // Return data from API + res.status(200).send({ + table: leagueTable.data, + message: 'cache miss', + }); + } + }); + } catch (err) { + res.status(500).send({ message: err.message }); + } }); app.listen(process.env.PORT || 3001, () => { diff --git a/package-lock.json b/package-lock.json index 9079750..6b1bfd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,15 @@ "axios": "^0.21.1", "cors": "^2.8.5", "express": "^4.17.1", + "express-validator": "^6.12.1", "redis": "^3.1.2" }, "devDependencies": { "dotenv": "^10.0.0", "nodemon": "^2.0.12" + }, + "engines": { + "node": "14.x" } }, "node_modules/@sindresorhus/is": { @@ -668,6 +672,18 @@ "node": ">= 0.10.0" } }, + "node_modules/express-validator": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.12.1.tgz", + "integrity": "sha512-olpTAv0ZB5IhNuDQ2rodKAuJsewgFgLIsczJMAWD6T0Yvxsa+j/Hk61jl8e26lAq+oJr6hUqPRjdlOBKhFlWeQ==", + "dependencies": { + "lodash": "^4.17.21", + "validator": "^13.5.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1077,6 +1093,11 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -1866,6 +1887,14 @@ "node": ">= 0.4.0" } }, + "node_modules/validator": { + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", + "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -2450,6 +2479,15 @@ } } }, + "express-validator": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.12.1.tgz", + "integrity": "sha512-olpTAv0ZB5IhNuDQ2rodKAuJsewgFgLIsczJMAWD6T0Yvxsa+j/Hk61jl8e26lAq+oJr6hUqPRjdlOBKhFlWeQ==", + "requires": { + "lodash": "^4.17.21", + "validator": "^13.5.2" + } + }, "fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2743,6 +2781,11 @@ "package-json": "^6.3.0" } }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", @@ -3343,6 +3386,11 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "validator": { + "version": "13.6.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-13.6.0.tgz", + "integrity": "sha512-gVgKbdbHgtxpRyR8K0O6oFZPhhB5tT1jeEHZR0Znr9Svg03U0+r9DXWMrnRAB+HtCStDQKlaIZm42tVsVjqtjg==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", diff --git a/package.json b/package.json index afe7e58..f80c6cf 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "axios": "^0.21.1", "cors": "^2.8.5", "express": "^4.17.1", + "express-validator": "^6.12.1", "redis": "^3.1.2" } }