The URL that you use to access a custom apex rest service is determined by the @RestResource
annotation, which can only be used at the class level.
So it makes sense for Salesforce to only allow a single @HttpPost
method in a @RestResource
annotated class. There would be no way to provide a more specific URL to be able to choose between two @HttpPost
methods. The @HttpPost
method also needs to be static, so that precludes using inner classes to help juggle things.
What you can do, however, is have your @HttpPost
method act as a receptionist. Your @HttpPost
method stands at the front door and interacts with all incoming requests. You can then have several other methods (or other classes) that your @HttpPost
receptionist dispatches the incoming request to.
Something like
@RestResource(urlMapping='/my/endpoint/*')
global class MyRestAPI{
// You could use an if/else if chain or a switch statement to take care of this,
// but I personally find using a Map to be more elegant
private static Map<String, iRestPostHandler> resourceToHandler = new Map<String, iRestPostHandler>{
'/my/endpoint/service1' => new Service1Handler(),
'/my/endpoint/service2' => new Service2Handler()
}
@HttpPost
global static void dispatch(){
// @Http<X> annotated methods have access to the RestContext variable, which
// contains a RestRequest instance
// The RestRequest contains the request URI, which will always start with the
// urlMapping defined in the @RestResource annotation
if(resourceToHandler.containsKey(RestContext.request.requestURI)){
// dispatch to the appropriate class
resourceToHandler.get(RestContext.request.requestURI).handleRequest(RestContext.request, RestContext.response);
}
}
public interface iRestPostHandler{
// Have the interface take both the request (so you can handle the request body
// separately in each concrete class) and response (so that the dispatcher
// doesn't need to worry about handling output)
public void handleRequest(RestRequest req, RestResponse resp)
}
// Because we don't need to use the @HttpPost annotation (not like we could), we
// can make use of inner classes
public class Service1Handler implements iRestPostHandler{
public void handleRequest(RestRequest req, RestResponse resp){
Map<String, Object> requestBodyDeserialized = JSON.deserializeUntyped(req.requestBody);
//do work
}
}
public class Service2Handler implements iRestPostHandler{
public void handleRequest(RestRequest req, RestResponse resp){
Map<String, Object> requestBodyDeserialized = JSON.deserializeUntyped(req.requestBody);
//do different work
}
}
}