From bf2eef21f28313bedcfeecfb4950f598cbc76b1c Mon Sep 17 00:00:00 2001 From: Tudor Stanciu Date: Sat, 11 Apr 2020 20:01:31 +0300 Subject: [PATCH] json api server --- package.json | 5 ++- tools/apiServer.js | 81 +++++++++++++++++++++++++++++++++++++ tools/createMockDb.js | 12 ++++++ tools/mockData.js | 92 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 tools/apiServer.js create mode 100644 tools/createMockDb.js create mode 100644 tools/mockData.js diff --git a/package.json b/package.json index 673b971..2f816b6 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,10 @@ "name": "ps-redux", "description": "React and Redux Pluralsight course by Cory House", "scripts": { - "start": "webpack-dev-server --config webpack.config.dev.js --port 3000" + "start": "run-p start:dev start:api", + "start:dev": "webpack-dev-server --config webpack.config.dev.js --port 3000", + "prestart:api": "node tools/createMockDb.js", + "start:api": "node tools/apiServer.js" }, "dependencies": { "bootstrap": "4.3.1", diff --git a/tools/apiServer.js b/tools/apiServer.js new file mode 100644 index 0000000..38fe371 --- /dev/null +++ b/tools/apiServer.js @@ -0,0 +1,81 @@ +/* +This uses json-server, but with the module approach: https://github.com/typicode/json-server#module +Downside: You can't pass the json-server command line options. +Instead, can override some defaults by passing a config object to jsonServer.defaults(); +You have to check the source code to set some items. +Examples: +Validation/Customization: https://github.com/typicode/json-server/issues/266 +Delay: https://github.com/typicode/json-server/issues/534 +ID: https://github.com/typicode/json-server/issues/613#issuecomment-325393041 +Relevant source code: https://github.com/typicode/json-server/blob/master/src/cli/run.js +*/ + +/* eslint-disable no-console */ +const jsonServer = require("json-server"); +const server = jsonServer.create(); +const path = require("path"); +const router = jsonServer.router(path.join(__dirname, "db.json")); + +// Can pass a limited number of options to this to override (some) defaults. See https://github.com/typicode/json-server#api +const middlewares = jsonServer.defaults({ + // Display json-server's built in homepage when json-server starts. + static: "node_modules/json-server/dist" +}); + +// Set default middlewares (logger, static, cors and no-cache) +server.use(middlewares); + +// To handle POST, PUT and PATCH you need to use a body-parser. Using JSON Server's bodyParser +server.use(jsonServer.bodyParser); + +// Simulate delay on all requests +server.use(function (req, res, next) { + setTimeout(next, 0); +}); + +// Declaring custom routes below. Add custom routes before JSON Server router + +// Add createdAt to all POSTS +server.use((req, res, next) => { + if (req.method === "POST") { + req.body.createdAt = Date.now(); + } + // Continue to JSON Server router + next(); +}); + +server.post("/courses/", function (req, res, next) { + const error = validateCourse(req.body); + if (error) { + res.status(400).send(error); + } else { + req.body.slug = createSlug(req.body.title); // Generate a slug for new courses. + next(); + } +}); + +// Use default router +server.use(router); + +// Start server +const port = 3001; +server.listen(port, () => { + console.log(`JSON Server is running on port ${port}`); +}); + +// Centralized logic + +// Returns a URL friendly slug +function createSlug(value) { + return value + .replace(/[^a-z0-9_]+/gi, "-") + .replace(/^-|-$/g, "") + .toLowerCase(); +} + +function validateCourse(course) { + if (!course.title) return "Title is required."; + if (!course.authorId) return "Author is required."; + if (!course.category) return "Category is required."; + return ""; +} diff --git a/tools/createMockDb.js b/tools/createMockDb.js new file mode 100644 index 0000000..9a2a5b2 --- /dev/null +++ b/tools/createMockDb.js @@ -0,0 +1,12 @@ +/* eslint-disable no-console */ +const fs = require("fs"); +const path = require("path"); +const mockData = require("./mockData"); + +const { courses, authors } = mockData; +const data = JSON.stringify({ courses, authors }); +const filepath = path.join(__dirname, "db.json"); + +fs.writeFile(filepath, data, function (err) { + err ? console.log(err) : console.log("Mock DB created."); +}); diff --git a/tools/mockData.js b/tools/mockData.js new file mode 100644 index 0000000..6b423e6 --- /dev/null +++ b/tools/mockData.js @@ -0,0 +1,92 @@ +const courses = [ + { + id: 1, + title: "Securing React Apps with Auth0", + slug: "react-auth0-authentication-security", + authorId: 1, + category: "JavaScript" + }, + { + id: 2, + title: "React: The Big Picture", + slug: "react-big-picture", + authorId: 1, + category: "JavaScript" + }, + { + id: 3, + title: "Creating Reusable React Components", + slug: "react-creating-reusable-components", + authorId: 1, + category: "JavaScript" + }, + { + id: 4, + title: "Building a JavaScript Development Environment", + slug: "javascript-development-environment", + authorId: 1, + category: "JavaScript" + }, + { + id: 5, + title: "Building Applications with React and Redux", + slug: "react-redux-react-router-es6", + authorId: 1, + category: "JavaScript" + }, + { + id: 6, + title: "Building Applications in React and Flux", + slug: "react-flux-building-applications", + authorId: 1, + category: "JavaScript" + }, + { + id: 7, + title: "Clean Code: Writing Code for Humans", + slug: "writing-clean-code-humans", + authorId: 1, + category: "Software Practices" + }, + { + id: 8, + title: "Architecting Applications for the Real World", + slug: "architecting-applications-dotnet", + authorId: 1, + category: "Software Architecture" + }, + { + id: 9, + title: "Becoming an Outlier: Reprogramming the Developer Mind", + slug: "career-reboot-for-developer-mind", + authorId: 1, + category: "Career" + }, + { + id: 10, + title: "Web Component Fundamentals", + slug: "web-components-shadow-dom", + authorId: 1, + category: "HTML5" + } +]; + +const authors = [ + { id: 1, name: "Cory House" }, + { id: 2, name: "Scott Allen" }, + { id: 3, name: "Dan Wahlin" } +]; + +const newCourse = { + id: null, + title: "", + authorId: null, + category: "" +}; + +// Using CommonJS style export so we can consume via Node (without using Babel-node) +module.exports = { + newCourse, + courses, + authors +};