KAHIBARO
Discord Login Register

Admin API

Why an Admin API Matters in E‑Commerce

The public API of your e‑commerce backend is for customers. The admin API is for staff, operators, and internal tools. It gives trusted users full control over the store.

You will already have many features in the project, such as products, users, orders, and background jobs. The admin API does not invent new business logic. It gives a controlled, powerful interface to manage that logic.

Typical admin users:

The goal of this chapter is to show how to expose existing features for internal use, protect them with strong authorization, and make them efficient and safe to use.

Some admin functions you will likely support:

You should build the admin API on top of the same services, repositories, and entities used by the rest of the backend. The difference is in who can call it and how much power it gives them.

Designing Admin vs Public APIs

The admin API has different priorities than the public API.

Different audiences and priorities

Public API:

Admin API:

Admin endpoints can be more verbose and detailed, because they are used by technical or trained users. For example:

Separate namespace

Use a clear path prefix for admin routes, for example:

This helps:

Example structure:

AreaPath example
Admin products/admin/products, /admin/products/{id}
Admin categories/admin/categories, /admin/categories/{id}
Admin users/admin/users, /admin/users/{id}
Admin orders/admin/orders, /admin/orders/{id}
Admin inventory/admin/inventory/adjust
Admin jobs / tasks/admin/jobs, /admin/jobs/{id}

Different response models

You can use different models for the same resource in public vs admin APIs.

Example with FastAPI / Pydantic style models (language‑agnostic idea):

python
class ProductPublic(BaseModel):
    id: int
    name: str
    description: str
    price: Decimal
    currency: str
    image_urls: list[str]
class ProductAdmin(BaseModel):
    id: int
    name: str
    description: str
    price: Decimal
    currency: str
    image_urls: list[str]
    # Admin‑only fields
    cost_price: Decimal
    margin_percentage: float
    supplier_sku: str | None
    is_active: bool
    created_at: datetime
    updated_at: datetime
    last_purchased_at: datetime | None

This separation avoids accidental data leakage and keeps public responses simpler.

Versioning and stability

Public API changes can break clients. Admin UI and internal tools are under your control, so you can update them together with the API.

You still want to:

Authentication and Authorization for Admin

Admin APIs hold the most sensitive capabilities of your system. Treat them as highly critical.

Strong authentication

Use a strong authentication method for admin access:

Common pattern:

  1. User logs in via /auth/login or /admin/login.
  2. Server returns a token with user claims that include roles/permissions.
  3. Admin endpoints verify the token and inspect roles.

Example JWT payload:

json
{
  "sub": "user_123",
  "email": "admin@example.com",
  "roles": ["admin", "support"],
  "permissions": [
    "products:read",
    "products:write",
    "orders:read",
    "orders:refund",
    "users:read"
  ],
  "iat": 1727400000,
  "exp": 1727407200
}

Admin endpoints would require specific roles or permissions, not just any authenticated user.

Rule: Never allow access to /admin endpoints using the same permissions as normal customer endpoints. Admin accounts must be authenticated and authorized separately and more strictly.

Role‑based and permission‑based checks

Use the concepts you learned in the Authorization section:

Combine them in your checks:

Example check in pseudocode:

python
def require_permission(user, permission: str):
    if permission not in user.permissions:
        raise ForbiddenError("Missing permission: " + permission)
@router.post("/admin/orders/{order_id}/refund")
def refund_order(order_id: int, current_user: User = Depends(get_current_user)):
    require_permission(current_user, "orders:refund")
    # perform refund

Network and IP protections

In addition to authentication and authorization you can add network level defenses:

This is optional in small projects, but very important in real production setups.

Core Admin Endpoints

In the e‑commerce project you have several domains:

Admin API should provide full CRUD and management capabilities for these.

Admin product management

Some admin product endpoints:

MethodPathDescription
GET/admin/productsList products with filters
POST/admin/productsCreate a new product
GET/admin/products/{id}Get full product details
PUT/admin/products/{id}Replace product
PATCH/admin/products/{id}Partially update product
DELETE/admin/products/{id}Soft delete or archive a product

Typical fields in admin request body:

Example admin product creation payload:

json
{
  "name": "Wireless Headphones X100",
  "slug": "wireless-headphones-x100",
  "description": "High quality wireless headphones...",
  "price": 129.99,
  "currency": "USD",
  "cost_price": 80.00,
  "tax_rate": 0.20,
  "category_ids": [12, 34],
  "tags": ["audio", "wireless", "headphones"],
  "is_active": true,
  "is_featured": false,
  "image_urls": [
    "https://cdn.example.com/images/x100-front.jpg",
    "https://cdn.example.com/images/x100-side.jpg"
  ]
}

Admin category management

Admin categories usually include:

Endoints:

You can also add helper endpoints, for example:

Admin user management

