Thursday, September 3, 2026

SAP Commerce OCC Error Handling: Exception Handling, Error DTOs, HTTP Status Codes & Global Error Handling

Introduction

A REST API is not complete simply because it returns a successful response.

A production-ready API must also handle failures in a predictable and meaningful way.

Consider a SAP Commerce OCC API:

GET /occ/v2/electronics/customproducts/P999

What should happen when product P999 doesn't exist?

Should the API return:

500 Internal Server Error

Probably not.

A better response would indicate that the requested resource could not be found.

Similarly, if a customer sends invalid data, the API should return a client-side error rather than a generic server exception.

This is why OCC error handling is an important part of SAP Commerce development.

In this article, we'll cover:

  • SAP Commerce OCC exception handling
  • Common exceptions
  • HTTP status codes
  • Error DTOs
  • Validation errors
  • Global error handling
  • Custom exceptions
  • Authentication and authorization errors
  • Postman testing
  • Troubleshooting strategies
  • Interview questions
  • Enterprise best practices

What is OCC Error Handling?

OCC error handling is the mechanism used by SAP Commerce to convert application exceptions into structured HTTP responses.

A simplified flow is:

Client
  ↓
OCC Controller
  ↓
Facade
  ↓
Service
  ↓
DAO
  ↓
Exception
  ↓
OCC Error Handling
  ↓
HTTP Error Response
  ↓
Client

Instead of exposing internal Java stack traces, the API should return a controlled response.

For example:

{
  "errors": [
    {
      "type": "UnknownIdentifierError",
      "message": "Product not found"
    }
  ]
}

The exact response fields depend on the SAP Commerce version and configured OCC error-handling implementation.


Why Error Handling Matters

Good error handling provides:

  • Consistent API responses
  • Easier client-side handling
  • Better debugging
  • Improved security
  • Better user experience
  • Clearer monitoring
  • Easier integration testing

Poor error handling can expose internal implementation details and make production troubleshooting much harder.


Common HTTP Status Codes

A well-designed API uses appropriate HTTP status codes.

StatusMeaningTypical OCC Scenario
200OKSuccessful GET
201CreatedSuccessful resource creation
204No ContentSuccessful operation with no response body
400Bad RequestInvalid request
401UnauthorizedAuthentication missing/invalid
403ForbiddenInsufficient permissions
404Not FoundResource doesn't exist
409ConflictBusiness/data conflict
500Internal Server ErrorUnexpected server failure

200 OK

A successful GET commonly returns:

200 OK

Example:

GET /occ/v2/electronics/products/P100

Response:

{
  "code": "P100",
  "name": "Laptop"
}

201 Created

A successful create operation can return:

201 Created

For example:

POST /occ/v2/electronics/users

after successfully creating a customer.


204 No Content

Some successful operations don't need to return a response body.

For example:

DELETE /resource/123

could return:

204 No Content

depending on the endpoint implementation.


400 Bad Request

A 400 indicates that the client sent an invalid request.

Examples:

Missing required field
Invalid JSON
Invalid parameter
Invalid value
Malformed request

Example:

{
  "email": "invalid-email"
}

if the endpoint requires a valid email address.


401 Unauthorized

A 401 generally indicates an authentication problem.

Typical causes:

  • Missing access token
  • Expired token
  • Invalid token
  • Invalid authentication configuration

Example:

GET /occ/v2/electronics/users/current/orders

without a valid access token.


403 Forbidden

A 403 generally means that authentication succeeded but authorization failed.

For example:

Authenticated customer
      ↓
Attempts admin-only API
      ↓
403 Forbidden

Remember:

401 = Authentication problem
403 = Authorization problem

This is one of the most common OCC interview questions.


404 Not Found

Use 404 when the requested resource doesn't exist.

For example:

GET /occ/v2/electronics/products/UNKNOWN

If no product exists for that code, the API should return an appropriate not-found response.


409 Conflict

409 Conflict can be useful when the request conflicts with the current state of a resource.

Examples include:

  • Duplicate business identifier
  • Invalid state transition
  • Resource already exists
  • Concurrent update conflict

Whether a particular OCC endpoint uses 409 depends on its implementation and error mapping.


500 Internal Server Error

A 500 should generally indicate an unexpected server-side failure.

Examples:

  • Unhandled exception
  • Database failure
  • External service failure
  • Programming error

Do not intentionally return 500 for normal validation or not-found conditions.


Common SAP Commerce Exceptions

During OCC execution, various SAP Commerce exceptions may occur.

Common examples include:

UnknownIdentifierException
ModelNotFoundException
InterceptorException
ValidationException
IllegalArgumentException
CommerceCartModificationException

The exact exceptions depend on the service being called.


UnknownIdentifierException

Suppose an API retrieves a product by code:

ProductModel product =
        productService.getProductForCode(code);

If the product cannot be found, the service layer can throw an appropriate identifier-related exception.

Conceptually:

if (product == null)
{
    throw new UnknownIdentifierException(
        "Product not found: " + code);
}

The OCC layer can then translate this into an appropriate REST error response.


ModelNotFoundException

This exception can occur when a requested model cannot be found in situations where the underlying API expects it to exist.

For example:

Order
Customer
Product
Cart

When exposing these resources through OCC, the exception should be transformed into a client-friendly response rather than leaking internal details.


ValidationException

Validation exceptions can occur when request data or model data fails validation.

For example:

Email missing
Invalid date
Missing mandatory field
Invalid business value

A good API should communicate clearly which input caused the failure.


InterceptorException

SAP Commerce interceptors can reject model operations.

For example:

PrepareInterceptor
ValidateInterceptor
RemoveInterceptor

Suppose an attribute is mandatory:

externalId

and the model is saved without it.

A validation or interceptor-related exception may be raised.

That exception should be handled appropriately at the application boundary.


OCC Error Response

A typical structured error response can look like:

{
  "errors": [
    {
      "type": "UnknownIdentifierError",
      "message": "Product P999 was not found"
    }
  ]
}

Depending on the version and configuration, an OCC error response can contain additional information such as:

type
message
reason
subject
subjectType
language

The exact schema should be verified against the OCC version used by the project.


Why Should We Return Structured Errors?

Imagine your frontend receives:

500 Internal Server Error

with no useful information.

The developer has no idea what happened.

Compare that with:

{
  "errors": [
    {
      "type": "UnknownIdentifierError",
      "message": "Product P999 was not found"
    }
  ]
}

Now the client can handle the error appropriately.


Exception Mapping

The OCC layer maps Java exceptions to HTTP errors.

Conceptually:

UnknownIdentifierException
        ↓
404
        ↓
UnknownIdentifierError

Another example:

AuthenticationException
        ↓
401

and:

AccessDeniedException
        ↓
403

The exact mappings depend on the configured SAP Commerce security and exception-handling infrastructure.


Error Handling in Controller

Avoid putting large amounts of exception-handling logic into every controller.

