Skip to main content

Overview

Create a new product in the Juadah bakery catalog. This endpoint accepts multipart/form-data to support image uploads via Cloudinary.

Endpoint

POST /api/products

Authentication & Authorization

This endpoint requires Admin access. Regular users will receive a 403 Forbidden error.
Requires authentication via cookie-based session with admin role.

Request Body

This endpoint accepts multipart/form-data for file uploads.
name
string
required
Product name. Must not be empty.
description
string
required
Product description. Must not be empty.
price
number
required
Product price in rupiah. Must be a valid number.
images
file[]
Array of image files to upload. Supports up to 5 images. Accepted formats: .png, .jpg, .jpeg.

Response

status
string
required
Response status. Returns "success" for successful requests.
data
object
required
Response data containing the created product.
products
object
The created product object.
id
number
Unique product identifier.
name
string
Product name.
description
string
Product description.
price
number
Product price in rupiah.
images
string[]
Array of uploaded image URLs from Cloudinary.

Example Request

Using cURL with Multipart Form Data

curl -X POST "https://juadah-backend.vercel.app/api/products" \
  -H "Cookie: accessToken=your-admin-access-token" \
  -F "name=Kue Bolu" \
  -F "description=Kue paling enak" \
  -F "price=10000" \
  -F "images=@/path/to/image1.png" \
  -F "images=@/path/to/image2.jpg"

Using JavaScript (Fetch API)

const formData = new FormData();
formData.append('name', 'Kue Bolu');
formData.append('description', 'Kue paling enak');
formData.append('price', '10000');

// Add multiple images
formData.append('images', imageFile1);
formData.append('images', imageFile2);

const response = await fetch('https://juadah-backend.vercel.app/api/products', {
  method: 'POST',
  credentials: 'include', // Include cookies
  body: formData
});

const result = await response.json();

Using Python (requests)

import requests

url = "https://juadah-backend.vercel.app/api/products"

files = [
    ('images', open('image1.png', 'rb')),
    ('images', open('image2.jpg', 'rb'))
]

data = {
    'name': 'Kue Bolu',
    'description': 'Kue paling enak',
    'price': '10000'
}

cookies = {
    'accessToken': 'your-admin-access-token'
}

response = requests.post(url, files=files, data=data, cookies=cookies)
print(response.json())

Example Response

Success Response (201)

{
  "status": "success",
  "data": {
    "products": {
      "id": 1,
      "name": "Kue Bolu",
      "description": "Kue paling enak",
      "price": 10000,
      "images": [
        "https://res.cloudinary.com/demo/image/upload/path/to/image.png",
        "https://res.cloudinary.com/demo/image/upload/path/to/image.jpg"
      ]
    }
  }
}

Validation Error (400)

{
  "status": "fail",
  "errors": {
    "code": 400,
    "message": "validation error",
    "details": {
      "name": "product name is required",
      "price": "product price cannot be empty",
      "images": "image extension is not supported"
    }
  }
}

Forbidden Error (403)

Returned when a non-admin user attempts to create a product.
{
  "status": "fail",
  "errors": {
    "code": 403,
    "message": "this action is only for user with admin access"
  }
}

Server Error (500)

{
  "status": "fail",
  "errors": {
    "code": 500,
    "message": "fail to create product and this is not your fault, please try again later"
  }
}

Validation Rules

  • name: Required, must not be empty
  • description: Required, must not be empty
  • price: Required, must be a valid number
  • images: Optional, maximum 5 images, must be .png, .jpg, or .jpeg format

Implementation Details

  • Images are uploaded to Cloudinary
  • The endpoint uses multer middleware to handle multipart/form-data
  • File validation occurs before upload
  • Product creation is transactional - if image upload fails, the product is not created