Skip to content

Commit

Permalink
Merge pull request #54 from therahulchaurasia/issue-53
Browse files Browse the repository at this point in the history
Done [New API] : User Data #53
  • Loading branch information
dishamodi0910 authored Oct 28, 2023
2 parents 94a3f45 + ccc3d56 commit 0e09ead
Show file tree
Hide file tree
Showing 20 changed files with 3,695 additions and 6 deletions.
76 changes: 70 additions & 6 deletions New_APIs/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,71 @@
# **Let's built something new together!**
# Lets build a User Data API using NodeJS, ExpressJS, MongoDB and Mongoose

| Name of API | Description of API |
|---|---|
|[BASIC CRUD API](https://github.com/developer-student-clubs/APIVerse/tree/master/New_APIs/Demo_CRUD_API)| It explains us how can we perform basic CRUD operations.|
|[MOVIE TV SHOWS API](https://github.com/developer-student-clubs/APIVerse/tree/master/New_APIs/Movie_Tv_Show_API)| Rest API to fetch data of movie and tv-show with filter options of page, limit, search, and type.|
|[JSON API](https://github.com/developer-student-clubs/APIVerse/tree/master/New_APIs/JsonServer_API)| Give Json data of your choice and get all request ready to work by json server.|
## Table of contents

- [Getting Started](#getting-started)
- [Prerequisites](#prerequisites)
- [Installation](#installation)
- [Built With](#built-with)
- [Author](#author)

## Getting Started

### Prerequisites

- NodeJS
- MongoDB
- Postman

### Installation

- Clone the repository
- Type in the following command in the terminal

```bash
cd UserDataAPI
npm install
```

- Create a .env file in the root directory and add the following
- Add your MongoDB connection string and desired port number

```bash
MONGO_URI = <YOUR_MONGODB_CONNECTION_STRING>
PORT = <YOUR_DESIRED_PORT_NUMBER>
```

- Populate the database by running the following command in the terminal

```bash
node populate.js
```

- Run the following command in the terminal

```bash
npm start
```

- Open Postman and test the API by sending requests to the following endpoints

```bash
GET http://localhost:3000/api/v1/users
POST http://localhost:3000/api/v1/users
GET http://localhost:3000/api/v1/users/:id(enter your own)
PATCH http://localhost:3000/api/v1/users/:id(enter your own)
DELETE http://localhost:3000/api/v1/users/:id(enter your own)
```

## Built With

- [NodeJS](https://nodejs.org/en/)
- [ExpressJS](https://expressjs.com/)
- [MongoDB](https://www.mongodb.com/)
- [Mongoose](https://mongoosejs.com/)
- [Postman](https://www.postman.com/)
- [VS Code](https://code.visualstudio.com/)
- [Git](https://git-scm.com/)

## Author

- Github - [therahulchaurasia](https://github.com/therahulchaurasia)
2 changes: 2 additions & 0 deletions New_APIs/UserDataAPI/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MONGO_URI = mongodb+srv://<username>:<password>@nodeexpressprojects.ajshdj.mongodb.net/<YOUR_COLLECTION_NAME>?retryWrites=true&w=majority
PORT = Enter a port number or it will use the default 3000 specified in app.js
2 changes: 2 additions & 0 deletions New_APIs/UserDataAPI/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
.env
41 changes: 41 additions & 0 deletions New_APIs/UserDataAPI/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require("dotenv").config()
require("express-async-errors")

const express = require("express")
const app = express()
const fileUpload = require("express-fileupload")

const connectDB = require("./db/connect")
const userRouter = require("./routes/userRoutes")

const notFoundMiddleware = require("./middleware/not-found")
const errorMiddleware = require("./middleware/error-handler")

// middleware
app.use(express.json())
app.use(express.static("./public"))
app.use(fileUpload())
// routes

app.get("/", (req, res) => {
res.send('<h1>User Data API </h1><a href="/api/v1/users">User Routes</a>')
})

app.use("/api/v1/users", userRouter)

app.use(notFoundMiddleware)
app.use(errorMiddleware)

const port = process.env.PORT || 3000

const start = async () => {
try {
// connectDB
await connectDB(process.env.MONGO_URI)
app.listen(port, () => console.log(`Server is listening port ${port}...`))
} catch (error) {
console.log(error)
}
}

start()
73 changes: 73 additions & 0 deletions New_APIs/UserDataAPI/controllers/userController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
const User = require("../models/User")
const CustomError = require("../errors/index")

const getAllUsers = async (req, res) => {
const users = await User.find({})
res.status(200).json({ users, count: users.length })
}

const getSingleUser = async (req, res) => {
const { id: userId } = req.params
const user = await User.findOne({ _id: userId })
if (!user) {
throw new CustomError.NotFoundError(`No user found with the id ${userId}`)
}
res.status(200).json({ user })
}

const postUser = async (req, res) => {
const { firstName, lastName, gender, address, timeZone } = req.body
if ((!firstName, !lastName, !address)) {
throw new CustomError.BadRequestError("Please provide valid values")
}
if (!["Male", "Female"].includes(gender)) {
throw new CustomError.BadRequestError("Gender can only be male or female")
}

// When you create a user you get an image avatar generated using the combination of your firstname, lastname and address
const imageAvatar = Math.ceil(Math.random() * 4)
const image = `https://robohash.org/${firstName.split(" ").join("")}${address
.split(" ")
.join("")}${lastName
.split(" ")
.join("")}.png?size=200x200&set=set${imageAvatar}`
const user = await User.create({
firstName,
lastName,
gender,
address,
timeZone,
image,
})
res.status(201).json({ user })
}

const updateUser = async (req, res) => {
const { id: userId } = req.params
const user = await User.findOneAndUpdate({ _id: userId }, req.body, {
new: true,
runValidators: true,
})
if (!user) {
throw new CustomError.NotFoundError(`No user found with the id ${userId}`)
}
res.status(StatusCodes.OK).json({ user })
}

const deleteUser = async (req, res) => {
const { id: userId } = req.params
const user = await User.findOne({ _id: userId })
if (!user) {
throw new CustomError.NotFoundError(`No user found with the id ${userId}`)
}
await user.remove()
res.status(200).json({ msg: `Success! User Removed` })
}

module.exports = {
getAllUsers,
getSingleUser,
deleteUser,
postUser,
updateUser,
}
7 changes: 7 additions & 0 deletions New_APIs/UserDataAPI/db/connect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const mongoose = require("mongoose")

const connectDB = (url) => {
return mongoose.connect(url)
}

module.exports = connectDB
11 changes: 11 additions & 0 deletions New_APIs/UserDataAPI/errors/bad-request.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { StatusCodes } = require('http-status-codes');
const CustomAPIError = require('./custom-api');

class BadRequestError extends CustomAPIError {
constructor(message) {
super(message);
this.statusCode = StatusCodes.BAD_REQUEST;
}
}

module.exports = BadRequestError;
12 changes: 12 additions & 0 deletions New_APIs/UserDataAPI/errors/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const CustomAPIError = require('./custom-api')
const UnauthenticatedError = require('./unauthenticated')
const NotFoundError = require('./not-found')
const BadRequestError = require('./bad-request')
const UnauthorizedError = require('./unauthorized')
module.exports = {
CustomAPIError,
UnauthenticatedError,
NotFoundError,
BadRequestError,
UnauthorizedError,
}
11 changes: 11 additions & 0 deletions New_APIs/UserDataAPI/errors/not-found.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { StatusCodes } = require('http-status-codes');
const CustomAPIError = require('./custom-api');

class NotFoundError extends CustomAPIError {
constructor(message) {
super(message);
this.statusCode = StatusCodes.NOT_FOUND;
}
}

module.exports = NotFoundError;
28 changes: 28 additions & 0 deletions New_APIs/UserDataAPI/middleware/error-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const { StatusCodes } = require('http-status-codes');
const errorHandlerMiddleware = (err, req, res, next) => {
let customError = {
// set default
statusCode: err.statusCode || StatusCodes.INTERNAL_SERVER_ERROR,
msg: err.message || 'Something went wrong try again later',
};
if (err.name === 'ValidationError') {
customError.msg = Object.values(err.errors)
.map((item) => item.message)
.join(',');
customError.statusCode = 400;
}
if (err.code && err.code === 11000) {
customError.msg = `Duplicate value entered for ${Object.keys(
err.keyValue
)} field, please choose another value`;
customError.statusCode = 400;
}
if (err.name === 'CastError') {
customError.msg = `No item found with id : ${err.value}`;
customError.statusCode = 404;
}

return res.status(customError.statusCode).json({ msg: customError.msg });
};

module.exports = errorHandlerMiddleware;
3 changes: 3 additions & 0 deletions New_APIs/UserDataAPI/middleware/not-found.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const notFound = (req, res) => res.status(404).send('Route does not exist')

module.exports = notFound
35 changes: 35 additions & 0 deletions New_APIs/UserDataAPI/models/User.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
const mongoose = require("mongoose")

const UserSchema = new mongoose.Schema(
{
firstName: {
type: String,
required: [true, "Please provide first name"],
maxlength: 50,
},
lastName: {
type: String,
required: [true, "Please provide last name"],
maxlength: 50,
},
gender: {
type: String,
required: [true, "Please provide gender"],
enum: ["Male", "Female"],
},
address: {
type: String,
required: [true, "Please provide address"],
},
timeZone: {
type: String,
},
image: {
type: String,
default: "/uploads/example.jpeg",
},
},
{ timestamps: true }
)

module.exports = mongoose.model("User", UserSchema)
Loading

0 comments on commit 0e09ead

Please sign in to comment.