For example, don't repeat this everywhere:

try
{
    // business logic
}
catch (Exception e)
{
    // manually construct response
}

A centralized exception-handling mechanism is generally easier to maintain.


Global Exception Handling

A global exception handler can provide a central place to handle errors.

In Spring-based applications, concepts such as:

@ControllerAdvice

and:

@ExceptionHandler

are commonly used for centralized MVC exception handling.

A simplified example:

@ControllerAdvice
public class GlobalExceptionHandler
{
    @ExceptionHandler(
        UnknownIdentifierException.class)
    public ResponseEntity<?> handleNotFound(
            UnknownIdentifierException exception)
    {
        // Build appropriate response
        return ResponseEntity.notFound().build();
    }
}

However, in SAP Commerce OCC projects, you should first understand and use the platform's existing OCC exception-handling mechanisms rather than introducing a parallel error framework unnecessarily.


Custom OCC Exceptions

Sometimes a business requirement needs a specific error.

For example:

Cannot cancel an already shipped order

Instead of returning:

500

you can define appropriate business exception handling.

Conceptually:

throw new InvalidOrderStateException(
    "Order cannot be cancelled after shipment");

The OCC layer can then translate the exception into a structured error response.


Example: Cancel Order

Suppose:

Order status = SHIPPED

and the customer tries:

POST /orders/123/cancel

The service checks:

if (OrderStatus.SHIPPED.equals(order.getStatus()))
{
    throw new InvalidOrderStateException(
        "Shipped orders cannot be cancelled");
}

The API should return a meaningful client-facing error rather than a generic 500.


Validation Errors

Suppose we have:

{
  "firstName": "",
  "email": "abc"
}

If the endpoint requires:

firstName → mandatory
email → valid format

the API should identify the invalid fields.

Conceptually:

{
  "errors": [
    {
      "type": "ValidationError",
      "message": "First name is required",
      "subject": "firstName"
    },
    {
      "type": "ValidationError",
      "message": "Invalid email address",
      "subject": "email"
    }
  ]
}

The exact representation depends on the project's OCC validation configuration.


Don't Expose Stack Traces

Never return:

{
  "stackTrace": "java.lang.NullPointerException..."
}

to a customer or external client.

Stack traces can reveal:

  • Internal class names
  • File paths
  • Database details
  • Infrastructure details
  • Security-sensitive information

Log diagnostic information internally and return a controlled API response.


Logging Errors

A useful production log should capture:

Request ID
Endpoint
HTTP method
User/client
Exception type
Error message
Timestamp
Correlation ID

Example:

RequestId=REQ-10001
Endpoint=/occ/v2/electronics/products/P999
Exception=UnknownIdentifierException
Product=P999

Do not log:

Passwords
OAuth tokens
Client secrets
Sensitive customer information

Error Handling with Postman

Postman is useful for validating OCC error behaviour.

Test 1: Invalid Product

Request:

GET /occ/v2/electronics/products/P999

Expected:

404 Not Found

Test 2: No Authentication

Request:

GET /occ/v2/electronics/users/current/orders

without a token.

Expected:

401 Unauthorized

Test 3: Insufficient Permission

Use a valid authenticated user without the required permission.

Expected:

403 Forbidden

Test 4: Invalid Request

Send incomplete request data.

Expected:

400 Bad Request

Error Handling in CI/CD

Automated API tests should validate both:

Success scenarios
Failure scenarios

For example:

Product exists → 200
Product missing → 404
Invalid request → 400
Missing token → 401
Insufficient permission → 403

This prevents accidental changes to your API contract.


Error Handling Test Matrix

ScenarioExpected Status
Valid product200
Product not found404
Invalid request400
Missing token401
Invalid permissions403
Successful create201
Successful delete204
Unexpected server failure500

This table can become a useful regression checklist.


Common Mistakes

Returning 500 for Everything

Bad:

Product not found → 500
Invalid input → 500
Unauthorized → 500

This makes the API difficult to consume.


Catching Exception Too Broadly

Avoid:

catch (Exception e)
{
    throw new RuntimeException();
}

This can hide the actual business error.


Swallowing Exceptions

Avoid:

try
{
    // operation
}
catch (Exception e)
{
    // do nothing
}

Failures must be logged and handled appropriately.


Exposing Internal Messages

Avoid returning:

SQL Exception
Database table doesn't exist
NullPointerException

directly to API consumers.


Best Practices

Use Meaningful HTTP Status Codes

Don't use 500 for client errors.

Keep Error Responses Consistent

Clients should receive a predictable structure.

Centralize Common Error Handling

Use the platform's OCC mechanisms and Spring error-handling facilities appropriately.

Log Internally

Capture detailed diagnostics in server logs.

Protect Sensitive Information

Never expose credentials, tokens or internal infrastructure details.

Test Failure Scenarios

Negative scenarios are just as important as happy-path scenarios.


Enterprise Example

Imagine a checkout API:

POST /occ/v2/electronics/users/current/carts/123/payment

Possible outcomes:

Valid payment
        ↓
200 / 201

Invalid payment data
        ↓
400

Not authenticated
        ↓
401

Not authorized
        ↓
403

Cart doesn't exist
        ↓
404

Payment state conflict
        ↓
409

Payment service failure
        ↓
500

This makes the API predictable for the storefront or mobile application.


Interview Questions

What is OCC error handling?

It is the mechanism that converts backend exceptions into appropriate HTTP responses and structured OCC error information.


What is the difference between 400 and 500?

400 generally indicates that the request from the client is invalid, while 500 indicates an unexpected server-side failure.


What is the difference between 401 and 403?

401 indicates an authentication problem. 403 means the caller is authenticated but does not have sufficient permission.


What should happen when a product doesn't exist?

The API should normally return a not-found response such as:

404 Not Found

with an appropriate structured error.


Should stack traces be returned to API clients?

No. Detailed stack traces should remain on the server side.


Where should business validation occur?

Business validation generally belongs in the appropriate Service Layer/domain logic, while request-shape validation can happen at the API boundary.


Should every controller have its own try-catch?

No. Centralized exception handling is generally easier to maintain. Use SAP Commerce's existing OCC exception-handling facilities where applicable.


Real Interview Scenario

Question

Your custom OCC API returns 500 when a product code doesn't exist. How would you fix it?

Answer

I would first inspect the service and DAO flow.

Controller
   ↓
Facade
   ↓
Service
   ↓
DAO

Then determine how the missing product is represented.

Instead of allowing a generic exception or null-pointer failure to reach the web layer, the service should use an appropriate identifier-related exception.

The OCC error-handling mechanism can then map that exception to a suitable 404 response and structured error payload.

I would also add an automated regression test for the missing-product scenario.


Another Interview Scenario

Question

The API returns 401 even though Postman has a token.

What would you investigate?

Answer

I would check:

Token expiration
Token format
Authorization header
Bearer prefix
OAuth client
Scope/roles
Endpoint security configuration
Environment-specific OAuth configuration
Clock differences

