-
Notifications
You must be signed in to change notification settings - Fork 218
task #182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
task #182
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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(` | ||
| <h1>Add expense</h1> | ||
| <form method="POST" action="/add-expense"> | ||
| <label>Date: <input name="date" type="date" required /></label><br /> | ||
| <label>Title: <input name="title" type="text" required /></label><br /> | ||
| <label>Amount: <input name="amount" type="number" required /></label><br /> | ||
| <button type="submit">Save</button> | ||
| </form> | ||
| `); | ||
|
|
||
| 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('<h2>Invalid data</h2>'); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| if (!expense.date || !expense.title || !expense.amount) { | ||
| res.statusCode = 400; | ||
| res.setHeader('Content-Type', 'text/html'); | ||
| res.end('<h2>Missing required fields</h2>'); | ||
|
|
||
| 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('<h2>Server error</h2>'); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| /* ---------- HTML RESPONSE ---------- */ | ||
| res.statusCode = 200; | ||
| res.setHeader('Content-Type', 'text/html'); | ||
|
|
||
| res.end(JSON.stringify(expense, null, 2)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great job setting the |
||
| }, | ||
| ); | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
|
|
||
| module.exports = { | ||
| createServer, | ||
| }; | ||
| module.exports = { createServer }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,7 +53,7 @@ describe('Form Data Server', () => { | |
|
|
||
| const savedData = JSON.parse(fs.readFileSync(dataPath)); | ||
|
|
||
| expect(savedData).toStrictEqual(expense); | ||
| expect(savedData).toStrictEqual([expense]); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test correctly verifies that a single expense is saved. To fully confirm that the data overwriting issue from the previous review is fixed, consider adding another test case that checks if a new expense is appended to a file that already contains existing expenses. |
||
| }); | ||
|
|
||
| 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); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This assertion doesn't align with the task requirements. The server is expected to return an HTML page containing the JSON (ideally wrapped in |
||
| }); | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The requirements state that the application should show an HTML form. This server logic only accepts
POSTrequests to/add-expenseand returns a404 Not Foundfor all other requests, includingGETrequests that would typically be used to serve the form.