Skip to content

Commit

Permalink
Merge pull request #48 from officialabdulrehman/rest-api
Browse files Browse the repository at this point in the history
Rest api
  • Loading branch information
iamzaidsoomro authored Oct 23, 2021
2 parents 9cf07fd + c63491c commit cd6c4bb
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 0 deletions.
4 changes: 4 additions & 0 deletions Backend Development/rest-api-demo/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
MONGODB_LOCAL_URI = mongodb://localhost:27017/boilerplate
MONGODB_URI = "your production mongo url"

NODE_ENV = "not production"
20 changes: 20 additions & 0 deletions Backend Development/rest-api-demo/README.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
This project is only a sample to look and recreate your own rest-api with concepts from this project.
It is not the super simple version, but it's not the most complex either.
It has clean structure for better understanding.

Starting point for this project is server.js which imports app.js containing all the logic

follow the following steps to create your own services

1 create model
2 create service
3 create router
4 import and use the router in app.js

NOTE: This project can be massively improved. I have kept it simple for the ease of understanding for beginners.

Full version of this boiler-plate: https://github.com/officialabdulrehman/node-express-restapi-boilerplate

Auther: https://github.com/officialabdulrehman

Happy Coding!!!
22 changes: 22 additions & 0 deletions Backend Development/rest-api-demo/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import express from "express"; // import express

import { DBConnect } from "./config/database/connection"; // import database connection function

import { MONGODB_URI, PORT } from "./utils/secrets"; // import secrets
import { defaultErrorHandler, cors } from "./utils/apiHelpers"; // import helper functions

import { userRouter } from "./routers/user/user"; // import router

export const app = express(); // create app/server, store it in app - export
export default app; // default export

DBConnect(MONGODB_URI); // connect database ( call DBConnect and pass mongo uri)

app.use(cors); // enable cors

app.set("port", PORT || 3000); // set server port
app.use(express.json()); // parse json

app.use("/api/v1/user", userRouter); // initialize router here

app.use(defaultErrorHandler); // handle errors at one place
26 changes: 26 additions & 0 deletions Backend Development/rest-api-demo/config/database/connection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import mongoose from "mongoose";
import bluebird from "bluebird";

export const DBConnect = async (mongoUrl) => {
mongoose.Promise = bluebird;

const connectionP = new Promise((res, rej) => {
mongoose
.connect(mongoUrl)
.then((ins) => {
console.log("Mongo connected!!!");
console.log(
`Using mongo host '${mongoose.connection.host}' and port '${mongoose.connection.port}'`
);
return res(ins);
})
.catch((err) => {
console.log(
`MongoDB connection error. Please make sure MongoDB is running. ${err}`
);
return rej(err);
});
});

return connectionP;
};
13 changes: 13 additions & 0 deletions Backend Development/rest-api-demo/models/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import mongoose from "mongoose";

const { Schema, model } = mongoose;

const schemaFields = {
email: { type: String, required: true, unique: true },
name: { type: String, required: false },
age: { type: Number, required: false },
};

const schema = new Schema(schemaFields, { timestamps: true });

export const UserModel = model("User", schema);
25 changes: 25 additions & 0 deletions Backend Development/rest-api-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "server",
"version": "1.0.0",
"description": "rest-api-boilerplate-basic",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js",
"nodemon": "nodemon --experimental-modules --es-module-specifier-resolution=node index.js"
},
"author": "NizTheDev",
"license": "MIT",
"devDependencies": {
"nodemon": "^2.0.6"
},
"dependencies": {
"axios": "^0.21.1",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"express-validator": "^6.7.0",
"mongoose": "^5.13.7",
"validator": "^13.5.2"
},
"type": "module"
}
14 changes: 14 additions & 0 deletions Backend Development/rest-api-demo/routers/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Router } from "express";
import userService from "../services/user";
import { response, restApiValidation } from "../utils/apiHelpers";

export const userRouter = Router();
export default userRouter;

userRouter.get("/", [], async (req, res, next) => {
restApiValidation(req, res, next);
const page = parseInt(req.params.page) || 1;
const perPage = parseInt(req.params.perPage) || 10;
const result = await userService.list(page, perPage);
response(res, result);
});
11 changes: 11 additions & 0 deletions Backend Development/rest-api-demo/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { app } from "./app"; // import app

// run app by starting to listen
const server = app.listen(app.get("port"), () => {
console.log(
`App is running at http://localhost:${app.get("port")} in ${app.get(
"env"
)} mode`
);
console.log(" Press CTRL-C to stop\n");
});
22 changes: 22 additions & 0 deletions Backend Development/rest-api-demo/services/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { UserModel } from "../models/user";

class UserService {
transformUser(user) {
return {
email: user.email,
name: user.name,
age: user.age,
};
}

async list(page, perPage) {
let skip = (page - 1) * perPage;
skip = page > 1 ? skip - 1 : skip;
const limit = page > 1 ? perPage + 2 : perPage + 1;
const user = await UserModel.find({}).skip(skip).limit(limit).sort(sort);
return this.transformUser(user);
}
}

export const userService = new UserService(userDAO);
export default userService;
47 changes: 47 additions & 0 deletions Backend Development/rest-api-demo/utils/apiHelpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export const defaultErrorHandler = (err, req, res, next) => {
const { code, message, data } = err;
res.status(code || 500).json({
message: message || "Internal server error",
result: {},
errors: data || [],
});
};

export const cors = (req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"GET, POST, PUT, PATCH, DELETE"
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
if (req.method === "OPTIONS") return res.sendStatus(200);
next();
};
export default cors;

export const restApiValidation = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
const error = new Error(`Bad Request`);
error.data = errors.array().map((err) => {
return {
message: err.msg || "",
param: err.param || "",
location: err.location || "",
value: err.value || "",
};
});
error.code = 400;
throw error;
}
return true;
};

export const response = (res, result) => {
const response = {
message: "Success",
result: result,
errors: [],
};
res.status(200).json(response);
};
22 changes: 22 additions & 0 deletions Backend Development/rest-api-demo/utils/secrets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import dotenv from "dotenv";
dotenv.config();

const ENVIRONMENT = process.env.NODE_ENV;
const prod = ENVIRONMENT === "production";
export const MONGODB_URI = prod
? process.env["MONGODB_URI"]
: process.env["MONGODB_LOCAL_URI"];

export const PORT = process.env.PORT;

if (!MONGODB_URI) {
if (prod) {
throw new Error(
"No mongo connection string. Set MONGODB_URI environment variable."
);
} else {
throw new Error(
"No mongo connection string. Set MONGODB_URI_LOCAL environment variable."
);
}
}

0 comments on commit cd6c4bb

Please sign in to comment.