Another Interview Scenario

Question

The API returns 403 after a successful login.

What does that tell you?

Answer

Authentication likely succeeded, but authorization failed.

I would investigate:

Client roles
User roles
Endpoint restrictions
Spring Security configuration
Required OCC role

Complete Error-Handling Architecture

Remember this flow:

                         CLIENT
                            |
                            ↓
                     OCC Controller
                            |
                            ↓
                         Facade
                            |
                            ↓
                         Service
                            |
                            ↓
                          DAO
                            |
                            ↓
                       Exception
                            |
                            ↓
                 OCC Error Handling
                            |
              ┌─────────────┼──────────────┐
              ↓             ↓              ↓
             400           404             500
         Bad Request    Not Found     Server Error
              |
              ↓
        Structured Error
              |
              ↓
            CLIENT

For security-related failures:

Authentication Failure → 401
Authorization Failure  → 403

Conclusion

Good error handling is a critical part of a production-ready SAP Commerce OCC API.

The most important principles are:

Correct Exception
       ↓
Correct HTTP Status
       ↓
Structured Error Response
       ↓
Useful Server Logging
       ↓
Secure Client Response

In this article, we covered:

  • OCC exception handling
  • HTTP status codes
  • 400, 401, 403, 404, 409, and 500
  • Common SAP Commerce exceptions
  • Validation errors
  • Global exception handling
  • Custom business exceptions
  • Postman testing
  • CI/CD validation
  • Security considerations
  • Production troubleshooting
  • Interview scenarios

The goal is not simply to prevent an exception from crashing an API. The goal is to make the API predictable, secure, debuggable, and easy for client applications to consume.

Tuesday, September 1, 2026

SAP Commerce OCC Authentication & OAuth 2.0 Explained: Complete Guide with Postman

Introduction

Security is one of the most important aspects of SAP Commerce OCC Web Services.

In a real-world eCommerce application, APIs cannot simply be exposed to every client.

For example, an API such as:

GET /occ/v2/electronics/users/current/orders

contains customer-specific information and must be protected.

SAP Commerce uses OAuth 2.0 as the standard authorization framework for OCC Web Services. OCC security is implemented using configurable Spring Security mechanisms, with authentication and authorization applied to determine whether a client or user can access a particular resource.

In this article, we will understand:

  • What OAuth 2.0 is
  • Authentication vs authorization
  • OCC security architecture
  • OAuth clients
  • Access tokens
  • JWT tokens
  • Client Credentials flow
  • Authorization Code flow
  • PKCE
  • Anonymous vs authenticated OCC APIs
  • 401 vs 403
  • Postman testing
  • Common OCC security problems
  • SAP Commerce interview questions

1. What is OAuth 2.0?

OAuth 2.0 is an authorization framework that allows applications to access protected resources without requiring the client application to directly handle the user's credentials.

In SAP Commerce, OAuth is used to secure OCC APIs.

A simplified flow looks like:

Client Application
       |
       | Request access token
       ↓
Authorization Server
       |
       | Access Token
       ↓
Client Application
       |
       | Authorization: Bearer <token>
       ↓
OCC API
       |
       ↓
Resource Server
       |
       ↓
Protected Resource

SAP Commerce Cloud documents OAuth as the default authorization framework for commerce-driven OCC Web Services.


2. Authentication vs Authorization

This is one of the most common interview questions.

Authentication

Authentication answers:

Who are you?

For example:

Username
Password
OAuth token

The system verifies the identity.


Authorization

Authorization answers:

What are you allowed to do?

For example:

Customer
    ↓
Can view own orders

Client
    ↓
Can access allowed APIs

Admin
    ↓
Can perform administrative operations

A simple way to remember:

Authentication = Who are you?

Authorization = What can you do?

SAP Commerce OCC security separates these concepts and uses roles and other constraints to determine access.


3. OCC Security Architecture

A simplified architecture is:

                 CLIENT
                    |
                    |
             OAuth Access Token
                    |
                    ↓
          ┌──────────────────┐
          │  OCC Web Layer   │
          └────────┬─────────┘
                   |
                   ↓
          ┌──────────────────┐
          │ Spring Security  │
          └────────┬─────────┘
                   |
             Authentication
                   |
                   ↓
             Authorization
                   |
                   ↓
          ┌──────────────────┐
          │ OCC Controller   │
          └────────┬─────────┘
                   |
                   ↓
                Facade
                   |
                   ↓
                Service
                   |
                   ↓
                 DAO

The important point is:

Security is checked before the request reaches your business logic.


4. What is an OAuth Client?

An OAuth client represents an application requesting access to protected resources.

For example:

Mobile Application
Web Application
Integration System
Third-Party Application
Backend Service

The client is normally identified using:

client_id
client_secret

For example:

client_id = mobile_app
client_secret = ********

The secret should never be exposed in client-side code.


5. What is an Access Token?

An access token represents authorization granted to a client.

After successfully authenticating with the authorization server, the client receives a token.

The client then sends:

Authorization: Bearer <access-token>

with subsequent API requests.

Conceptually:

Client
  |
  | client credentials
  ↓
Authorization Server
  |
  | access token
  ↓
Client
  |
  | Bearer token
  ↓
OCC API

6. JWT Access Tokens

For current SAP Commerce Cloud OAuth support using JDK 21, SAP documents JWT access tokens.

JWT stands for:

JSON Web Token

A JWT is a self-contained token containing claims about the authorization.

A simplified JWT looks like:

xxxxx.yyyyy.zzzzz

It consists of:

Header
.
Payload
.
Signature

For example:

{
  "sub": "customer@example.com",
  "roles": [
    "CUSTOMERGROUP"
  ],
  "exp": 1780000000
}

The actual claims depend on the SAP Commerce configuration.

SAP documents that current JDK 21 OAuth support uses JWTs for access-token management and that the resource server validates the JWT signature using public keys available through a JWKS endpoint.


7. JWT Authentication Flow

The current flow can be visualized as:

                 Client
                   |
                   | 1. Request Token
                   ↓
          Authorization Server
                   |
                   | 2. Signed JWT
                   ↓
                 Client
                   |
                   | 3. API Request
                   | Authorization: Bearer JWT
                   ↓
           OCC Resource Server
                   |
                   | 4. Verify JWT
                   ↓
              OCC Endpoint

The resource server can validate the JWT signature using the authorization server's public keys.

This means the resource server does not have to perform a database lookup for every JWT validation.


8. OAuth Grant Types

OAuth supports different authorization flows.

For SAP Commerce, the flow you should understand depends on your Commerce version and security configuration.

For modern JDK 21-based SAP Commerce Cloud OAuth, the important flows are:

Client Credentials
Authorization Code

The rebuilt OAuth implementation removed the older:

Resource Owner Password
Implicit

flows because they are deprecated/discouraged by current OAuth security practices.

This version distinction is important when working with older SAP Commerce projects.


