- Warung Bu Ode RESTful API
- API Routes Documentation
- Routes Overview
- Authentication Routes (
/auth
) - Warung Routes (
/warung
) - Menu Routes (
/menu
) - Bill Routes (
/bill
) - Dependencies
- Acknowledgements
- Authors
- License
This project is a RESTful API designed for managing operations in "Warung Bu Ode", using Node.js and various other technologies like Prisma, Cloudinary, and Express.
Before you begin, ensure you have met the following requirements:
- Node.js (v18 or higher): The project is built with Node.js. You must have Node.js version 18 or higher installed on your machine. You can download it from Node.js official website.
- npm (Node Package Manager): npm is used to install dependencies. It comes with Node.js, so if you have Node.js installed, you should have npm as well.
- Git: While not strictly necessary, the project recommends using Git for version control. If you plan to clone the repository, make sure Git is installed on your system. You can download it from Git's official website.
- Basic knowledge of terminal or command line usage: Since the installation and running of the project require using the terminal or command line, basic knowledge in this area will be beneficial.
Once you have these prerequisites, you can proceed with the installation instructions below.
Follow these steps to install and run the project:
-
Clone the repository:
git clone https://github.com/KuraoHikari/BE-WarungBuOde.git cd be-warungbuode
-
Install dependencies:
npm install
-
Set up environment variables: Create a
.env
file in the root directory and fill it with necessary environment variables:DATABASE_URL="your_database_url" DIRECT_URL="if you using neondb or serverles sql" JWT_SECRET="your_jwt_secret" CLOUD_NAME="your cloudinary name" API_KEY="your cludinary apikey" API_SECRET="your cludinary api secret"
-
Run database migrations (ensure your database connection details are correct in
.env
):npx prisma migrate dev
-
Start the server:
- For development:
npm run dev
- For production:
npm start
- For development:
The provided content outlines the structure and components of a Prisma schema file used for configuring a Prisma ORM setup. The schema is designed for a PostgreSQL database and includes specifications for data sources, generators, models, and relationships between them.
Key Components of the Prisma Schema:
-
Data Source Configuration:
- Utilizes PostgreSQL, with the connection URL provided through environment variables (
DATABASE_URL
andDIRECT_URL
).
- Utilizes PostgreSQL, with the connection URL provided through environment variables (
-
Generator Configuration:
- Specifies that the Prisma client for JavaScript (
prisma-client-js
) should be generated, directing the output to "./generated/client".
- Specifies that the Prisma client for JavaScript (
-
Models and Relationships:
- User Model: Includes fields such as id, email, username, password, and role. It is associated with other models like Warung, WarungEmploye, Menu, and Bill.
- Warung Model: Represents a restaurant or food stall with fields like id, name, and location. It has relationships with User, WarungEmploye, Menu, and Bill.
- WarungEmploye Model: Links employees to specific Warungs and Users.
- Menu Model: Contains details about food items including title, price, description, image, and availability. It is linked to the Warung and User models and associated with Orders.
- Order Model: Details an order placed by a user, including the menu item, quantity, total price, and creation date.
- Bill Model: Represents a bill or invoice, with fields for total amount, status, approval status, and customer name. It is associated with Users, Warungs, and Orders.
-
Enums:
- Defines a
Role
enum with valuesEMPLOYE
andADMIN
to distinguish between different user roles within the system.
- Defines a
To get a better understanding of the database structure, you can view the Entity Relationship Diagram (ERD) for Warung Bu Ode:
For a direct look at the main ERD, see below:
After starting the server, the API endpoints will be available at http://localhost:3000/
(change the port if you've configured it differently).
Verifies the JWT token provided in the request headers. It ensures that the token is valid and that the user exists in the database. If the verification is successful, it attaches the user's information to the request object.
Usage:
Attach this middleware to any route that requires user authentication.
router.get("/protected-route", authenticationMiddleware, (req, res) => {
res.send("This is a protected route");
});
Checks if the authenticated user has an admin role. It should be used after authenticationMiddleware
to ensure that the route is accessible only by users with admin privileges.
Usage: Attach this middleware to routes that should be accessible only by admin users.
router.post(
"/admin-only",
authenticationMiddleware,
authorizationAdminMiddleware,
(req, res) => {
res.send("Admin content");
}
);
Verifies if the authenticated user is authorized to access a specific warung based on the warungId
parameter in the route and the user's ID. It ensures that the user is linked to the warung they are trying to access.
Usage:
Use this middleware for routes that manage warung-specific data.
router.get(
"/warung/:warungId/data",
authenticationMiddleware,
authorizationWarungMiddleware,
(req, res) => {
res.send("Warung specific data");
}
);
Checks if a warung with the specified warungName
exists in the request parameters. It's designed for routes that should be publicly accessible but still require validation of the warung's existence.
Usage:
Attach this middleware to public routes that require validation of a warung's existence based on its name.
router.get(
"/public/:warungName/info",
authorizationPublicBillMiddleware,
(req, res) => {
res.send("Public warung information");
}
);
Error Handling :
All middleware functions respond with a 401 Unauthorized
status code and a JSON message indicating the type of authorization error if the authentication or authorization fails.
The imageValidationMiddleware
performs the following checks on image files included in requests:
- File Type Validation: Ensures the uploaded file is of an image type (png, jpg, jpeg, gif, bmp).
- File Size Validation: Ensures the uploaded image does not exceed a maximum size limit of 510kb.
Usage:
To use this middleware, attach it to any route that accepts image uploads. This will ensure that only valid image files are processed, and any invalid uploads are rejected with an appropriate error message.
Example:
const express = require("express");
const multer = require("multer");
const imgValidate = require("./imageValidationMiddleware");
const upload = multer({ dest: "uploads/" });
const app = express();
app.post("/upload-image", upload.single("image"), imgValidate, (req, res) => {
res.send("Image uploaded successfully");
});
In this example, multer
is used to handle multipart/form-data, which is primarily used for uploading files. The upload.single('image')
middleware is used to accept a single file with the field name image
. After the file is processed by multer
, imgValidate
checks the file type and size.
Error Handling: If the uploaded file does not meet the validation criteria, the middleware responds with a 400 Bad Request status and a JSON message indicating the reason for rejection:
- If the file is not an image: { message: "file must be an image" }
- If the image exceeds the size limit: { message: "max image size is 510kb" }
The multerMiddleware
is configured to use multer
's memory storage engine. This means that files uploaded through this middleware are stored in the server's memory. It's an ideal setup for temporary storage or when files need to be processed (e.g., resized or converted) before being saved to a permanent storage solution.
Usage:
To use this middleware in your application, first import it into the file where you're setting up your routes:
import upload from "./multerMiddleware";
app.post("/upload", upload.single("image"), (req, res) => {
// Handle the uploaded file here
res.send("File uploaded successfully");
});
For multiple files, you can use upload.array('images', maxCount)
or upload.fields([{ name: 'avatar', maxCount: 1 }, { name: 'gallery', maxCount: 8 }])
depending on your needs.
Configuration:
The middleware uses multer
's default memory storage engine. If you need to customize the storage engine (e.g., to save files to disk or to cloud storage), you can modify the storage
option in the multerMiddleware.js
file.
Error Handling:
multer
includes built-in error handling mechanisms. If an upload fails due to file size limits, file type restrictions, or other configuration rules, multer
will automatically respond with an appropriate error message. You can also add custom error handling to further manage how upload errors are handled.
The validationMiddleware
function takes a Zod schema as an argument and returns an Express middleware function. This middleware attempts to parse the incoming request body using the provided schema. If the data matches the schema, the request proceeds to the next middleware or route handler. If the data does not match, it responds with a 400 Bad Request
status and details about the validation errors.
Usage:
To use this middleware, first define a Zod schema that describes the expected structure and data types of the request body for a particular route. Then, use the validateData
function to create a middleware for that route.
Example:
import express from "express";
import { z } from "zod";
import { validateData } from "./validationMiddleware";
const app = express();
app.use(express.json());
const userSchema = z.object({
name: z.string(),
age: z.number().positive(),
});
app.post("/users", validateData(userSchema), (req, res) => {
res.send("User is valid");
});
app.listen(3000, () => console.log("Server running on port 3000"));
In this example, userSchema defines the expected structure for user data. The validateData(userSchema)
middleware will validate incoming POST requests to /users
against this schema.
Error Handling
If the request body does not match the schema, the middleware responds with a400 Bad Request
status. The response includes a JSON object with an error
key indicating "Invalid data" and a details
key containing an array of error messages specifying which parts of the data did not match the schema.
This document provides an overview of all routes available in the "Warung Bu Ode" project. Each route is designed to handle specific aspects of the application, from authentication to managing menus and bills.
- Path:
/login
- Method:
POST
- Auth Required: No
The request to this endpoint must include a JSON payload with the following fields:
email
: User's email address.password
: User's password.
Example Request Body:
{
"email": "[email protected]",
"password": "userpassword"
}
The request body is validated against a predefined schema (loginSchema
) to ensure that all required fields are present and conform to the expected formats. This is done using the validateData
middleware.
If the request does not pass validation, a 400 Bad Request
response is returned with details about the validation errors.
- Success Response:
- Code: 200 OK
- Content:{ "token": "jwt.token.here" }
- Error Responses:
- If the credentials are invalid (user not found or password does not match):
- Code: 403 Forbidden
- Content: { "message": "Invalid Credentials" }
- For any other server errors:
- Code: 500 Internal Server Error
- Content: { "error": "Internal Server Error" }
- If the credentials are invalid (user not found or password does not match):
The loginAuth
controller performs the following steps:
- Extracts
email
andpassword
from the request body. - Attempts to find a user in the database with the provided email.
- If the user is found, compares the provided password with the hashed password stored in the database using
bcrypt
. - If the password matches, generates a JWT token with the user's ID and email, and returns it in the response.
- If the credentials are invalid, returns an error response indicating "Invalid Credentials".
- Catches and handles any other errors with a generic server error response.
- Passwords are hashed using
bcrypt
before being stored in the database to ensure security. - JWT tokens are used for authentication, providing a secure way to manage user sessions.
- Path:
/register
- Method:
POST
- Auth Required: No
The request to this endpoint must include a JSON payload with the following fields:
email
: User's email address (must be unique).password
: User's password.username
: User's chosen username.
Example Request Body:
{
"email": "[email protected]",
"password": "securepassword123",
"username": "newuser"
}
Before reaching the controller, the request body is validated against a predefined schema to ensure that all required fields are present and conform to the expected formats. This is done using the validateData
middleware with a registrationSchema
.
If the request does not pass validation, a 400 Bad Request
response is returned with details about the validation errors.
- Success Response:
- Code: 201 Created
- Content: { "message": "User Created" }
- Error Responses:
- If the user already exists (duplicate email):
- Code: 403 Forbidden
- Content: { "message": "User Already Exists" }
- For any other server errors:
- Code: 500 Internal Server Error
- Content: { "error": "Internal Server Error" }
- If the user already exists (duplicate email):
The registerAuth
controller performs the following steps:
- Extracts email, password, and username from the request body.
- Hashes the password using bcrypt.
- Attempts to create a new user record in the database with the provided details.
- Returns a success response if the user is created successfully.
- Handles known errors, such as duplicate email, and returns appropriate error responses.
- Catches and responds to any other errors with a generic server error message.
- Passwords are hashed using bcrypt before being stored in the database to ensure security.
- Input validation is performed to prevent injection attacks and ensure data integrity.
- Path: /warung
- Method: POST
- Auth Required: Yes
To create a new Warung, the request must include a JSON payload with the following fields:
- name: The name of the Warung.
- location: The location of the Warung.
Example Request Body:
{
"name": "Warung Makan Pak Budi",
"location": "Jalan Raya No. 123"
}
The request body is validated against the createWarungSchema to ensure that all required fields are present and valid. This validation is performed using the validateData middleware.
If the request does not meet the validation criteria, a 400 Bad Request
response is returned with details about the validation errors.
- Code: 201 Created
- Content: JSON representation of the newly created Warung.
If a Warung with the same name and location already exists:
- Code: 403 Forbidden
- Content: { "message": "Warung Already Exists" }
For any other server errors:
- Code: 500 Internal Server Error
- Content: { "error": "Internal Server Error" }
The createWarung controller performs the following steps:
- Extracts name, location, and the authenticated user's id from the request.
- Attempts to create a new Warung record in the database with the provided details.
- If successful, returns the newly created Warung record.
- Handles specific known errors, such as a duplicate Warung entry, by returning appropriate error responses.
- Catches and handles any other errors with a generic server error response.
- This endpoint requires user authentication. The user's ID is extracted from the authenticated session and associated with the new Warung record.
- Input validation is performed to prevent invalid data from being entered into the database.
- Path:
/warung
- Method:
GET
- Auth Required: Yes
This endpoint supports pagination and searching. The following query parameters can be used:
page
: The page number of the results to fetch (default is1
).limit
: The number of results per page (default is10
).search
: A search term to filter the results by the Warung's name.
Example Request URL:
/warung?page=2&limit=5&search=nasi
The request is validated using Zod to ensure that the provided query parameters meet the expected format. If the validation fails, a 400 Bad Request
response is returned with details about the validation errors.
-
Success Response:
- Code:
200 OK
- Content: A JSON object containing the list of Warungs, total count, current page, and total pages.
- Code:
-
Error Responses:
-
For validation errors:
- Code:
400 Bad Request
- Content: Details about the validation errors.
- Code:
-
For server errors:
- Code:
500 Internal Server Error
- Content:
{ "error": "Internal Server Error" }
- Code:
-
The getAllMyWarung
controller performs the following steps:
- Validates the request using Zod.
- Parses pagination and search parameters from the request query.
- Constructs a query with conditions based on the authenticated user's ID and optional search term.
- Fetches a paginated list of Warungs from the database.
- Returns the list of Warungs, along with pagination details.
- This endpoint requires user authentication. Only Warungs associated with the authenticated user's ID are returned.
- Input validation is performed to prevent SQL injection and other malicious activities.
- Path:
/warung/:warungId
- Method:
PATCH
- Auth Required: Yes
warungId
: The unique identifier of the Warung to be updated. This is a URL parameter.
The request body must contain the following field:
location
: The new location of the Warung.
Example Request Body:
{
"location": "New Location Address"
}
The request data is validated against updateWarungSchema
to ensure it meets the expected format and types. If the validation fails, a 400 Bad Request
response is returned with details about the validation errors.
- Code:
200 OK
- Content: A JSON object representing the updated Warung.
- If the Warung is not found:
- Code:
404 Not Found
- Content:
{ "message": "Warung not found" }
- Code:
- For server errors:
- Code:
500 Internal Server Error
- Content:
{ "error": "Internal Server Error" }
- Code:
The editWarungById
controller performs the following steps:
- Validates the request data.
- Checks if the Warung exists and belongs to the authenticated user.
- Updates the Warung's location.
- Returns the updated Warung.
- This endpoint requires user authentication. Only the owner of the Warung can update its details.
- Input validation is performed to prevent SQL injection and other malicious activities.
- Path:
/menu/:warungId
- Method:
POST
- Auth Required: Yes
warungId
: The unique identifier of the Warung to which the menu item will be added. This is a URL parameter.
The request body must contain the following fields:
title
: The title of the menu item.price
: The price of the menu item.desc
: A description of the menu item.available
: A boolean indicating whether the menu item is available.category
: The category of the menu item.
Additionally, the request must include an image file.
Example Request Body:
{
"title": "Nasi Goreng Spesial",
"price": 25000,
"desc": "Delicious special fried rice with extra toppings",
"available": true,
"category": "Main Course"
}
The request data is validated using the createMenuSchema
. The following middlewares are used:
authenticationMiddleware
: Ensures the user is authenticated.upload.single("image")
: Handles the image upload.imgValidate
: Validates the uploaded image.authorizationWarungMiddleware
: Ensures the user is authorized to add menu items to the specified Warung.validateData(createMenuSchema)
: Validates the request body data.
If the validation fails, a 400 Bad Request
response is returned with details about the validation errors.
- Code:
201 Created
- Content: A JSON object representing the newly created menu item.
- For validation errors:
- Code:
400 Bad Request
- Content: Details about the validation errors.
- Code:
- For server errors:
- Code:
500 Internal Server Error
- Content:
{ "error": "Internal Server Error" }
- Code:
The createMenu
controller performs the following steps:
- Extracts the authenticated user's ID from the request.
- Extracts the
warungId
from the request parameters. - Extracts
title
,price
,desc
,available
, andcategory
from the request body. - Converts the uploaded image to a base64 data URI and uploads it to a cloud storage.
- Creates a new menu item in the database with the provided details and the image URL.
- Returns the newly created menu item.
- This endpoint requires user authentication. The authenticated user's ID is associated with the new menu item.
- Authorization middleware ensures that only the owner of the Warung can add menu items to it.
- Input validation is performed to prevent SQL injection and other malicious activities.
- Path:
/menu
- Method:
GET
- Auth Required: Yes
page
: The page number of the results to fetch (default is1
).limit
: The number of results per page (default is10
).search
: A search term to filter the results by the menu item's title.category
: A category to filter the results by the menu item's category.available
: A boolean to filter the results by the menu item's availability.
Example Request URL:
/menu?page=2&limit=5&search=pasta&category=Main Course&available=true
The request is validated using Zod to ensure that the provided query parameters meet the expected format. If the validation fails, a 400 Bad Request
response is returned with details about the validation errors.
- Code:
200 OK
- Content: A JSON object containing the list of menu items, total count, current page, and total pages.
- For validation errors:
- Code:
400 Bad Request
- Content: Details about the validation errors.
- Code:
- For server errors:
- Code:
500 Internal Server Error
- Content:
{ "error": "Internal Server Error" }
- Code:
The getAllMenu
controller performs the following steps:
- Extracts the authenticated user's ID from the request.
- Validates the request using Zod.
- Parses pagination, search, category, and available parameters from the request query.
- Constructs a query with conditions based on the authenticated user's ID and optional filters.
- Fetches a paginated list of menu items from the database.
- Returns the list of menu items, along with pagination details.
- This endpoint requires user authentication. Only menu items associated with the authenticated user's ID are returned.
- Input validation is performed to prevent SQL injection and other malicious activities.
- Path:
/menu/:warungId/:menuId
- Method:
PATCH
- Auth Required: Yes
warungId
: The unique identifier of the Warung to which the menu item belongs. This is a URL parameter.menuId
: The unique identifier of the menu item to be updated. This is a URL parameter.
The request body can contain the following fields:
title
: The new title of the menu item.price
: The new price of the menu item.desc
: The new description of the menu item.available
: A boolean indicating whether the menu item is available.category
: The new category of the menu item.
Example Request Body:
{
"title": "Updated Nasi Goreng Spesial",
"price": 30000,
"desc": "Updated description for special fried rice",
"available": false,
"category": "Main Course"
}
The request data is validated using the updateMenuSchema
. The following middlewares are used:
authorizationWarungMiddleware
: Ensures the user is authorized to update menu items for the specified Warung.validateData(updateMenuSchema)
: Validates the request body data.
If the validation fails, a 400 Bad Request
response is returned with details about the validation errors.
- Code:
200 OK
- Content: A JSON object representing the updated menu item.
- For validation errors:
- Code:
400 Bad Request
- Content: Details about the validation errors.
- Code:
- For server errors:
- Code:
500 Internal Server Error
- Content:
{ "error": "Internal Server Error" }
- Code:
The updateMenu
controller performs the following steps:
- Extracts the
warungId
andmenuId
from the request parameters. - Extracts
title
,price
,desc
,available
, andcategory
from the request body. - Constructs an update object with the provided fields, converting data types as necessary.
- Updates the specified menu item in the database.
- Returns the updated menu item.
- This endpoint requires user authentication. Only the owner of the Warung can update its menu items.
- Authorization middleware ensures that only the owner of the Warung can update menu items for it.
- Input validation is performed to prevent SQL injection and other malicious activities.
- Path:
/bill/all
- Method:
GET
- Auth Required: Yes
page
: The page number of the results to fetch (default is1
).limit
: The number of results per page (default is10
).search
: A search term to filter the results by the customer's name.status
: A status to filter the results by the bill's status.approved
: A boolean to filter the results by the bill's approval status.
Example Request URL:
/bill/all?page=2&limit=5&search=john&status=paid&approved=true
The request is validated using Zod to ensure that the provided query parameters meet the expected format. If the validation fails, a 400 Bad Request
response is returned with details about the validation errors.
- Code:
200 OK
- Content: A JSON object containing the list of bills, total count, current page, and total pages.
- For validation errors:
- Code:
400 Bad Request
- Content: Details about the validation errors.
- Code:
- For server errors:
- Code:
500 Internal Server Error
- Content:
{ "error": "Internal Server Error" }
- Code:
The getAllUserBill
controller performs the following steps:
- Extracts the authenticated user's ID from the request.
- Validates the request using Zod.
- Parses pagination, search, status, and approved parameters from the request query.
- Constructs a query with conditions based on the authenticated user's ID and optional filters.
- Fetches a paginated list of bills from the database.
- Returns the list of bills, along with pagination details.
- This endpoint requires user authentication. Only bills associated with the authenticated user's ID are returned.
- Input validation is performed to prevent SQL injection and other malicious activities.
- Path:
/bill/:warungId/edit/:billId
- Method:
PATCH
- Auth Required: Yes
warungId
: The unique identifier of the Warung to which the bill belongs. This is a URL parameter.billId
: The unique identifier of the bill to be updated. This is a URL parameter.
The request body can contain the following fields:
status
: The new status of the bill.approved
: A boolean indicating whether the bill is approved.customerName
: The new name of the customer.
Example Request Body:
{
"status": "paid",
"approved": true,
"customerName": "John Doe"
}
The request data is validated using the updateBillSchema
. The following middlewares are used:
authorizationWarungMiddleware
: Ensures the user is authorized to update bills for the specified Warung.validateData(updateBillSchema)
: Validates the request body data.
If the validation fails, a 400 Bad Request
response is returned with details about the validation errors.
- Code:
200 OK
- Content: A JSON object representing the updated bill.
- For validation errors:
- Code:
400 Bad Request
- Content: Details about the validation errors.
- Code:
- If the bill is not found:
- Code:
404 Not Found
- Content:
{ "message": "Bill not found" }
- Code:
- For server errors:
- Code:
500 Internal Server Error
- Content:
{ "error": "Internal Server Error" }
- Code:
The updateBillById
controller performs the following steps:
- Extracts the
billId
anduserId
from the request parameters and the authenticated user respectively. - Validates the request body using the defined schema.
- Fetches the bill from the database using the
billId
anduserId
. - Constructs an update object with the provided fields, converting data types as necessary.
- Updates the specified bill in the database.
- Returns the updated bill.
- This endpoint requires user authentication. Only the owner of the Warung can update its bills.
- Authorization middleware ensures that only the owner of the Warung can update bills for it.
- Input validation is performed to prevent SQL injection and other malicious activities.
This project uses the following major dependencies:
- Node.js: Runtime environment.
- Express: Web application framework.
- Prisma: ORM for database management.
- Cloudinary: Service for managing media files.
- Zod: For schema validation.
- Other dependencies include
bcrypt
,body-parser
,cors
,dotenv
,http-status-codes
,jsonwebtoken
,multer
.
Special thanks to the contributors and supporters of the technologies used in this project. Their dedication to open source makes projects like this possible.
- Kurao Hikari - Initial Work - GitHub Profile
This project is licensed under the MIT License - see the LICENSE.md file for details.