Admin users manage customer accounts:

MethodPathDescription
GET/admin/usersSearch users by email, name, etc.
GET/admin/users/{id}Detailed user info
PATCH/admin/users/{id}Update profile, flags, notes
POST/admin/users/{id}/blockBlock a user account
POST/admin/users/{id}/unblockUnblock a user
GET/admin/users/{id}/ordersList user orders

Be careful with admin‑side operations that are dangerous:

You should require stronger permissions for these and often keep an audit trail.

Admin order management

Admin orders are central to support and operations:

Common endpoints:

MethodPathDescription
GET/admin/ordersList orders with filters
GET/admin/orders/{id}Get full order with user and items
PATCH/admin/orders/{id}Update status, notes, metadata
POST/admin/orders/{id}/refundCreate a refund
POST/admin/orders/{id}/cancelCancel an order
POST/admin/orders/{id}/resend-emailResend confirmation

Useful filters:

Example query:

GET /admin/orders?status=paid&created_from=2024-01-01&created_to=2024-01-31&page=1&limit=50

Example response shape:

json
{
  "items": [
    {
      "id": 1001,
      "user": {
        "id": 23,
        "email": "customer@example.com",
        "full_name": "Jane Doe"
      },
      "status": "paid",
      "payment_status": "captured",
      "total_amount": 199.90,
      "currency": "USD",
      "created_at": "2024-01-12T10:34:56Z"
    }
  ],
  "page": 1,
  "limit": 50,
  "total_items": 132,
  "total_pages": 3
}

Admin inventory management

Inventory features connect to the "Inventory" chapter, but the admin UI and API will expose them.

Typical endpoints:

Adjustment example:

json
{
  "product_id": 123,
  "variant_id": 456,
  "location_id": 1,
  "delta": -2,
  "reason": "Manual correction after damaged items",
  "note": "2 items broken during packing"
}

The backend would:

Admin Filters, Sorting, and Pagination

Admin users need to search and navigate large datasets, for example tens of thousands of orders or products. This is where good filtering and pagination design matters.

Common patterns for listing endpoints

You can define consistent parameters across admin listing endpoints:

ParameterTypePurpose
pageintPage number, starting from 1
limitintItems per page, default such as 20 or 50
sort_bystrField to sort on, such as created_at
sort_directionstrasc or desc
qstrFree text search (email, name, SKU, etc.)

You then add resource specific filters:

Example orders list:

GET /admin/orders?page=2&limit=25&status=paid&sort_by=created_at&sort_direction=desc

Example products list:

GET /admin/products?page=1&limit=50&category_id=12&is_active=true&q=headphones

Response shape for paginated results

Use a consistent response model:

json
{
  "items": [ /* list of resources */ ],
  "page": 1,
  "limit": 50,
  "total_items": 1234,
  "total_pages": 25
}

This makes admin UI components reusable. The frontend can use total_items and limit to build page navigation.

Safety considerations in filtering and sorting

When you accept sort_by or filter fields from the user:

Example of safe mapping in pseudocode:

python
ALLOWED_SORT_FIELDS = {
    "created_at": Order.created_at,
    "total_amount": Order.total_amount,
    "status": Order.status
}
if sort_by not in ALLOWED_SORT_FIELDS:
    sort_column = Order.created_at
else:
    sort_column = ALLOWED_SORT_FIELDS[sort_by]

This prevents SQL injection vulnerabilities.

Rule: Never concatenate raw query parameters directly into SQL ORDER BY or WHERE clauses. Always validate fields against an allowlist and use query parameter binding.

Bulk Operations and Background Jobs

Admin tasks often involve many records at once. For example:

Doing such operations in a single HTTP request that blocks until all work is done can:

The solution is to combine admin endpoints with background processing (previously covered in the course).

Pattern: Start a job, then poll for status

A common design:

  1. Admin sends a request to start a bulk job.
  2. Backend validates the request and creates a job record with status pending.
  3. Backend pushes the job to a queue or background worker.
  4. Response returns the job ID immediately.
  5. Admin UI periodically calls a job status endpoint to display progress.

Example: bulk price update

Request:

POST /admin/products/bulk-update-price

json
{
  "product_ids": [1, 2, 3, 4, 5],
  "price_change_type": "percentage", 
  "value": 10.0,  
  "direction": "increase" 
}

Response:

json
{
  "job_id": "job_abc123",
  "status": "pending"
}

Status endpoint:

GET /admin/jobs/job_abc123

json
{
  "job_id": "job_abc123",
  "type": "bulk_price_update",
  "status": "running",
  "created_at": "2024-02-01T10:00:00Z",
  "started_at": "2024-02-01T10:00:02Z",
  "finished_at": null,
  "total_items": 5,
  "processed_items": 3,
  "failed_items": 0,
  "errors": []
}