9. Client Credentials Flow

The Client Credentials flow is useful when:

An application needs to access resources on its own behalf.

There is no end-user involved.

Example:

Integration System
       |
       ↓
SAP Commerce OCC

Possible use cases:

  • Backend integration
  • ERP integration
  • Middleware
  • Scheduled integration
  • Server-to-server communication

10. Client Credentials Flow Diagram

Integration Application
          |
          | client_id
          | client_secret
          ↓
Authorization Server
          |
          | access_token
          ↓
Integration Application
          |
          | Bearer token
          ↓
OCC API

11. Client Credentials Request

A typical token request looks conceptually like:

POST /authorizationserver/oauth/token
Content-Type: application/x-www-form-urlencoded

Request:

grant_type=client_credentials
client_id=my-client
client_secret=my-secret

The exact endpoint and configuration can vary by SAP Commerce version and deployment.

SAP's OAuth documentation provides the Client Credentials flow as the mechanism for giving a client access to resources it owns.


12. Example Token Response

A token response may look like:

{
    "access_token": "eyJhbGciOi...",
    "token_type": "Bearer",
    "expires_in": 3600
}

The client then uses:

Authorization: Bearer eyJhbGciOi...

for protected API calls.


13. Authorization Code Flow

The Authorization Code flow is designed for applications where a user is involved.

For example:

Customer
   ↓
Web Application
   ↓
SAP Commerce

The application redirects the user to the authorization server.

The user authenticates and grants access.

The authorization server returns an authorization code.

The application exchanges that code for tokens.


14. Authorization Code Flow

The simplified flow is:

User
 |
 ↓
Client Application
 |
 | Authorization Request
 ↓
Authorization Server
 |
 | Login / Consent
 ↓
User
 |
 | Authentication
 ↓
Authorization Server
 |
 | Authorization Code
 ↓
Client Application
 |
 | Exchange Code
 ↓
Authorization Server
 |
 | Access Token
 ↓
Client Application
 |
 | Bearer Token
 ↓
OCC API

SAP documents the Authorization Code flow as a secure method where the user is redirected to the authorization server and the resulting authorization code is exchanged for an access token.


15. PKCE

PKCE stands for:

Proof Key for Code Exchange

It improves the security of the Authorization Code flow, particularly for public clients such as native applications and single-page applications.

The flow uses:

code_verifier
      ↓
code_challenge

The client creates a random:

code_verifier

and derives:

code_challenge

from it.

The authorization request includes:

code_challenge
code_challenge_method=S256

The token request later includes:

code_verifier

SAP's current Authorization Code documentation states that PKCE supports the S256 code challenge method.


16. Why PKCE is Important

Imagine a malicious application intercepts an authorization code.

Without PKCE, it may attempt to exchange that code.

With PKCE:

Authorization Code
        +
Code Verifier
        ↓
Token

The attacker doesn't possess the original verifier.

Therefore, the stolen authorization code is much less useful.


17. Anonymous OCC Requests

Not every OCC API requires a customer login.

Some APIs can be accessed anonymously depending on the endpoint and configuration.

For example, public catalog information may be available without a customer token.

Conceptually:

Anonymous User
      |
      ↓
Public OCC API
      |
      ↓
Product/Catalog Data

However:

Anonymous does not automatically mean completely unsecured.

Security configuration still applies.

SAP documents different OCC roles including ANONYMOUS, client roles, customer roles and guest roles.


18. Customer Authentication

A registered customer can authenticate and receive an access token.

Then:

GET /occ/v2/electronics/users/current/orders

can use:

Authorization: Bearer <customer-token>

The special:

current

identifier represents the user associated with the OAuth token in OCC APIs.

SAP's OCC documentation explicitly describes current as representing the user associated with the OAuth token.


19. Client vs Customer

This is important.

Client

Represents an application.

Example:

Mobile Application
Integration System
Backend Service

Customer

Represents an actual shopper.

Example:

john@example.com

So:

Client
   ↓
Application identity

Customer
   ↓
User identity

20. OCC Roles

SAP Commerce OCC security uses roles to determine access.

Common conceptual roles include:

ANONYMOUS
CLIENT
TRUSTED_CLIENT
CUSTOMERGROUP
CUSTOMERMANAGERGROUP
GUEST

The exact roles and configuration depend on the Commerce version and project.

SAP documents that OAuth-authenticated clients can be assigned client roles and customer authentication can result in customer roles.


21. 401 Unauthorized

One of the most common errors when testing OCC APIs is:

401 Unauthorized

This generally indicates an authentication problem.

Possible reasons:

Missing token
Invalid token
Expired token
Invalid client credentials
Invalid authentication configuration

Example:

GET /occ/v2/electronics/users/current/orders

without a token may result in:

401 Unauthorized

22. 403 Forbidden

Now consider:

403 Forbidden

This is different.

The user/client may have been authenticated successfully, but does not have permission to perform the requested operation.

Think:

401 → Who are you?

403 → I know who you are, but you're not allowed.

This distinction is extremely important during troubleshooting.


23. 401 vs 403

HTTP StatusMeaning
400Invalid request
401Authentication failed/missing
403Authenticated but not authorized
404Resource not found
500Server-side error

A simple interview answer:

401 is primarily an authentication problem, while 403 indicates that the request has been authenticated but access is denied.


24. Testing OCC Authentication Using Postman

Postman is extremely useful for testing SAP Commerce OCC APIs.

Create a collection:

SAP Commerce OCC
│
├── Authentication
│
├── Products
│
├── Cart
│
├── Orders
│
└── Customers

25. Step 1 — Generate Token

Create:

POST

to your configured authorization server token endpoint.

For example:

https://localhost:9002/authorizationserver/oauth/token

The exact endpoint depends on your Commerce version and configuration.

Use:

Content-Type:
application/x-www-form-urlencoded

26. Step 2 — Send Credentials

For Client Credentials:

grant_type=client_credentials
client_id=<client-id>
client_secret=<client-secret>

Your configured client must have appropriate roles/access.


27. Step 3 — Copy the Token

The authorization server returns an access token.

For example:

{
    "access_token": "eyJhbGciOi...",
    "token_type": "Bearer",
    "expires_in": 3600
}

Copy:

access_token

28. Step 4 — Call OCC API

Now call:

GET /occ/v2/electronics/products/P100

Headers:

Authorization: Bearer <access-token>

Example:

Authorization:
Bearer eyJhbGciOi...

29. Postman Authorization Tab

Instead of manually creating the header, you can use:

Authorization
     ↓
Type: Bearer Token
     ↓
Token: <access-token>

Postman automatically generates:

Authorization: Bearer <token>

30. Testing an Anonymous API

For a public API, you may be able to call:

GET /occ/v2/electronics/products/P100

without:

Authorization

However, this depends on your endpoint's security configuration.

Don't assume every GET endpoint is public.


31. Securing a Custom OCC API

Suppose yesterday we created:

