Expand my Community achievements bar.

Guidelines for the Responsible Use of Generative AI in the Experience Cloud Community.
SOLVED

POST from 3rd party client to SlingServlet registered using resourceTypes

Avatar

Level 3

I am trying to create a servlet, registered using resourceType, that can accept an HTTP POST from a client external to the AEM site. Here's is my current code:

 

 

package com.ab.mysite.core.servlets;

import org.osgi.service.component.annotations.Component;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(
	service=Servlet.class,
	property= {			
		"sling.servlet.resourceTypes="+ "mysite/components/structure/page",
		"sling.servlet.selectors=" + "biosync",
		"sling.servlet.extensions=" + "html",
		"sling.servlet.methods="+"POST",
		"sling.servlet.methods="+"GET"
	}	
)
public class BioSyncServlet extends SlingAllMethodsServlet {

	private static final long serialVersionUID = 1L;
	private static final Logger log = LoggerFactory.getLogger(BioSyncServlet.class);
		
	@Override
	protected void doPost(
			SlingHttpServletRequest request, 
			SlingHttpServletResponse response)	
	{
		try {
			addCorsHeader(response);
			response.setContentType("text/plain");
			response.getWriter().write(getResponse(request));
			response.getWriter().close();
		} 
		catch (Exception ex) {
			log.error(ex.getMessage());
		}
	}
	
	@Override
	protected void doGet(
			SlingHttpServletRequest request, 
			SlingHttpServletResponse response) 
			throws IOException, ServletException
	{		
			try {
			addCorsHeader(response);
			response.setContentType("text/plain");
			response.getWriter().write(getResponse(request));	
			response.getWriter().close();
		} 
		catch (Exception ex) {
			log.error(ex.getMessage());
		}
	}
	
	private void addCorsHeader(SlingHttpServletResponse response){        
		response.setHeader("Access-Control-Allow-Origin", "*");        
		response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD");
        response.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Origin, X-Requested-With, Content-Type, Accept");
        response.setHeader("Access-Control-Max-Age", "1728000");
    }
	
	private String getResponse(SlingHttpServletRequest request)
	{		
		String fName = request.getParameter("fname");
		String lName = request.getParameter("lname");
		
		String responseText = "Your first name is " + fName + " and your last name is " + lName;
		return responseText;
	}
}

 

 

If I make an HTTP GET request to any page on my site (they all have resourceType "mysite/components/structure/page") with the selector, credentials in the headers, and a querystring of "?fname=Marvin&lname=Palmer", it returns "Your first name is Marvin and your last name is Palmer" as expected.

 

But if I make an HTTP POST to this servlet with (same page, selector, credentials) and pass the params in the post body, I get a 500 error and "java.lang.IllegalArgumentException" saying value for key 'fname' can't be put into node: Marvin.

 

Interestingly, if I HTTP POST (with credentials) using the same url + "/jcr:content", then I get a 200 response, and lname and fname are written with values "Marvin" and "Palmer" to the JCR at that node path. 

 

But I can't figure out how to get the request to result in execution of my doPost() method. I was able to get this doPost() to work when I registered the servlet using a "bin/biosync" path instead of using resourceType, but I've read that's a discouraged practice. 

 

What am I doing wrong?

1 Accepted Solution

Avatar

Correct answer by
Level 8

Hi @mpalme1 

Whenever we register servlet using resourceType, then the request url for that servlet will be "${resource.path}.extension" here path value will be path where this component is added in any page. so, try to add this in data-attribute in your component html, inspect the page source of the page where this component is added & check the path. you need access this value in javascript to pass this url as ajax request url.

 

Component html :

<div id="compname-resource-path" data-resource-path="${resource.path}.extension">

 

</div>

 

$('#compname-resource-path').data('resource-path'); //request url

View solution in original post

5 Replies

Avatar

Correct answer by
Level 8

Hi @mpalme1 

Whenever we register servlet using resourceType, then the request url for that servlet will be "${resource.path}.extension" here path value will be path where this component is added in any page. so, try to add this in data-attribute in your component html, inspect the page source of the page where this component is added & check the path. you need access this value in javascript to pass this url as ajax request url.

 

Component html :

<div id="compname-resource-path" data-resource-path="${resource.path}.extension">

 

</div>

 

$('#compname-resource-path').data('resource-path'); //request url

Avatar

Level 3
Except I'm not trying to call the servlet from a component. I actually need to be able to call the servlet from a program running outside of AEM.

Avatar

Level 8

@mpalme1 

If you want access this servlet outside AEM then register this servlet as path based & use that path as request url. ideally we should not share resource based servlet path to 3rd party/to access outside AEM since this path is not constant value, it will be a dynamic path as resource path will be different as & when we move this component within page/site.

Avatar

Level 3
So, that being the case, I think I'd want to create a least privileged account in http://localhost:4502/useradmin that would be used for the auth headers of the request and only allow it to post to that path, but it seems like I can't assign permissions to an account for anything under path /bin. How would I go about that?