Admin UI can show a progress bar using processed_items / total_items.

Admin job types in an e‑commerce backend

Some useful job types:

Each job type might have its own payload and logic, but the job status model can stay consistent.

Safety and auditing for bulk operations

Bulk operations are risky, so add protections:

Example preview endpoint:

POST /admin/products/bulk-update-price/preview

json
{
  "category_id": 10,
  "price_change_type": "percentage",
  "value": 15.0,
  "direction": "decrease"
}

Response:

json
{
  "affected_count": 124,
  "sample_products": [
    { "id": 1, "old_price": 100.0, "new_price": 85.0 },
    { "id": 2, "old_price": 59.99, "new_price": 50.99 }
  ]
}

Auditing, Logging, and Safety

Admin APIs can change almost everything in your system. You should always be able to answer:

Audit logs

Create an audit log for important admin actions:

An audit log entry might contain:

Example stored in JSON form:

json
{
  "id": 1234,
  "timestamp": "2024-03-10T12:34:56Z",
  "admin_user_id": 42,
  "action": "order.refund",
  "resource_type": "order",
  "resource_id": 1001,
  "before": {
    "status": "paid",
    "refund_total": 0.0
  },
  "after": {
    "status": "refunded",
    "refund_total": 199.90
  },
  "ip_address": "203.0.113.10"
}

You might expose audit logs through admin API endpoints:

This helps investigations when something goes wrong.

Logging admin requests

For security and debugging:

This helps you:

Safety controls

You can add safety controls around very sensitive admin operations:

Rule: Never expose critical system secrets or full payment data through the admin API. Admins should see only what they need, such as last 4 digits of a card or masked tokens.

Designing a Simple Admin API for the Project

To make this concrete, here is a minimal but useful admin API design derived from earlier project chapters.

Example endpoint overview

AreaPath examplePurpose
ProductsGET /admin/productsList products with filters and pagination
POST /admin/productsCreate product
GET /admin/products/{id}View product details
PATCH /admin/products/{id}Edit product
POST /admin/products/{id}/imagesManage images (upload / reorder)
CategoriesGET /admin/categoriesList categories
POST /admin/categoriesCreate category
PATCH /admin/categories/{id}Edit category
UsersGET /admin/usersSearch users
GET /admin/users/{id}View user details
POST /admin/users/{id}/blockBlock user
OrdersGET /admin/ordersList and filter orders
GET /admin/orders/{id}Full order details
POST /admin/orders/{id}/refundRefund order
POST /admin/orders/{id}/cancelCancel order
InventoryGET /admin/inventory/stock-levelsView stock per product / variant
POST /admin/inventory/adjustAdjust stock
JobsPOST /admin/products/bulk-update-priceStart bulk price update job
GET /admin/jobs/{id}Check job status

Example endpoint in more detail

Admin "get order" endpoint:

GET /admin/orders/{id}

Response:

json
{
  "id": 1001,
  "status": "paid",
  "payment_status": "captured",
  "created_at": "2024-01-12T10:34:56Z",
  "updated_at": "2024-01-12T10:35:10Z",
  "user": {
    "id": 23,
    "email": "customer@example.com",
    "full_name": "Jane Doe",
    "is_blocked": false
  },
  "items": [
    {
      "product_id": 123,
      "variant_id": 456,
      "name": "Wireless Headphones X100",
      "sku": "X100-BLACK",
      "unit_price": 99.95,
      "quantity": 2,
      "total_price": 199.90
    }
  ],
  "shipping_address": {
    "full_name": "Jane Doe",
    "address_line1": "123 Main St",
    "city": "Springfield",
    "country": "US",
    "postal_code": "12345"
  },
  "billing_address": { /* ... */ },
  "payment": {
    "provider": "stripe",
    "transaction_id": "pi_12345",
    "paid_at": "2024-01-12T10:34:59Z"
  },
  "shipment": {
    "carrier": "UPS",
    "tracking_number": "1Z999AA10123456784",
    "shipped_at": null
  },
  "notes": [
    {
      "id": 1,
      "author": "admin@example.com",
      "message": "Customer requested fast shipping.",
      "created_at": "2024-01-12T10:35:05Z"
    }
  ]
}

This response is far more detailed than what the public API would expose, and it is designed for support agents that need to see everything about the order.

Summary

In the e‑commerce project, the admin API is:

Internally, it should reuse the same domain logic (services, repositories, models) as the rest of the backend. The difference is who can call it and what extra information and capabilities it exposes.

When you implement the Admin API for the project, start small:

  1. Identify the top 5 tasks admins must complete daily.
  2. Create endpoints for those tasks.
  3. Add filtering and pagination to make them usable at scale.
  4. Wrap sensitive actions in strong authorization checks and logging.

You can extend this foundation later with more admin features, including reports, dashboards, and integrations with external tools.

Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!