GET /occ/v2/electronics/customproducts/P100

Now we want only authenticated customers to access it.

The flow becomes:

Client
   |
   | OAuth token
   ↓
Spring Security
   |
   | Authentication
   ↓
Authorization
   |
   | Allowed
   ↓
CustomProductController

Security should be configured at the appropriate OCC/Spring Security layer rather than manually checking tokens inside the controller.


32. Don't Validate Tokens Manually

Avoid code like:

if (token.equals("some-token"))
{
    // allow access
}

This is completely wrong for a production application.

Authentication should be handled by the configured security framework.

Your controller should focus on business functionality.


33. Security Configuration

SAP Commerce OCC security is highly configurable through Spring Security.

Depending on the Commerce version, relevant security configuration is located in the webservices/OCC security configuration.

SAP documents security configuration for OCC through Spring Security and separate security configuration for OCC web-service versions.

The important conceptual architecture is:

HTTP Request
      ↓
Security Filter
      ↓
Authentication
      ↓
Authorization
      ↓
Controller

34. Current vs Older SAP Commerce OAuth

This is particularly important if you work on multiple SAP Commerce projects.

Older Commerce versions may use the older OAuth implementation and may document flows such as:

Password
Client Credentials
Authorization Code
Implicit

However, SAP's rebuilt OAuth capability uses current Spring Security support.

For the JDK 21 implementation, SAP documents:

Authorization Code
Client Credentials

and JWT-based access tokens.

The older Password and Implicit flows were removed from the rebuilt implementation.

Therefore, always check the exact SAP Commerce release before copying OAuth configuration from another project.


35. Why This Matters in Real Projects

Suppose you join a project using:

SAP Commerce 2211

and another developer gives you OAuth configuration from an older project.

You may see:

Password Grant

and:

Implicit Grant

You should not blindly copy it.

First check:

SAP Commerce version
JDK version
OAuth implementation
Spring Security version
Cloud vs on-premise

Security configuration is one area where version differences matter significantly.


36. Common OAuth Problems

Problem 1 — Invalid Client

You receive something similar to:

invalid_client

Check:

client_id
client_secret
client configuration
client authentication method

Problem 2 — Invalid Grant

Check:

grant_type

and verify that the configured OAuth client supports the requested flow.


Problem 3 — 401 from OCC

Check:

Authorization header
Token expiration
Token signature
Client configuration
OAuth configuration

Problem 4 — 403 from OCC

Check:

User roles
Client roles
Endpoint security
Authorization configuration

37. Security Best Practices

Never expose client secrets

Don't put:

client_secret

inside:

JavaScript
Mobile application
Git repository
Public configuration

Always use HTTPS

Tokens and credentials should never be sent over plain HTTP in production.


Use short-lived access tokens

Shorter token lifetimes reduce the impact of token leakage.


Use refresh tokens where appropriate

Authorization Code scenarios can use refresh tokens to obtain new access tokens without requiring the user to authenticate again.


Use PKCE

For public clients, PKCE provides additional protection for the Authorization Code flow.


Don't log access tokens

Avoid:

LOG.info("Token = " + token);

Tokens are sensitive credentials.


38. OAuth Flow Comparison

FlowTypical Use
Client CredentialsServer-to-server
Authorization CodeUser-facing applications
Authorization Code + PKCEPublic/mobile/browser clients
PasswordLegacy/older implementations
ImplicitLegacy/deprecated

For modern SAP Commerce Cloud, focus your learning on:

Client Credentials
Authorization Code
PKCE
JWT

39. Real-World Example

Imagine an SAP Commerce architecture:

                 React Storefront
                       |
                       ↓
               Authorization Server
                       |
                       ↓
                  Access Token
                       |
                       ↓
                OCC Web Services
                       |
          ┌────────────┴────────────┐
          ↓                         ↓
       Product                    Cart
          ↓                         ↓
       Facade                    Facade
          ↓                         ↓
       Service                   Service

The React application doesn't directly access:

ProductModel
CartModel
OrderModel

It communicates with OCC using REST APIs and OAuth-based security.


40. Interview Question: What is OAuth2 in SAP Commerce?

A good answer:

OAuth 2.0 is the authorization framework used to secure SAP Commerce OCC Web Services. A client obtains an access token from the authorization server and sends that token in the Authorization Bearer header when calling protected OCC resources. Spring Security validates the request and authorization is based on the authenticated principal and configured roles.


41. Interview Question: Authentication vs Authorization?

Answer:

Authentication verifies the identity of the client or user. Authorization determines whether that authenticated principal has permission to access a particular resource or perform an operation.


42. Interview Question: What is a JWT?

Answer:

JWT stands for JSON Web Token. It is a signed, self-contained token containing claims. In current SAP Commerce Cloud JDK 21 OAuth support, JWTs are used as access tokens. The OCC resource server validates the token signature using public keys exposed through the JWKS mechanism.


43. Interview Question: What is Client Credentials Flow?

Answer:

Client Credentials is used for machine-to-machine communication where there is no end-user involved. The client authenticates using its configured credentials and receives an access token that it can use to access authorized resources.


44. Interview Question: What is Authorization Code Flow?

Answer:

Authorization Code is used when a user is involved. The client redirects the user to the authorization server, the user authenticates and grants access, and the client receives an authorization code which is exchanged for an access token.


45. Interview Question: What is PKCE?

Answer:

PKCE stands for Proof Key for Code Exchange. It adds a code verifier/challenge mechanism to the Authorization Code flow and helps protect public clients from authorization-code interception attacks.


46. Interview Question: 401 vs 403?

Answer:

401 → Authentication problem

403 → Authorization problem

For example:

401
No/invalid/expired token

403
Valid identity but insufficient permissions

47. Interview Question: Can OCC APIs be anonymous?

Answer:

Yes. Some OCC endpoints can be accessed anonymously depending on their security configuration. However, protected APIs require appropriate authentication and authorization. Anonymous access does not mean that all security checks are bypassed.

SAP explicitly documents public OCC endpoints and notes that some operations may still require an appropriate client token even when the endpoint does not require a customer login.


48. Interview Scenario

Question

Your OCC API works in Postman without authentication, but fails with:

401 Unauthorized

when called from the storefront.

What would you check?

Answer

I would investigate:

1. Is the storefront sending the Authorization header?

2. Is the access token expired?

3. Is the token issued for the correct client?

4. Is the endpoint protected?

5. Are the storefront and OCC using the same OAuth configuration?

6. Is Spring Security configured correctly?

7. Are there environment-specific properties?

8. Is HTTPS/proxy configuration affecting the request?

49. Another Interview Scenario

Question

The token is valid, but your API returns:

403 Forbidden

What do you check?

Answer

I would check:

User/client roles
       ↓
Endpoint authorization
       ↓
Spring Security configuration
       ↓
Required OCC role
       ↓
Base site/security configuration

The key point is that authentication succeeded but authorization failed.


