Expand my Community achievements bar.

SOLVED

How to reject a POST request when uploading a content fragment via REST when a unique ID is detected?

Avatar

Level 2

I am bulk uploading content fragments to AEM as a CS.

For this CF Model I have a property that is unique for all the content fragments, but to test when I tried uploading the same object twice, AEM did accept the POST request and created the CF and added '<cf-url>-1' with the same data and completely ignored the unique ID that I defined in the CF model. Normally, it should reject the request because the point of unique ID is that another CF with the same ID shouldn't exist. 
Is there a way I can implement this rule?

Topics

Topics help categorize Community content and increase your ability to discover relevant content.

1 Accepted Solution

Avatar

Correct answer by
Community Advisor

Hi @parth3 ,

To enforce uniqueness of a property when creating content fragments via REST in Adobe Experience Manager (AEM), you can leverage custom validation logic. Here's a general approach to implement this rule:

  1. Custom Validation Servlet: Create a custom servlet that intercepts the POST request for creating content fragments. This servlet will be responsible for checking if the unique ID already exists before allowing the creation of a new content fragment.

  2. Validation Logic: In the servlet, implement logic to query the existing content fragments to check if the unique ID already exists. If it does, reject the POST request with an appropriate error message.

  3. Register Servlet: Register the custom servlet with AEM so that it gets invoked when a POST request is made to create a content fragment.

Here's a simplified example of what the servlet might look like:

 

import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.osgi.service.component.annotations.Component;
import org.osgi.framework.Constants;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;

@Component(
    service = Servlet.class,
    property = {
        Constants.SERVICE_DESCRIPTION + "=Custom Content Fragment Creation Validator Servlet",
        ServletResolverConstants.SLING_SERVLET_PATHS + "=/bin/contentFragmentValidator",
        ServletResolverConstants.SLING_SERVLET_METHODS + "=" + HttpConstants.METHOD_POST
    }
)
public class ContentFragmentValidatorServlet extends SlingAllMethodsServlet {

    @Override
    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        // Get the unique ID from the request
        String uniqueId = request.getParameter("uniqueId");

        // Check if the unique ID already exists
        if (isUniqueIdExists(uniqueId)) {
            response.setStatus(HttpServletResponse.SC_CONFLICT); // 409 Conflict
            response.getWriter().write("Error: Content Fragment with the provided unique ID already exists.");
        } else {
            // Proceed with creating the content fragment
            // Your code to create content fragment goes here
            response.setStatus(HttpServletResponse.SC_CREATED); // 201 Created
            response.getWriter().write("Content Fragment created successfully.");
        }
    }

    private boolean isUniqueIdExists(String uniqueId) {
        // Logic to check if the unique ID already exists in the repository
        // You can use ResourceResolver to query the repository for existing content fragments
        // Return true if unique ID exists, false otherwise
    }
}

 

In this example, the servlet intercepts POST requests made to /bin/contentFragmentValidator. It retrieves the unique ID from the request parameters and checks if it already exists in the repository. If the unique ID exists, it returns a 409 Conflict response with an error message. Otherwise, it proceeds with creating the content fragment.

You'll need to customize isUniqueIdExists method to query the repository and check if the unique ID exists. You can use ResourceResolver to perform the query.

Remember to deploy this servlet to your AEM instance and ensure proper error handling and security measures are implemented as per your requirements.

View solution in original post

5 Replies

Avatar

Community Advisor

Hi,

 

Generally, the unique ID for any data structure in AEM is the node path (which includes the name), not any other field in its property. This rule also applies when working with Content Fragments. The API first checks if the node name exists, and if it does, it adds a new Content Fragment with a differentiator (-1), as you mentioned. This is how the API operates and adheres to the best practices of a microservice architecture. If there is any additional validation required before creating the Content Fragment, it should be implemented outside of this endpoint. Therefore, the solution would be for you to first check if the Content Fragment exists before using the Content Fragment creation endpoint.



Hope this helps

 

 



Esteban Bustamante

Avatar

Correct answer by
Community Advisor

Hi @parth3 ,

