-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathserver.js
242 lines (192 loc) · 5.46 KB
/
server.js
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
// server.js
// where your node app starts
// init project
require('dotenv').config();
var express = require('express');
var app = express();
const dns = require('dns').promises
const bodyParser = require('body-parser')
const url = require('url')
const uuid = require('uuid')
// enable CORS (https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)
// so that your API is remotely testable by FCC
var cors = require('cors');
app.use(cors({optionsSuccessStatus: 200})); // some legacy browsers choke on 204
// http://expressjs.com/en/starter/static-files.html
app.use(express.static('public'));
app.use((req, res, next) => {
console.log(req.method, ':', req.originalUrl);
next()
})
// http://expressjs.com/en/starter/basic-routing.html
app.get("/", function (req, res) {
res.sendFile(__dirname + '/views/index.html');
});
// your first API endpoint...
app.get("/api/hello", function (req, res) {
res.json({greeting: 'hello API'});
});
// Request Header Parser Microservice
app.get('/api/whoami', (req, res) => {
// A request to /api/whoami should return a JSON object with your IP address in the ipaddress key.
// A request to /api/whoami should return a JSON object with your preferred language in the language key.
// A request to /api/whoami should return a JSON object with your software in the software key.
res.json({
ipaddress: req.ip,
language: req.headers['accept-language'] || '',
software: req.headers['user-agent'] || '',
})
})
// URL Shortener Microservice
const SHORT_URLS = { counter: 0 };
function shortenURL(url) {
if (!(url in SHORT_URLS)) {
SHORT_URLS.counter += 1
let id = SHORT_URLS.counter.toString(16);
SHORT_URLS[id] = url
SHORT_URLS[url] = id
}
return SHORT_URLS[url]
}
app.post('/api/shorturl', bodyParser.urlencoded({ extended: false}), async (req, res) => {
const { url: urlToShort } = req.body
try {
if(!/^https?:\/\/.+/.test(urlToShort))
throw 'Invalid URL'
if (!/^https?:\/\/localhost.*/.test(urlToShort)) {
const hostName = new url.URL(urlToShort).hostname
await dns.lookup(hostName)
}
res.send({
original_url : urlToShort,
short_url : shortenURL(urlToShort)
})
} catch (err) {
console.log(err);
res.json({ error: 'Invalid URL'})
}
})
app.get('/api/shorturl/:short', (req, res) => {
const {short: shortURL} = req.params
if (!shortURL)
res.json({ error: 'Invalid short URL' })
else {
const decodedURL = SHORT_URLS[shortURL]
if (!decodedURL)
res.json({ error: 'Invalid short URL' })
else
res.redirect(decodedURL)
}
})
// Timestamp Microservice
const INVALID_DATE_RESPONSE = { error: 'Invalid Date' };
function parseDate(date) {
if (!date)
return new Date()
else if (/^\d+$/.test(date))
return new Date(+date)
else
return new Date(date)
}
app.get('/api/time/:date?', (req, res) => {
console.log(req.params);
const { date } = req.params
// NOTE JS date is in MILIseconds while UNIX time is in seconds
const parsedDate = parseDate(date)
if (parsedDate.toString() !== "Invalid Date") {
// looks like a valid date
res.json({
unix: parsedDate.getTime(),
utc: parsedDate.toUTCString()
})
} else {
res.json(INVALID_DATE_RESPONSE)
}
})
// Exercise Tracker
const users = {}
const exercises = {}
const usersRouter = express.Router()
// register form data parser fot this router
usersRouter.use(bodyParser.urlencoded({ extended: false }))
// create user
usersRouter.post('/', (req, res) => {
const { username } = req.body
const _id = uuid.v4();
const newUser = { username, _id }
users[_id] = newUser
res.json(newUser)
})
// get all users
usersRouter.get('/', (_,res) => {
res.json(Object.values(users))
})
// post an exercise
usersRouter.post('/:_id/exercises', (req, res) => {
const { _id } = req.params
const user = users[_id]
if (user) {
const {
duration, description,
date = new Date().getTime()
} = req.body
const exerc = { ...user,
description: String(description),
duration: Number(duration),
date: new Date(date).getTime()
}
if (!(_id in exercises))
exercises[_id] = []
exercises[_id].push(exerc)
res.json({
...exerc,
date: new Date(exerc.date).toDateString()
})
}
})
function parseDateParam(date) {
if (!date) return;
date = new Date(date)
if (date.toString().toLowerCase() !== 'invalid date') {
return date.getTime()
}
else
return
}
function parseLimitParam(limit) {
if (!limit) return;
limit = Number(limit)
if (isNaN(limit))
limit = Infinity
return limit
}
function formatExerc(x) {
return ({
description: x.description,
date: new Date(x.date).toDateString(),
duration: x.duration
})
}
usersRouter.get('/:id/logs', (req, res) => {
const { id } = req.params
let log = exercises[id]
const from = parseDateParam(req.query.from),
to = parseDateParam(req.query.to),
limit = parseLimitParam(req.query.limit);
if (from || to || limit) {
console.log('get filtered log');
if (from) log = log.filter(x => x.date >= from )
if (to) log = log.filter(x => x.date <= to)
if (limit)log = log.slice(0, limit)
}
res.json({
...users[id],
count: log.length,
log: log.map(formatExerc)
})
})
app.use('/api/users', usersRouter)
// listen for requests :)
var listener = app.listen(process.env.PORT || 3000, function () {
console.log('Your app is listening on port ' + listener.address().port);
});