50. Complete OCC Security Flow

Remember this diagram:

                    CLIENT
                       |
                       |
               Request Token
                       |
                       ↓
              AUTHORIZATION
                 SERVER
                       |
                       |
                  JWT TOKEN
                       |
                       ↓
                    CLIENT
                       |
                       |
          Authorization: Bearer JWT
                       |
                       ↓
                OCC WEB LAYER
                       |
                       ↓
              SPRING SECURITY
                       |
             ┌─────────┴─────────┐
             ↓                   ↓
        Authentication      Authorization
             |                   |
             └─────────┬─────────┘
                       ↓
                OCC CONTROLLER
                       |
                       ↓
                    FACADE
                       |
                       ↓
                   SERVICE
                       |
                       ↓
                     DAO
                       |
                       ↓
                  DATABASE

Conclusion

OAuth 2.0 is a fundamental part of SAP Commerce OCC security.

The most important concepts to remember are:

OAuth 2.0
    ↓
Authorization Server
    ↓
Access Token
    ↓
Bearer Token
    ↓
Spring Security
    ↓
Authentication
    ↓
Authorization
    ↓
OCC API

For modern SAP Commerce Cloud, especially JDK 21 environments, pay particular attention to:

JWT
Client Credentials
Authorization Code
PKCE
Spring Security
Resource Server
Authorization Server

Also remember that OAuth configuration differs between older and newer Commerce releases. Don't copy OAuth configuration from an old SAP Commerce project without checking the target Commerce/JDK version first.

Thursday, August 27, 2026

SAP Commerce Custom OCC API Development: Complete Step-by-Step Java Guide

Introduction

In the previous article, we discussed the architecture of SAP Commerce OCC Web Services.

We saw the typical request flow:

Client
   ↓
OCC Controller
   ↓
Facade
   ↓
Service
   ↓
DAO
   ↓
FlexibleSearch
   ↓
Database

Today, instead of only discussing the architecture, we are going to build a custom OCC API.

We will create an API that retrieves a product by product code.

Our final API will look like:

GET /occ/v2/electronics/customproducts/P100

and return:

{
  "code": "P100",
  "name": "Laptop",
  "description": "Business Laptop"
}

This is the kind of practical knowledge that is especially useful when working on real SAP Commerce projects.

SAP's current documentation recommends using OCC Extensions to extend OCC functionality. OCC extensions contain REST controllers and related classes in /src, while their web Spring configuration is placed under /resources/occ/v2/<extension>/web/spring.


1. What Are We Going to Build?

Our custom API will follow this architecture:

                    REST CLIENT
                         |
                         ↓
              CustomProductController
                         |
                         ↓
                CustomProductFacade
                         |
                         ↓
                CustomProductService
                         |
                         ↓
                  CustomProductDao
                         |
                         ↓
                 FlexibleSearch
                         |
                         ↓
                    Database

Response:

Database
   ↓
ProductModel
   ↓
Service
   ↓
Facade
   ↓
Converter
   ↓
ProductData
   ↓
ProductWsDTO
   ↓
JSON

2. Prerequisites

Before implementing the API, you should have:

  • SAP Commerce installed
  • A custom SAP Commerce extension
  • Java knowledge
  • Spring knowledge
  • Basic FlexibleSearch knowledge
  • Basic OCC knowledge
  • Postman or another REST client

3. Create an OCC Extension

For this example, let's assume our extension is:

customocc

SAP's OCC extension naming convention requires the extension name to end with occ.

For example:

xyzocc
customocc
mycompanyocc

SAP documents generating OCC extensions using the yocc extension template and adding the resulting extension to localextensions.xml.


4. Add the Extension to localextensions.xml

Open:

config/localextensions.xml

Add:

<extension name="customocc"/>

For example:

<extensions>

    <extension name="commercewebservices"/>

    <extension name="customcore"/>
    <extension name="customfacades"/>
    <extension name="customocc"/>

</extensions>

The exact dependency structure depends on your project.


5. OCC Extension Directory Structure

A typical OCC extension looks like:

customocc
│
├── extensioninfo.xml
│
├── resources
│   │
│   └── occ
│       └── v2
│           └── customocc
│               │
│               └── web
│                   └── spring
│                       └── customocc-web-spring.xml
│
└── src
    │
    └── com
        └── mycompany
            └── customocc
                │
                └── controllers

This structure is important.

SAP's documentation specifies that the Spring configuration should be under:

/resources/occ/v2/<extension_name>/web/spring

and the configuration filename should end with:

-web-spring.xml


6. Create the DAO

Our DAO will retrieve a product using FlexibleSearch.

Create:

public interface CustomProductDao
{
    ProductModel findProductByCode(String code);
}

Implementation:

public class DefaultCustomProductDao
        implements CustomProductDao
{
    @Resource
    private FlexibleSearchService flexibleSearchService;

    @Override
    public ProductModel findProductByCode(
            final String code)
    {
        final String query =
                "SELECT {p.pk} " +
                "FROM {Product AS p} " +
                "WHERE {p.code} = ?code";

        final FlexibleSearchQuery searchQuery =
                new FlexibleSearchQuery(query);

        searchQuery.addQueryParameter(
                "code",
                code);

        final SearchResult<ProductModel> result =
                flexibleSearchService.search(searchQuery);

        return result.getResult()
                .stream()
                .findFirst()
                .orElse(null);
    }
}

The DAO has one responsibility:

Retrieve the data.

It should not contain presentation logic.


7. Create the Service

Now create the service interface:

public interface CustomProductService
{
    ProductModel getProductByCode(String code);
}

Implementation:

public class DefaultCustomProductService
        implements CustomProductService
{
    @Resource
    private CustomProductDao customProductDao;

    @Override
    public ProductModel getProductByCode(
            final String code)
    {
        return customProductDao
                .findProductByCode(code);
    }
}

The architecture is now:

Service
   ↓
DAO
   ↓
FlexibleSearch

8. Why Do We Need the Service Layer?

A common mistake is:

Controller
   ↓
DAO

Instead, we use:

Controller
   ↓
Facade
   ↓
Service
   ↓
DAO

Why?

Because business logic belongs in the Service Layer.

For example, tomorrow we might introduce:

Only APPROVED products
Only products from a specific catalog
Customer-specific pricing
Stock validation
Product visibility rules

That logic can be handled by the Service Layer.


9. Create the Data Object

Now we need an object to carry product information.

For example:

public class CustomProductData
{
    private String code;
    private String name;
    private String description;

    public String getCode()
    {
        return code;
    }

    public void setCode(final String code)
    {
        this.code = code;
    }

    public String getName()
    {
        return name;
    }

    public void setName(final String name)
    {
        this.name = name;
    }

    public String getDescription()
    {
        return description;
    }

    public void setDescription(
            final String description)
    {
        this.description = description;
    }
}

This object is different from:

ProductModel

The model represents the SAP Commerce item.

