diff --git a/app/server.js b/app/server.js index 5201d84d..50b1b58b 100644 --- a/app/server.js +++ b/app/server.js @@ -1,11 +1,16 @@ +// 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 @@ -13,19 +18,66 @@ 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; diff --git a/swagger.yaml b/swagger.yaml index 1c2eb22f..15150e35 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -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 diff --git a/test/server.test.js b/test/server.test.js index 7ff14c8f..c7379628 100644 --- a/test/server.test.js +++ b/test/server.test.js @@ -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 +});