diff --git a/package.json b/package.json index 8a92721..761c111 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,7 @@ "license": "GPL-3.0", "devDependencies": { "@mate-academy/eslint-config": "latest", - "@mate-academy/scripts": "^1.8.6", + "@mate-academy/scripts": "^2.1.2", "axios": "^1.7.2", "eslint": "^8.57.0", "eslint-plugin-jest": "^28.6.0", @@ -27,5 +27,8 @@ }, "mateAcademy": { "projectType": "javascript" + }, + "dependencies": { + "mime-types": "^3.0.1" } } diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..8a006cf 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,129 @@ 'use strict'; +const http = require('http'); +const url = require('url'); +const path = require('path'); +const fs = require('fs'); +const mime = require('mime-types'); + function createServer() { - /* Write your code here */ - // Return instance of http.Server class + const server = http.createServer(async (req, res) => { + function checkValidation(obj) { + if (typeof obj.date !== 'string' || !obj.date.trim()) { + throw new Error(`Field of date not correct: ${obj.date}`); + } + + if (typeof obj.title !== 'string' || !obj.title.trim()) { + throw new Error(`Field of title not correct: ${obj.title}`); + } + + const number = +obj.amount; + + if (!Number.isFinite(number) || number <= 0) { + throw new Error(`Field of amount not correct: ${number}`); + } + + const date = new Date(obj.date); + + if (isNaN(date.getTime())) { + throw new Error(`Field of date not correct: ${obj.date}`); + } + + return true; + } + + if (req.method === 'POST') { + let rawBody = ''; + + const contentType = req.headers['content-type']; + + req.on('data', (chunk) => { + rawBody = rawBody + chunk; + }); + + req.on('end', () => { + let data = null; + + const normalizedContentType = contentType.includes(';') + ? contentType.split(';')[0] + : contentType; + + if (normalizedContentType === 'application/json') { + data = JSON.parse(rawBody); + } + + if (normalizedContentType === 'application/x-www-form-urlencoded') { + data = Object.fromEntries(new URLSearchParams(rawBody)); + } + + if (data === null) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end(`Unsupported Content-Type: ${normalizedContentType}`); + + return; + } + + try { + checkValidation(data); + } catch (err) { + res.writeHead(400, { 'Content-Type': 'text/html' }); + + res.end( + `
${err.message}
${JSON.stringify(
+              {
+                invalid: data,
+              },
+              null,
+              2,
+            )}
`, + ); + + return; + } + + const folder = path.join(__dirname, '..', 'db'); + const filePath = path.join(folder, 'expense.json'); + + if (!fs.existsSync(folder)) { + fs.mkdirSync(folder, { recursive: true }); + } + + fs.writeFileSync(filePath, JSON.stringify(data, null, 2)); + + res.writeHead(200, { 'Content-Type': 'text/html' }); + + res.end(`
${JSON.stringify(data, null, 2)}
`); + }); + } + + if (req.method === 'GET') { + const base = req.headers.host + ? `http://${req.headers.host}` + : 'http://localhost:5701'; + + const normalizedUrl = new url.URL(req.url || '', base); + const origin = + path.basename(normalizedUrl.pathname.slice(1)) || 'index.html'; + + const mimeType = mime.lookup(origin) || 'text/plain'; + + const originPathName = path.join(__dirname, origin); + + const fsStream = fs.createReadStream(originPathName); + + fsStream.on('error', (err) => { + res.writeHead(404, { 'Content-Type': mimeType }); + res.end(`Error reading file: ${String(err)}`); + }); + + fsStream.on('open', () => { + res.writeHead(200, { 'Content-Type': 'text/html' }); + fsStream.pipe(res); + }); + } + }); + + return server; } module.exports = { diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..6fcd423 --- /dev/null +++ b/src/index.html @@ -0,0 +1,37 @@ + + + + + + Form data + + +
+ + + + + + + + +
+ +