The Data object represents the information we want to expose through the application layer.


10. Create the Converter

SAP Commerce uses converters and populators extensively to construct Data objects from Models or other service-layer objects. SAP's documentation recommends Spring-configured converters and keeping conversion logic inside populators.

Create:

public class CustomProductPopulator
        implements Populator<ProductModel,
                             CustomProductData>
{
    @Override
    public void populate(
            final ProductModel source,
            final CustomProductData target)
    {
        target.setCode(source.getCode());
        target.setName(source.getName());
        target.setDescription(
                source.getDescription());
    }
}

11. Why Use a Populator?

Suppose tomorrow we want to add:

Price
Stock
Images
Categories
Classification
Reviews
Promotions

Instead of putting everything into one huge class, we can create:

CustomProductBasicPopulator
CustomProductPricePopulator
CustomProductStockPopulator
CustomProductImagePopulator

This keeps the conversion logic modular.

SAP specifically describes populators as a pipeline of population tasks and notes that configurable populators can help avoid unnecessary conversion and reduce performance/bandwidth costs.


12. Create the Facade

Create:

public interface CustomProductFacade
{
    CustomProductData getProductByCode(
            String code);
}

Implementation:

public class DefaultCustomProductFacade
        implements CustomProductFacade
{
    @Resource
    private CustomProductService customProductService;

    @Resource
    private Converter<ProductModel,
                       CustomProductData> customProductConverter;

    @Override
    public CustomProductData getProductByCode(
            final String code)
    {
        final ProductModel product =
                customProductService
                        .getProductByCode(code);

        if (product == null)
        {
            return null;
        }

        return customProductConverter
                .convert(product);
    }
}

Now:

Facade
   ↓
Service
   ↓
DAO

13. Create the WsDTO

Now create the web-service DTO.

public class CustomProductWsDTO
{
    private String code;
    private String name;
    private String description;

    public String getCode()
    {
        return code;
    }

    public void setCode(final String code)
    {
        this.code = code;
    }

    public String getName()
    {
        return name;
    }

    public void setName(final String name)
    {
        this.name = name;
    }

    public String getDescription()
    {
        return description;
    }

    public void setDescription(
            final String description)
    {
        this.description = description;
    }
}

The purpose is to keep the API contract separate from internal SAP Commerce models.

SAP's OCC implementation documentation identifies WsDTO as the data layer used by the OCC REST API.


14. Create the OCC Controller

Now we get to the most important part.

Create:

@Controller
@RequestMapping(
        value = "/{baseSiteId}/customproducts")
public class CustomProductController
{
    @Resource
    private CustomProductFacade customProductFacade;

    @RequestMapping(
            value = "/{code}",
            method = RequestMethod.GET)
    @ResponseBody
    public CustomProductWsDTO getProduct(
            @PathVariable final String code)
    {
        final CustomProductData productData =
                customProductFacade
                        .getProductByCode(code);

        return convertToWsDTO(productData);
    }

    protected CustomProductWsDTO convertToWsDTO(
            final CustomProductData data)
    {
        final CustomProductWsDTO dto =
                new CustomProductWsDTO();

        dto.setCode(data.getCode());
        dto.setName(data.getName());
        dto.setDescription(
                data.getDescription());

        return dto;
    }
}

SAP's official OCC extension example follows this general pattern: a controller is created under /src, mapped using Spring MVC annotations, and returns a WsDTO.


15. Our API URL

The controller:

@RequestMapping(
    value = "/{baseSiteId}/customproducts")

combined with:

@RequestMapping(
    value = "/{code}",
    method = RequestMethod.GET)

gives:

/occ/v2/{baseSiteId}/customproducts/{code}

For example:

/occ/v2/electronics/customproducts/P100

SAP documents /occ/v2 as the standard web root for commercewebservices.


16. Configure the Spring Beans

Now we need to tell Spring about our beans.

Create:

customocc-web-spring.xml

under:

resources/occ/v2/customocc/web/spring/

Example:

<bean id="customProductDao"
      class="com.mycompany.customocc.dao.impl.DefaultCustomProductDao">
</bean>

<bean id="customProductService"
      class="com.mycompany.customocc.service.impl.DefaultCustomProductService">
    <property name="customProductDao"
              ref="customProductDao"/>
</bean>

<bean id="customProductPopulator"
      class="com.mycompany.customocc.populator.CustomProductPopulator">
</bean>

<bean id="customProductConverter"
      class="de.hybris.platform.servicelayer.dto.converter.impl.AbstractPopulatingConverter">
    <property name="targetClass"
              value="com.mycompany.customocc.data.CustomProductData"/>

    <property name="populators">
        <list>
            <ref bean="customProductPopulator"/>
        </list>
    </property>
</bean>

<bean id="customProductFacade"
      class="com.mycompany.customocc.facade.impl.DefaultCustomProductFacade">
    <property name="customProductService"
              ref="customProductService"/>

    <property name="customProductConverter"
              ref="customProductConverter"/>
</bean>

Note: In a real project, you would normally separate beans into the appropriate core/facades/OCC extensions rather than placing every layer inside the OCC extension. This example keeps the article easy to understand.


17. Build the Project

After creating the extension and configuration:

ant clean all

Then restart the SAP Commerce server.

For a local environment, you may use your normal SAP Commerce startup process.


18. Test the API Using Postman

Open Postman.

Select:

GET

Enter:

https://localhost:9002/occ/v2/electronics/customproducts/P100

Depending on your local SSL configuration, you may use:

http://localhost:9001/occ/v2/electronics/customproducts/P100

Use the port configured in your environment.


19. Authentication

If the endpoint is secured, obtain an appropriate OAuth access token and add:

Authorization: Bearer <access-token>

SAP Commerce OCC uses configurable Spring Security mechanisms for securing OCC calls.


20. Expected Response

If product P100 exists:

{
    "code": "P100",
    "name": "Laptop",
    "description": "Business Laptop"
}

The complete flow is:

GET /occ/v2/electronics/customproducts/P100
                    |
                    ↓
          CustomProductController
                    |
                    ↓
           CustomProductFacade
                    |
                    ↓
           CustomProductService
                    |
                    ↓
             CustomProductDao
                    |
                    ↓
             FlexibleSearch
                    |
                    ↓
              ProductModel
                    |
                    ↓
                Converter
                    |
                    ↓
             ProductData
                    |
                    ↓
                WsDTO
                    |
                    ↓
                  JSON

21. Handling Product Not Found

The current example returns null.

In a production API, this is not ideal.

Instead, we should throw a meaningful exception.

For example:

if (product == null)
{
    throw new UnknownIdentifierException(
            "Product not found: " + code);
}

Then the OCC error-handling mechanism can generate an appropriate error response.

For example:

{
    "errors": [
        {
            "type": "UnknownIdentifierError",
            "message": "Product not found: P999"
        }
    ]
}

SAP Commerce provides an OCC error-response mechanism specifically for converting exceptions into REST responses.


