├── .babelrc ├── .sequelizerc ├── README.md ├── app.js ├── package.json └── server ├── config └── config.json ├── controller ├── book.js └── user.js ├── models ├── book.js └── user.js └── routes └── index.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"] 3 | } -------------------------------------------------------------------------------- /.sequelizerc: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | "config": path.resolve('./server/config', 'config.json'), 5 | "models-path": path.resolve('./server/models'), 6 | "seeders-path": path.resolve('./server/seeders'), 7 | "migrations-path": path.resolve('./server/migrations') 8 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RESTful_API 2 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | import http from 'http' 2 | import express from 'express' 3 | 4 | import logger from 'morgan'; 5 | import bodyParser from 'body-parser'; 6 | import routes from './server/routes'; 7 | 8 | const hostname = '127.0.0.1'; 9 | const port = 3000; 10 | const app = express() 11 | const server = http.createServer(app); 12 | 13 | app.use(logger('dev')); 14 | app.use(bodyParser.json()); 15 | app.use(bodyParser.urlencoded({ extended: false })); 16 | 17 | routes(app); 18 | 19 | app.get('*', (req, res) => res.status(200).send({ 20 | message: 'Welcome to the .', 21 | })); 22 | 23 | server.listen(port, hostname, () => { 24 | console.log(`Server running at http://${hostname}:${port}/`); 25 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "restfulAPI", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "nodemon --exec babel-node app.js", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "devDependencies": { 14 | "babel-preset-env": "^1.7.0", 15 | "nodemon": "^1.18.4" 16 | }, 17 | "dependencies": { 18 | "babel-cli": "^6.26.0", 19 | "babel-core": "^6.26.3", 20 | "body-parser": "^1.18.3", 21 | "express": "^4.16.3", 22 | "morgan": "^1.9.1", 23 | "pg": "^7.4.3", 24 | "pg-hstore": "^2.3.2", 25 | "sequelize": "^4.38.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /server/config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "development": { 3 | "username": "your_database_username", 4 | "password": "your_database_password", 5 | "database": "bookstore", 6 | "host": "127.0.0.1", 7 | "dialect": "postgres" 8 | }, 9 | "test": { 10 | "username": "root", 11 | "password": null, 12 | "database": "database_test", 13 | "host": "127.0.0.1", 14 | "dialect": "postgres" 15 | }, 16 | "production": { 17 | "username": "root", 18 | "password": null, 19 | "database": "database_production", 20 | "host": "127.0.0.1", 21 | "dialect": "postgres" 22 | } 23 | } -------------------------------------------------------------------------------- /server/controller/book.js: -------------------------------------------------------------------------------- 1 | import model from '../models'; 2 | 3 | const { Book } = model; 4 | 5 | class Books { 6 | static create(req, res) { 7 | const { title, author, description, quantity } = req.body 8 | const { userId } = req.params 9 | return Book 10 | .create({ 11 | title, 12 | author, 13 | description, 14 | quantity, 15 | userId 16 | }) 17 | .then(book => res.status(201).send({ 18 | message: `Your book with the title ${title} has been created successfully `, 19 | book 20 | })) 21 | } 22 | static list(req, res) { 23 | return Book 24 | .findAll() 25 | .then(books => res.status(200).send(books)); 26 | } 27 | static modify(req, res) { 28 | const { title, author, description, quantity } = req.body 29 | return Book 30 | .findById(req.params.bookId) 31 | .then((book) => { 32 | book.update({ 33 | title: title || book.title, 34 | author: author || book.author, 35 | description: description || book.description, 36 | quantity: quantity || book.quantity 37 | }) 38 | .then((updatedBook) => { 39 | res.status(200).send({ 40 | message: 'Book updated successfully', 41 | data: { 42 | title: title || updatedBook.title, 43 | author: author || updatedBook.author, 44 | description: description || updatedBook.description, 45 | quantity: quantity || updatedBook.quantity 46 | } 47 | }) 48 | }) 49 | .catch(error => res.status(400).send(error)); 50 | }) 51 | .catch(error => res.status(400).send(error)); 52 | } 53 | static delete(req, res) { 54 | return Book 55 | .findById(req.params.bookId) 56 | .then(book => { 57 | if(!book) { 58 | return res.status(400).send({ 59 | message: 'Book Not Found', 60 | }); 61 | } 62 | return book 63 | .destroy() 64 | .then(() => res.status(200).send({ 65 | message: 'Book successfully deleted' 66 | })) 67 | .catch(error => res.status(400).send(error)); 68 | }) 69 | .catch(error => res.status(400).send(error)) 70 | } 71 | } 72 | 73 | export default Books -------------------------------------------------------------------------------- /server/controller/user.js: -------------------------------------------------------------------------------- 1 | import model from '../models'; 2 | 3 | const { User } = model; 4 | 5 | class Users { 6 | static signUp(req, res) { 7 | const { name, username, email, password } = req.body 8 | return User 9 | .create({ 10 | name, 11 | username, 12 | email, 13 | password 14 | }) 15 | .then(userData => res.status(201).send({ 16 | success: true, 17 | message: 'User successfully created', 18 | userData 19 | })) 20 | } 21 | } 22 | 23 | export default Users; -------------------------------------------------------------------------------- /server/models/book.js: -------------------------------------------------------------------------------- 1 | export default (sequelize, DataTypes) => { 2 | const Book = sequelize.define('Book', { 3 | title: { 4 | type: DataTypes.STRING, 5 | allowNull: { 6 | args: false, 7 | msg: 'Please enter the title for your book' 8 | } 9 | }, 10 | author: { 11 | type: DataTypes.STRING, 12 | allowNull: { 13 | args: false, 14 | msg: 'Please enter an author' 15 | } 16 | }, 17 | description: { 18 | type: DataTypes.STRING, 19 | allowNull: { 20 | args: false, 21 | msg: 'Pease input a description' 22 | } 23 | }, 24 | quantity: { 25 | type: DataTypes.INTEGER, 26 | allowNull: { 27 | args: false, 28 | msg: 'Pease input a quantity' 29 | } 30 | }, 31 | userId: { 32 | type: DataTypes.INTEGER, 33 | references: { 34 | model: 'User', 35 | key: 'id', 36 | as: 'userId', 37 | } 38 | } 39 | }, {}); 40 | Book.associate = (models) => { 41 | // associations can be defined here 42 | Book.belongsTo(models.User, { 43 | foreignKey: 'userId', 44 | onDelete: 'CASCADE' 45 | }); 46 | }; 47 | return Book; 48 | }; -------------------------------------------------------------------------------- /server/models/user.js: -------------------------------------------------------------------------------- 1 | export default (sequelize, DataTypes) => { 2 | const User = sequelize.define('User', { 3 | name: { 4 | type: DataTypes.STRING, 5 | allowNull: { 6 | args: false, 7 | msg: 'Please enter your name' 8 | } 9 | }, 10 | username: { 11 | type: DataTypes.STRING, 12 | allowNull: { 13 | args: false, 14 | msg: 'Please enter your username' 15 | } 16 | }, 17 | email: { 18 | type: DataTypes.STRING, 19 | allowNull: { 20 | args: false, 21 | msg: 'Please enter your email address' 22 | }, 23 | unique: { 24 | args: true, 25 | msg: 'Email already exists' 26 | }, 27 | validate: { 28 | isEmail: { 29 | args: true, 30 | msg: 'Please enter a valid email address' 31 | }, 32 | }, 33 | }, 34 | password: { 35 | type: DataTypes.STRING, 36 | allowNull: { 37 | args: false, 38 | msg: 'Please enter a password' 39 | }, 40 | validate: { 41 | isNotShort: (value) => { 42 | if (value.length < 8) { 43 | throw new Error('Password should be at least 8 characters'); 44 | } 45 | }, 46 | }, 47 | } 48 | }, {}); 49 | User.associate = (models) => { 50 | // associations can be defined here 51 | User.hasMany(models.Book, { 52 | foreignKey: 'userId', 53 | }); 54 | }; 55 | return User; 56 | }; -------------------------------------------------------------------------------- /server/routes/index.js: -------------------------------------------------------------------------------- 1 | import Users from '../controllers/user'; 2 | import Books from '../controllers/book'; 3 | 4 | export default (app) => { 5 | 6 | app.get('/api', (req, res) => res.status(200).send({ 7 | message: 'Welcome to the bookStore API!', 8 | })); 9 | 10 | app.post('/api/users', Users.signUp); // API route for user to signup 11 | app.post('/api/users/:userId/books', Books.create); // API route for user to create a book 12 | app.get('/api/books', Books.list); // API route for user to get all books in the database 13 | app.put('/api/books/:bookId', Books.modify); // API route for user to edit a book 14 | app.delete('/api/books/:bookId', Books.delete); // API route for user to delete a book 15 | 16 | }; --------------------------------------------------------------------------------