-
Notifications
You must be signed in to change notification settings - Fork 218
Solution #175
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?
Solution #175
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 |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| name: Test | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: [ master ] | ||
|
|
||
| jobs: | ||
| build: | ||
|
|
||
| runs-on: ubuntu-latest | ||
|
|
||
| strategy: | ||
| matrix: | ||
| node-version: [20.x] | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v2 | ||
| - name: Use Node.js ${{ matrix.node-version }} | ||
| uses: actions/setup-node@v1 | ||
| with: | ||
| node-version: ${{ matrix.node-version }} | ||
| - run: npm install | ||
| - run: npm test |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,98 @@ | ||
| 'use strict'; | ||
|
|
||
| const http = require('http'); | ||
| const fs = require('fs'); | ||
| const path = require('path'); | ||
|
|
||
| function createServer() { | ||
| /* Write your code here */ | ||
| // Return instance of http.Server class | ||
| return http.createServer(async (req, res) => { | ||
| const { url, method } = req; | ||
|
|
||
| if (method === 'GET' && url === '/') { | ||
| const htmlPath = path.join(__dirname, 'index.html'); | ||
|
|
||
| res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); | ||
| fs.createReadStream(htmlPath).pipe(res); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| if ( | ||
| method === 'POST' && | ||
| (url === '/add-expense' || url === '/submit-expense') | ||
| ) { | ||
| let body = ''; | ||
|
|
||
| req.on('data', (chunk) => { | ||
| body += chunk; | ||
| }); | ||
|
|
||
| req.on('end', () => { | ||
| const contentType = req.headers['content-type'] || ''; | ||
| const isJsonRequest = contentType.includes('application/json'); | ||
| let expense; | ||
|
|
||
| try { | ||
| if (contentType.includes('application/json')) { | ||
| expense = JSON.parse(body); | ||
| } else if ( | ||
| contentType.includes('application/x-www-form-urlencoded') | ||
| ) { | ||
| expense = Object.fromEntries(new URLSearchParams(body)); | ||
| } else { | ||
| expense = {}; | ||
| } | ||
| } catch { | ||
| res.writeHead(400); | ||
|
|
||
| return res.end('Invalid JSON'); | ||
| } | ||
|
|
||
| if (!expense.date || !expense.title || expense.amount === undefined) { | ||
| res.writeHead(400); | ||
|
|
||
| return res.end('Invalid form data'); | ||
| } | ||
|
|
||
| const dbPath = path.resolve('db', 'expense.json'); | ||
|
|
||
| // NOTE: | ||
| // expense.json overwrites on each request | ||
| // because task tests expect the file to contain | ||
| // a single expense object. | ||
| // In a real application we would store an array of expenses. | ||
| fs.writeFileSync(dbPath, JSON.stringify(expense, null, 2), 'utf-8'); | ||
|
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 implementation still overwrites the |
||
|
|
||
| if (isJsonRequest) { | ||
| res.writeHead(200, { 'Content-Type': 'application/json' }); | ||
| res.end(JSON.stringify(expense)); | ||
| } else { | ||
| const prettyJson = JSON.stringify(expense, null, 2); | ||
|
|
||
| res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); | ||
|
|
||
| res.end(` | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <title>Document</title> | ||
| </head> | ||
| <body> | ||
| <h1>Saved expense</h1> | ||
| <pre>${prettyJson}</pre> | ||
| </body> | ||
| </html> | ||
| `); | ||
| } | ||
| }); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| res.writeHead(404); | ||
| res.end('Not Found'); | ||
| }); | ||
| } | ||
|
|
||
| module.exports = { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| { | ||
| "date": "2024-01-25", | ||
| "title": "Test Expense", | ||
| "amount": "100" | ||
| } | ||
|
Comment on lines
+1
to
+5
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. To support saving multiple expenses, the root of this JSON file should be an array. For example, it could start as an empty array
Author
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. But tests doesn't pass with it |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8"> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
| <title>Document</title> | ||
| </head> | ||
| <body> | ||
| <form action="/add-expense" method="POST"> | ||
|
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. A standard HTML form submission sends data as |
||
| <input type="date" name="date" required> | ||
| <input type="text" name="title" required> | ||
| <input type="number" name="amount" required> | ||
|
|
||
| <button type="submit">Save</button> | ||
| </form> | ||
| </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.
This implementation overwrites
expense.jsonwith the new expense on every submission, so only the last submitted expense is stored. To save a history of expenses, you should read the existing data from the file, add the new expense to a list (array), and then write the entire updated list back to the file.