22. Bad Request vs Not Found

A good API should distinguish errors.

Invalid request

400 Bad Request

Authentication failure

401 Unauthorized

Access denied

403 Forbidden

Resource doesn't exist

404 Not Found

Server error

500 Internal Server Error

23. Don't Put FlexibleSearch in Controller

Avoid:

@Controller
public class ProductController
{
    @RequestMapping(...)
    public ProductWsDTO getProduct(...)
    {
        // FlexibleSearch here
    }
}

This creates tight coupling.

Instead:

Controller
    ↓
Facade
    ↓
Service
    ↓
DAO

This is easier to:

  • Test
  • Maintain
  • Extend
  • Debug
  • Reuse

24. Don't Return ProductModel

Avoid:

public ProductModel getProduct(...)

from the API.

Prefer:

ProductModel
     ↓
ProductData
     ↓
ProductWsDTO

This prevents internal persistence structures from becoming your public API contract.


25. OCC Extension vs OCC AddOn

This is an important topic for experienced SAP Commerce developers.

Modern SAP Commerce provides OCC Extensions.

An OCC extension:

Depends on commercewebservices

and is automatically imported into the Commerce Web Services Spring context.

SAP explicitly documents that OCC extensions are not web extensions and don't require the traditional AddOn installation process.

Architecture:

commercewebservices
        ↑
        |
    customocc

Whereas the older AddOn approach had a different dependency/installation model.

For new development, you should understand the OCC Extension architecture and also recognize older AddOn-based implementations in legacy projects.


26. Why OCC Extensions Are Better for New Development

With an OCC extension:

customocc
   |
   ├── Controllers
   ├── Spring beans
   ├── DTOs
   └── Messages

There is no need to copy controller files into the web application.

SAP documents that Commerce Web Services imports OCC extension Spring configurations automatically using the OCC extension path convention.


27. Performance Considerations

When designing an OCC API, don't only focus on making the endpoint work.

You should also consider performance.

Avoid unnecessary database queries

Bad:

Product
 ↓
Price query
 ↓
Stock query
 ↓
Category query
 ↓
Image query
 ↓
Review query

for every request.

Instead, carefully design your service and converter/populator pipeline.

Avoid huge responses

Don't return:

100+ fields

when the client needs:

5 fields

SAP specifically highlights configurable populators as a way to avoid unnecessary conversion and reduce performance/bandwidth costs.


28. Pagination

Never return thousands of products in one API response.

Instead:

GET /occ/v2/electronics/products?
    pageSize=20&
    currentPage=0

Conceptually:

Page 0 → 20 products
Page 1 → next 20
Page 2 → next 20

Pagination is especially important for:

  • Product search
  • Orders
  • Customers
  • Categories
  • Saved carts

29. API Versioning

Imagine your API is:

/occ/v2/electronics/customproducts/P100

Later you make a breaking change.

You should think carefully about API compatibility rather than unexpectedly changing the existing response contract.

Versioning provides a way to evolve APIs safely.


30. Testing Strategy

For a production OCC API, don't test only through Postman.

You should have:

Unit tests

Test:

Facade
Service
Populator
Converter

Integration tests

Test:

DAO
FlexibleSearch
Spring configuration

OCC/API tests

Test:

HTTP request
Authentication
Response
HTTP status
Error response

31. Interview Question: Explain Your Custom OCC API

If an interviewer asks:

"Explain how you created a custom OCC API in SAP Commerce."

A strong answer would be:

"I created a dedicated OCC extension and added a Spring MVC controller. The controller accepts the REST request and delegates to a facade. The facade calls the service layer, which contains the business logic and uses a DAO for data retrieval. The DAO executes FlexibleSearch and returns the model. I then use a converter and populator to transform the model into a Data object, which is exposed through a WsDTO. Finally, OCC serializes the WsDTO into JSON."

That's a much stronger answer than:

"I created a controller and exposed a REST endpoint."


32. Interview Question: Why Facade Between Controller and Service?

Answer:

The facade provides a presentation-oriented API and hides underlying service complexity.

It also allows us to:

  • Coordinate multiple services
  • Convert models to Data objects
  • Prepare data for presentation
  • Keep controllers thin

33. Interview Question: Why Use Populators?

Answer:

Populators separate individual conversion responsibilities.

For example:

ProductBasicPopulator
ProductPricePopulator
ProductStockPopulator
ProductImagePopulator

They can be composed into a converter pipeline.

This improves modularity and makes it easier to add or remove data population logic. SAP's documentation specifically recommends keeping conversion logic in populators rather than calling populators directly from application code.


34. Interview Question: What Happens When OCC Receives a Request?

A good answer:

HTTP Request
     ↓
Spring MVC
     ↓
OCC Controller
     ↓
Facade
     ↓
Service
     ↓
DAO
     ↓
Database

Then:

Database
     ↓
Model
     ↓
Converter
     ↓
Data
     ↓
WsDTO
     ↓
HTTP Response

35. Complete Project Structure

A practical project could eventually look like:

customcore
│
├── dao
├── service
└── model


customfacades
│
├── facade
├── data
├── converter
└── populator


customocc
│
├── controllers
├── dto
└── resources
    └── occ
        └── v2
            └── customocc
                └── web
                    └── spring
                        └── customocc-web-spring.xml

This separation is cleaner for a real enterprise project.


36. Final Architecture

Remember this:

                    CLIENT
                      |
                      | HTTP
                      ↓
              ┌───────────────┐
              │ OCC Controller│
              └───────┬───────┘
                      |
                      ↓
              ┌───────────────┐
              │    Facade     │
              └───────┬───────┘
                      |
                      ↓
              ┌───────────────┐
              │    Service    │
              └───────┬───────┘
                      |
                      ↓
              ┌───────────────┐
              │      DAO      │
              └───────┬───────┘
                      |
                      ↓
                FlexibleSearch
                      |
                      ↓
                   Database
                      |
                      ↓
                ProductModel
                      |
                      ↓
                  Converter
                      |
                      ↓
                  Populator
                      |
                      ↓
                 ProductData
                      |
                      ↓
                  WsDTO
                      |
                      ↓
                    JSON
                      |
                      ↓
                   CLIENT

Conclusion

Creating a custom OCC API is one of the most useful skills for a SAP Commerce developer.

The most important concepts to remember are:

OCC Extension
      ↓
Controller
      ↓
Facade
      ↓
Service
      ↓
DAO
      ↓
FlexibleSearch
      ↓
Model
      ↓
Converter
      ↓
Populator
      ↓
Data
      ↓
WsDTO
      ↓
JSON

The key principle is separation of responsibilities.

The Controller handles HTTP.

The Facade handles presentation-oriented orchestration.

The Service handles business logic.

The DAO handles data access.

The Converter/Populator handles object transformation.

The WsDTO defines what the API exposes.

This architecture makes SAP Commerce applications easier to maintain, test, scale and extend.