-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
158 lines (134 loc) · 3.58 KB
/
server.js
File metadata and controls
158 lines (134 loc) · 3.58 KB
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
const express = require('express');
const cors = require('cors');
const isDevMode = process.env.NEXT_PUBLIC_DEV_MODE;
// defaults
const API_PORT = 8080;
const API_BASE = 'api/v1';
const ENDPOINT_OBJECT = 'pokemon';
// construct endpoints from defaults
const ENDPOINTS = {
GET: `/${API_BASE}/${ENDPOINT_OBJECT}`,
GET_BY_ID: `/${API_BASE}/${ENDPOINT_OBJECT}/:id`,
};
// pagination
const PAGINATION_IGNORE_PARAMS = ['pageIndex', 'pageSize'];
const PAGINATION_DEFAULT_PAGE_INDEX = 0;
const PAGINATION_DEFAULT_PAGE_SIZE = 20;
// sample data - can also pull from DB or other source
const dataFilePath = './sample-data/pokemon.json';
const data = require(dataFilePath);
// init app
const app = express();
// middlewhere
app.use(cors());
app.use(express.json());
// cors
app.use(function (_req, rest, next) {
rest.header('Access-Control-Allow-Origin', '*');
rest.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-Width Content-Type, Accept',
);
next();
});
// some helper methods
// return all data []
const getAllData = () => {
if (data) {
return data;
} else {
return [];
}
};
// return singular item {}
const getById = id => {
if (!id) return;
const availableData = getAllData();
if (availableData.length) {
const foundItem = availableData.find(item => {
return item.id === Number(id);
});
return foundItem;
}
};
const getFilteredKeys = dataQuery => {
return Object.keys(dataQuery)
.filter(key => !PAGINATION_IGNORE_PARAMS.includes(key))
.reduce((obj, key) => {
obj[key] = dataQuery[key];
return obj;
}, {});
};
/*
Endpoints
*/
// api/v1/${ENDPOINT_OBJECT}
app.get(ENDPOINTS.GET, (req, res) => {
if (isDevMode) {
console.log(ENDPOINTS.GET);
console.log('Query:', req.query);
}
const availableData = getAllData();
try {
// query string object
const dataQuery = req.query;
// pagination
const pageIndex = dataQuery.pageIndex
? parseInt(dataQuery.pageIndex)
: PAGINATION_DEFAULT_PAGE_INDEX;
const pageSize = dataQuery.pageSize
? parseInt(dataQuery.pageSize)
: PAGINATION_DEFAULT_PAGE_SIZE;
// calculate the start and end indexes for the requested page
const startIndex = pageIndex * pageSize;
const endIndex = (pageIndex + 1) * pageSize;
// ignore pagination params
const filteredKeys = getFilteredKeys(dataQuery);
const filteredData = availableData.filter(item => {
let isValid = true;
for (key in filteredKeys) {
// loose
isValid = isValid && item[key] == dataQuery[key];
}
return isValid;
});
// slice the products array based on the indexes
const paginatedData = filteredData.slice(startIndex, endIndex);
// send the paginated data and count of returned data
// if pagination params are not passed, send filtered data
res.json({
data:
dataQuery.pageIndex && dataQuery.pageSize
? paginatedData
: filteredData,
count: filteredData.length,
});
} catch (err) {
res.send(err.message);
}
});
// api/v1/${ENDPOINT_OBJECT}/:id
app.get(ENDPOINTS.GET_BY_ID, (req, res) => {
const foundItem = getById(req.params.id);
if (isDevMode) {
console.info(foundItem);
}
if (foundItem) {
res.send(foundItem);
} else {
res.status(404).send('Item not found');
}
});
/*
Error Handling
*/
app.get('*', function (_req, res) {
res.status(404).send({ status: 404, message: 'Invalid endpoint.' });
});
/*
Server listener
*/
app.listen(API_PORT, () => {
if (process.env.DEV_MODE)
console.info(`Server listening on port ${API_PORT}`);
});