diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..4d610aa 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,10 +1,110 @@ 'use strict'; +const http = require('node:http'); +const fs = require('node:fs'); +const path = require('node:path'); +const querystring = require('node:querystring'); + +const dataPath = path.resolve(__dirname, '../db/expense.json'); + function createServer() { - /* Write your code here */ - // Return instance of http.Server class + return http.createServer((req, res) => { + /* ---------- GET FORM ---------- */ + if (req.method === 'GET' && req.url === '/') { + res.statusCode = 200; + res.setHeader('Content-Type', 'text/html'); + + res.end(` +

Add expense

+
+
+
+
+ +
+ `); + + return; + } + + /* ---------- ONLY POST /add-expense ---------- */ + if (req.method !== 'POST' || req.url !== '/add-expense') { + res.statusCode = 404; + res.end('Not Found'); + + return; + } + + const chunks = []; + + req.on('data', (chunk) => chunks.push(chunk)); + + req.on('end', () => { + const body = Buffer.concat(chunks).toString('utf-8'); + + let expense; + + try { + if (req.headers['content-type']?.includes('application/json')) { + expense = JSON.parse(body); + } else { + expense = querystring.parse(body); + } + } catch { + res.statusCode = 400; + res.end('

Invalid data

'); + + return; + } + + if (!expense.date || !expense.title || !expense.amount) { + res.statusCode = 400; + res.setHeader('Content-Type', 'text/html'); + res.end('

Missing required fields

'); + + return; + } + + /* ---------- READ EXISTING FILE ---------- */ + fs.readFile(dataPath, 'utf-8', (readErr, fileData) => { + let expenses = []; + + if (!readErr && fileData) { + try { + expenses = JSON.parse(fileData); + } catch { + expenses = []; + } + } + + if (!Array.isArray(expenses)) { + expenses = []; + } + + expenses.push(expense); + + /* ---------- WRITE UPDATED ARRAY ---------- */ + fs.writeFile( + dataPath, + JSON.stringify(expenses, null, 2), + (writeErr) => { + if (writeErr) { + res.statusCode = 500; + res.end('

Server error

'); + + return; + } + + /* ---------- HTML RESPONSE ---------- */ + res.statusCode = 200; + res.setHeader('Content-Type', 'text/html'); + + res.end(JSON.stringify(expense, null, 2)); + }, + ); + }); + }); + }); } -module.exports = { - createServer, -}; +module.exports = { createServer }; diff --git a/tests/formDataServer.test.js b/tests/formDataServer.test.js index 0ee1766..30b95ff 100644 --- a/tests/formDataServer.test.js +++ b/tests/formDataServer.test.js @@ -53,7 +53,7 @@ describe('Form Data Server', () => { const savedData = JSON.parse(fs.readFileSync(dataPath)); - expect(savedData).toStrictEqual(expense); + expect(savedData).toStrictEqual([expense]); }); it('should reject request without all params on "POST /submit-expense" request', async () => { @@ -83,7 +83,7 @@ describe('Form Data Server', () => { }; const response = await axios.post(`${HOST}/add-expense`, expense); - expect(response.headers['content-type']).toBe('application/json'); + expect(response.headers['content-type']).toBe('text/html'); expect(response.data).toStrictEqual(expense); });