To enforce uniqueness of a property when creating content fragments via REST in Adobe Experience Manager (AEM), you can leverage custom validation logic. Here's a general approach to implement this rule:

  1. Custom Validation Servlet: Create a custom servlet that intercepts the POST request for creating content fragments. This servlet will be responsible for checking if the unique ID already exists before allowing the creation of a new content fragment.

  2. Validation Logic: In the servlet, implement logic to query the existing content fragments to check if the unique ID already exists. If it does, reject the POST request with an appropriate error message.

  3. Register Servlet: Register the custom servlet with AEM so that it gets invoked when a POST request is made to create a content fragment.

Here's a simplified example of what the servlet might look like:

 

import org.apache.sling.api.servlets.HttpConstants;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.servlets.ServletResolverConstants;
import org.osgi.service.component.annotations.Component;
import org.osgi.framework.Constants;

import javax.servlet.Servlet;
import javax.servlet.ServletException;
import java.io.IOException;

@Component(
    service = Servlet.class,
    property = {
        Constants.SERVICE_DESCRIPTION + "=Custom Content Fragment Creation Validator Servlet",
        ServletResolverConstants.SLING_SERVLET_PATHS + "=/bin/contentFragmentValidator",
        ServletResolverConstants.SLING_SERVLET_METHODS + "=" + HttpConstants.METHOD_POST
    }
)
public class ContentFragmentValidatorServlet extends SlingAllMethodsServlet {

    @Override
    protected void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
        // Get the unique ID from the request
        String uniqueId = request.getParameter("uniqueId");

        // Check if the unique ID already exists
        if (isUniqueIdExists(uniqueId)) {
            response.setStatus(HttpServletResponse.SC_CONFLICT); // 409 Conflict
            response.getWriter().write("Error: Content Fragment with the provided unique ID already exists.");
        } else {
            // Proceed with creating the content fragment
            // Your code to create content fragment goes here
            response.setStatus(HttpServletResponse.SC_CREATED); // 201 Created
            response.getWriter().write("Content Fragment created successfully.");
        }
    }

    private boolean isUniqueIdExists(String uniqueId) {
        // Logic to check if the unique ID already exists in the repository
        // You can use ResourceResolver to query the repository for existing content fragments
        // Return true if unique ID exists, false otherwise
    }
}

 

In this example, the servlet intercepts POST requests made to /bin/contentFragmentValidator. It retrieves the unique ID from the request parameters and checks if it already exists in the repository. If the unique ID exists, it returns a 409 Conflict response with an error message. Otherwise, it proceeds with creating the content fragment.

You'll need to customize isUniqueIdExists method to query the repository and check if the unique ID exists. You can use ResourceResolver to perform the query.

Remember to deploy this servlet to your AEM instance and ensure proper error handling and security measures are implemented as per your requirements.

Avatar

Community Advisor

Hi @parth3 

To enforce the uniqueness of a property in content fragments in AEM, you can use a custom validation rule.

1. Create a custom validation rule: In AEM, navigate to the Content Fragment Models console (`/aem/cfm/models.html`) and open the content fragment model you are working with. In the "Properties" tab, select the property that should be unique and click on the "Validation" tab. Add a custom validation rule by clicking on the "+" button.

2. Implement the validation logic: In the custom validation rule dialog, you can write JavaScript code to implement the uniqueness check. You can use the `com.day.cq.commons.jcr.JcrUtil` class to query the repository and check if a content fragment with the same property value already exists. Here's an example of how the code might look:
var uniqueProperty = properties.get("uniqueProperty");
var query = "SELECT * FROM [yourContentFragmentType] WHERE [uniqueProperty] = '" + uniqueProperty + "'";
var result = JcrUtil.query(session, query);
if (result.size() > 0) {
throw new Error("A content fragment with the same unique property already exists.");
}

Make sure to replace `[yourContentFragmentType]` with the actual node type of your content fragments.

3. Save the validation rule: After implementing the validation logic, save the custom validation rule. This rule will now be applied whenever a content fragment is created or updated.

 



Avatar

Level 2

parth3_0-1715178232813.png

I am in the CF Model editor mode. As you said, I am on the Properties tab for the ID property that I want use it as unique. But, I cannot see an option to add a custom validation script (i.e. Add a custom validation rule by clicking on the "+" button) the only option I see is Custom Validation Regex. 
Do you think this is because I am using AEM as a CS?