Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 59 additions & 7 deletions app/server.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,83 @@
// Require necessary modules
const express = require('express');
const bodyParser = require('body-parser');
const jwt = require('jsonwebtoken');
const swaggerUi = require('swagger-ui-express');
const YAML = require('yamljs');
const swaggerDocument = YAML.load('./swagger.yaml'); // Replace './swagger.yaml' with the path to your Swagger file
const swaggerDocument = YAML.load('./swagger.yaml');

// Create Express app
const app = express();
const PORT = process.env.PORT || 3000;

// Middleware
app.use(bodyParser.json());

// Importing the data from JSON files
const users = require('../initial-data/users.json');
const brands = require('../initial-data/brands.json');
const products = require('../initial-data/products.json');

// Error handling
const JWT_SECRET_KEY = 'secretKey';

// Authentication middleware
const authenticate = (req, res, next) => {
try {
const token = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(token, JWT_SECRET_KEY);
req.userId = decoded.userId;
next();
} catch(error) {
res.status(401).json({ message: 'Authentication failed' });
}
};

app.post('/api/login', (req, res) => {
const { username, password } = req.body;

const user = users.find(user => user.username === username && user.password === password);
if (user) {
const token = jwt.sign({ userId: user.id }, JWT_SECRET_KEY, { expiresIn: '1h' });
res.json({ token });
} else {
res.status(401).json({ message: 'Invalid username or password' });
}
});


// Routes
app.get('/api/brands', (req, res) => {
res.json(brands);
});

app.post('/api/login', (req, res) => {
const { username, password } = req.body;

const user = users.find(user => user.username === username && user.password === password);
if (user) {
const token = jwt.sign({ userId: user.id }, JWT_SECRET_KEY, { expiresIn: '1h' });
res.json({ token });
} else {
res.status(401).json({ message: 'Invalid username or password' });
}
});

app.get('/api/me/cart', authenticate, (req, res) => {
res.json(products);
});

// Error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
console.error(err.stack);
res.status(500).send('Something broke!');
});

// Swagger
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));

// Starting the server
const PORT = process.env.PORT || 3000;
// Start the server
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
console.log(`Server running on port ${PORT}`);
});

module.exports = app;
188 changes: 178 additions & 10 deletions swagger.yaml
Original file line number Diff line number Diff line change
@@ -1,11 +1,179 @@
swagger: '2.0'
openapi: 3.0.0
info:
version: '1.0.0'
title: 'E-Commerce API'
description: 'API for managing brands, products, and user cart'
host: 'localhost:3000'
schemes:
- 'http'
basePath: '/api'
produces:
- 'application/json'
title: Sunglasses Shop API
description: API endpoints for a sunglasses store.
version: 1.0.0
servers:
- url: https://virtserver.swaggerhub.com/NISSAN95SX95/SunglassesWireframe/1.0.0
description: SunGlasses Shop
paths:
/api/brands:
get:
tags:
- Brands
summary: Get all brands
operationId: getBrands
responses:
"200":
description: A list of brands
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Brand"
/api/brands/{id}/products:
get:
tags:
- Brands
summary: Get products by brand ID
operationId: getProductsByBrandId
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
"200":
description: Products of the specified brand
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Product"
/api/products:
get:
tags:
- Products
summary: Get all products
operationId: getAllProducts
responses:
"200":
description: A list of products
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Product"
/api/login:
post:
tags:
- Authentication
summary: Login to the system
operationId: loginUser
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/LoginCredentials"
required: true
responses:
"200":
description: Login successful
/api/me/cart:
get:
tags:
- Cart
summary: Get items in the cart
operationId: getCartItems
responses:
"200":
description: Items in the cart
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/CartItem"
post:
tags:
- Cart
summary: Add item to the cart
operationId: addItemToCart
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Product"
required: true
responses:
"200":
description: Item added to cart successfully
/api/me/cart/{productId}:
post:
tags:
- Cart
summary: Add quantity of item to the cart
operationId: addQuantityToCartItem
parameters:
- name: productId
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/ProductQuantity"
required: true
responses:
"200":
description: Quantity added to cart item successfully
delete:
tags:
- Cart
summary: Remove item from cart
operationId: removeItemFromCart
parameters:
- name: productId
in: path
description: ID of the product to be removed from the cart
required: true
schema:
type: string
responses:
"200":
description: Item removed from cart successfully
components:
schemas:
Brand:
type: object
properties:
id:
type: string
name:
type: string
Product:
type: object
properties:
id:
type: string
name:
type: string
brandId:
type: string
price:
type: number
LoginCredentials:
type: object
properties:
username:
type: string
password:
type: string
CartItem:
type: object
properties:
productId:
type: string
quantity:
type: integer
ProductQuantity:
type: object
properties:
quantity:
type: integer
50 changes: 44 additions & 6 deletions test/server.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,52 @@
const chai = require('chai');
const chaiHttp = require('chai-http');
const server = require('../app/server'); // Adjust the path as needed
const server = require('../app/server'); // Path to your server.js file

const should = chai.should();
// Configure chai
chai.use(chaiHttp);
chai.should();

// TODO: Write tests for the server
describe('Server API tests', () => {
// Test for GET /api/brands endpoint
describe('GET /api/brands', () => {
it('should get all brands', (done) => {
chai.request(server)
.get('/api/brands')
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.an('array');
done(); // Call done to indicate test completion
});
});
});

describe('Brands', () => {});
// Test for POST /api/login endpoint
describe('POST /api/login', () => {
it('should login a user', (done) => {
chai.request(server)
.post('/api/login')
.send({ username: 'yellowleopard753', password: 'jonjon' })
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.an('object');
res.body.should.have.property('token');
done();
});
});
});

describe('Login', () => {});
// Test for GET /api/me/cart endpoint
describe('GET /api/me/cart', () => {
it('should get items in the cart', (done) => {
chai.request(server)
.get('/api/me/cart')
.end((err, res) => {
res.should.have.status(200);
res.body.should.be.an('array');
done();
});
});
});

describe('Cart', () => {});
// Add more tests for other endpoints as needed
});