-
Notifications
You must be signed in to change notification settings - Fork 218
Завдання Form data #165
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?
Завдання Form data #165
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,75 @@ | ||
| 'use strict'; | ||
|
|
||
| const http = require('http'); | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| const DATA_PATH = path.resolve('db', 'expense.json'); | ||
|
|
||
| function createServer() { | ||
| /* Write your code here */ | ||
| // Return instance of http.Server class | ||
| return http.createServer((req, res) => { | ||
| const indexPath = path.resolve('src', 'index.html'); | ||
|
|
||
|
|
||
| if (req.method === 'GET' && req.url === '/') { | ||
| try { | ||
| const file = fs.readFileSync(indexPath); | ||
|
|
||
| res.writeHead(200, { 'Content-Type': 'text/html' }); | ||
| res.end(file); | ||
|
Comment on lines
+16
to
+19
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. Serving |
||
| } catch { | ||
| res.writeHead(404, { 'Content-Type': 'text/plain' }); | ||
|
|
||
|
|
||
|
Comment on lines
+20
to
+23
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. The |
||
| const chunks = []; | ||
|
|
||
| req.on('data', (chunk) => chunks.push(chunk)); | ||
|
|
||
| req.on('end', () => { | ||
| try { | ||
| const buffer = Buffer.concat(chunks).toString(); | ||
| const obj = JSON.parse(buffer); | ||
|
Comment on lines
+24
to
+31
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. Body-parsing code lives here inside the GET |
||
|
|
||
| if (!obj.date || !obj.title || !obj.amount) { | ||
| res.writeHead(400, { 'Content-Type': 'text/plain' }); | ||
| res.end('Invalid expense data'); | ||
|
|
||
| return; | ||
| } | ||
|
Comment on lines
+33
to
+38
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. Validation for required fields (
Comment on lines
+30
to
+38
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. You parse the incoming body with |
||
|
|
||
|
|
||
| fs.writeFileSync(DATA_PATH, JSON.stringify(obj, 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. The code currently writes the new expense object directly to 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 line overwrites 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. You call |
||
|
|
||
| res.writeHead(200, { 'Content-Type': 'application/json' }); | ||
| res.end(JSON.stringify(obj)); | ||
|
Comment on lines
+43
to
+44
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. After successfully saving the expense the server responds with Content-Type
Comment on lines
+43
to
+44
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. After save the server responds with
Comment on lines
+43
to
+44
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. After saving you respond with |
||
| } catch { | ||
| res.writeHead(400, { 'Content-Type': 'text/plain' }); | ||
| res.end('Invalid JSON'); | ||
| } | ||
| }); | ||
|
Comment on lines
+24
to
+49
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. The code that collects |
||
|
|
||
| return; | ||
| } | ||
| if (req.method === 'GET' && req.url === '/expenses') { | ||
|
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. The GET endpoint serving saved data is 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. Endpoint mismatch: the client ( |
||
| try { | ||
| const data = fs.existsSync(DATA_PATH) | ||
| ? fs.readFileSync(DATA_PATH, 'utf-8') | ||
| : ''; | ||
| const obj = data ? JSON.parse(data) : {}; | ||
|
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. Minor but important: when reading existing file you parse into
Comment on lines
+55
to
+58
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. The file-read fallback uses an empty string and then returns
Comment on lines
+55
to
+58
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. The GET |
||
|
|
||
| res.writeHead(200, { 'Content-Type': 'application/json' }); | ||
| res.end(JSON.stringify(obj)); | ||
|
Comment on lines
+53
to
+61
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. The GET handler for |
||
| } catch { | ||
| res.writeHead(500, { 'Content-Type': 'text/plain' }); | ||
| res.end('Failed to read expense'); | ||
| } | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| res.writeHead(404, { 'Content-Type': 'text/plain' }); | ||
| res.end('Not found'); | ||
| }); | ||
| } | ||
|
|
||
| module.exports = { | ||
| createServer, | ||
| }; | ||
| module.exports = { createServer }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <title>Add Expense</title> | ||
| </head> | ||
| <body> | ||
| <h1>Add Expense</h1> | ||
| <form id="expense-form"> | ||
| <label>Title: <input type="text" name="title" required></label><br> | ||
| <label>Date: <input type="date" name="date" required></label><br> | ||
| <label>Amount: <input type="number" name="amount" required></label><br> | ||
| <button type="submit">Add Expense</button> | ||
| </form> | ||
|
|
||
| <h2>All Expenses</h2> | ||
| <div id="expenses"></div> | ||
|
|
||
| <script> | ||
| const form = document.getElementById('expense-form'); | ||
| const expensesDiv = document.getElementById('expenses'); | ||
|
|
||
| async function loadExpenses() { | ||
| try { | ||
| const res = await fetch('/db/expense.json'); | ||
|
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. Client attempts to load saved expenses from 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. The client fetches saved expenses from 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. The client attempts to load saved expenses from |
||
| const arr = await res.json(); | ||
|
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. You call |
||
| expensesDiv.innerHTML = `<pre>${JSON.stringify(arr, null, 2)}</pre>`; | ||
|
Comment on lines
+26
to
+27
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. The client expects an array of expenses ( 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. Displaying expenses with |
||
| } catch { | ||
| expensesDiv.innerHTML = 'No expenses yet.'; | ||
|
Comment on lines
+24
to
+29
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. Consider error handling and UX: |
||
| } | ||
| } | ||
|
|
||
| form.addEventListener('submit', async e => { | ||
| e.preventDefault(); | ||
|
|
||
| const data = { | ||
| title: form.title.value, | ||
| date: form.date.value, | ||
| amount: form.amount.value | ||
|
Comment on lines
+36
to
+39
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. The form correctly includes the required fields
Comment on lines
+36
to
+39
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. Mapping of form inputs to the
Comment on lines
+36
to
+39
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. When building the |
||
| }; | ||
|
|
||
| await fetch('/submit-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. The client posts to |
||
| method: 'POST', | ||
| headers: { 'Content-Type': 'application/json' }, | ||
| body: JSON.stringify(data) | ||
|
Comment on lines
+44
to
+45
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. You send JSON from the client with |
||
| }); | ||
|
Comment on lines
+42
to
+46
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. The form is submitted with
Comment on lines
+42
to
+46
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. You |
||
|
|
||
| form.reset(); | ||
| loadExpenses(); | ||
|
Comment on lines
+46
to
+49
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. After the POST you
Comment on lines
+46
to
+49
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. After the fetch POST completes the code calls 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. After submitting you immediately call |
||
| }); | ||
|
|
||
| loadExpenses(); | ||
|
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. Minor: you call |
||
| </script> | ||
| </body> | ||
| </html> | ||
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.
DATA_PATH is
db/expense.jsonbut the code doesn't ensure thedbdirectory exists. Ifdb/is missing,fs.writeFileSyncwill throw. Before writing, create the directory if needed, e.g.fs.mkdirSync(path.dirname(DATA_PATH), { recursive: true }). This change ensures saving todb/expense.jsonalways succeeds.