part4a
Part4a Structure of backend application, introduction to testing
Project structure
├── index.js├── app.js├── dist│ └── ...├── controllers│ └── notes.js├── models│ └── note.js├── package-lock.json├── package.json├── utils│ ├── config.js│ ├── logger.js│ └── middleware.js
move info or error log together:
const info = (...params) => { console.log(...params)}
const error = (...params) => { console.error(...params)}
module.exports = { info, error}
require('dotenv').config()
const PORT = process.env.PORTconst MONGODB_URI = process.env.MONGODB_URI
module.exports = { MONGODB_URI, PORT}
const app = require('./app') // the actual Express applicationconst config = require('./utils/config')const logger = require('./utils/logger')
app.listen(config.PORT, () => { logger.info(`Server running on port ${config.PORT}`)})
const notesRouter = require('express').Router()const Note = require('../models/note')
notesRouter.get('/', (request, response) => { Note.find({}).then(notes => { response.json(notes) })})
notesRouter.get('/:id', (request, response, next) => { Note.findById(request.params.id) .then(note => { if (note) { response.json(note) } else { response.status(404).end() } }) .catch(error => next(error))})
notesRouter.post('/', (request, response, next) => { const body = request.body
const note = new Note({ content: body.content, important: body.important || false, })
note.save() .then(savedNote => { response.json(savedNote) }) .catch(error => next(error))})
notesRouter.delete('/:id', (request, response, next) => { Note.findByIdAndDelete(request.params.id) .then(() => { response.status(204).end() }) .catch(error => next(error))})
notesRouter.put('/:id', (request, response, next) => { const body = request.body
const note = { content: body.content, important: body.important, }
Note.findByIdAndUpdate(request.params.id, note, { new: true }) .then(updatedNote => { response.json(updatedNote) }) .catch(error => next(error))})
module.exports = notesRouter
A router object is an isolated instance of middleware and routes. You can think of it as a “mini-application,” capable only of performing middleware and routing functions. Every Express application has a built-in app router.
const config = require('./utils/config')const express = require('express')const app = express()const cors = require('cors')const notesRouter = require('./controllers/notes')const middleware = require('./utils/middleware')const logger = require('./utils/logger')const mongoose = require('mongoose')
mongoose.set('strictQuery', false)
logger.info('connecting to', config.MONGODB_URI)
mongoose.connect(config.MONGODB_URI) .then(() => { logger.info('connected to MongoDB') }) .catch((error) => { logger.error('error connecting to MongoDB:', error.message) })
app.use(cors())app.use(express.static('dist'))app.use(express.json())app.use(middleware.requestLogger)
app.use('/api/notes', notesRouter)
app.use(middleware.unknownEndpoint)app.use(middleware.errorHandler)
module.exports = app
const logger = require('./logger')
const requestLogger = (request, response, next) => { logger.info('Method:', request.method) logger.info('Path: ', request.path) logger.info('Body: ', request.body) logger.info('---') next()}
const unknownEndpoint = (request, response) => { response.status(404).send({ error: 'unknown endpoint' })}
const errorHandler = (error, request, response, next) => { logger.error(error.message)
if (error.name === 'CastError') { return response.status(400).send({ error: 'malformatted id' }) } else if (error.name === 'ValidationError') { return response.status(400).json({ error: error.message }) }
next(error)}
module.exports = { requestLogger, unknownEndpoint, errorHandler}
const mongoose = require('mongoose')
const noteSchema = new mongoose.Schema({ content: { type: String, required: true, minlength: 5 }, important: Boolean,})
noteSchema.set('toJSON', { transform: (document, returnedObject) => { returnedObject.id = returnedObject._id.toString() delete returnedObject._id delete returnedObject.__v }})
module.exports = mongoose.model('Note', noteSchema)
check the structure again:
├── index.js├── app.js├── dist│ └── ...├── controllers│ └── notes.js├── models│ └── note.js├── package-lock.json├── package.json├── utils│ ├── config.js│ ├── logger.js│ └── middleware.js
Exercises 4.1.-4.2.
4.1 Blog List, step 1
Turn the application(codes below) into a functioning npm project.
const express = require('express')const app = express()const cors = require('cors')const mongoose = require('mongoose')
const blogSchema = new mongoose.Schema({ title: String, author: String, url: String, likes: Number})
const Blog = mongoose.model('Blog', blogSchema)
const mongoUrl = 'mongodb://localhost/bloglist'mongoose.connect(mongoUrl)
app.use(cors())app.use(express.json())
app.get('/api/blogs', (request, response) => { Blog .find({}) .then(blogs => { response.json(blogs) })})
app.post('/api/blogs', (request, response) => { const blog = new Blog(request.body)
blog .save() .then(result => { response.status(201).json(result) })})
const PORT = 3003app.listen(PORT, () => { console.log(`Server running on port ${PORT}`)})
My solutions
My solutions:
(Please complete your own solutions before click here.)
Q: How to turn a .js application into a npm package?
A:
Turning a JavaScript application into an npm package involves several steps. Here's a general guide to help you through the process:
1. Initialize a Node.js Project:
If you haven't already, create a new directory for your project and initialize it with npm by running:
bashnpm init -y
This command creates a package.json file with default values.
2. Develop Your Application:
Build your application as you normally would. Make sure it works correctly.
3. Prepare Your Package:
- Ensure your code is well-structured and modular.- Write a README.md file that explains how to install and use your package.- Include a LICENSE file if you want to specify how your package can be used.- Write tests to ensure your package works as expected.
4. Update package.json:
Modify your package.json file to include:
- name: A unique name for your package.- version: A version number following semantic versioning (e.g., 1.0.0).- main: The entry point to your module (e.g., index.js).- scripts: Commands for testing, building, etc.- dependencies: Any packages your package needs to run.- devDependencies: Any packages needed for development.- files: An array of files that should be included when your package is published.- bin: If your package includes a command-line tool, specify the binary files here.- keywords: Keywords that help users find your package.
5. Test Locally:
Before publishing, test your package locally:
bashnpm pack
This will create a tarball of your package. You can then install it locally to test:
bashnpm install ./package-name-1.0.0.tgz
6. Publish to npm:
To publish your package, you need to log in to npm:
bashnpm login
After logging in, you can publish your package:
bashnpm publish
Note that you can also publish a package privately if you have an npm account with private packages enabled.
7. Versioning:
Always remember to update the version number in your package.json file before each new release.
8. Documentation:
Provide comprehensive documentation for your package. This can be in the README file or a separate documentation site.
9. Maintenance:
After publishing, you'll need to maintain your package by fixing bugs, adding features, and updating dependencies.
Remember, once you publish a package, you cannot change its name or version numbers for that same package. If you need to make changes, you'll need to publish a new version with an updated version number.
Also ref: https://philna.sh/blog/2019/01/10/how-to-start-a-node-js-project/
tierney cyren@bitandbang
How to start any new Node.js project:
$ npx license mit > LICENSE$ npx gitignore node$ npx covgen YOUR_EMAIL_ADDRESS$ npm init -y
You're ready to start coding.
issue on windows when run npx license mit: https://stackoverflow.com/questions/76188312/npx-license-mit-license-throwing-an-error-license-is-not-recognized-as-an-i
I can also confirm that npx license does not work out-of-the-box on Windows, but if you first do npm i -g license and then follow up with `npx license MIT` then you get the results you expect, however that seems to defeat the purpose of npx doesn't it? – hsbatra Commented Jan 19 at 23:59
Actual action: ignore the third command(the covgen) as it looks too verbose for this exercise.
Add scripts and dependencies and eslint.config.mjs from exercises in part3.
4.2 Blog List, step 2
Refactor the application into separate modules as shown earlier in this part of the course material.
TODO