Rest Routing with Multiple Wildcards / Supporting REST Routing for Nested Resources


Running into a SalesForce REST mapping issue involving multiple wildcards in an url. Is this not supported? Is there anyway to supporting routing for nested resources?

My Setup

I have this REST structure

  • GET /teams/{teamid}/members (list team members)
  • POST /teams/{teamid}/members (create team member)
  • PUT /teams/{teamid}/members/{memberid} (update team member)
  • DELETE /teams/{teamid}/members/{memberid} (delete team member

And I setup the routing as followed:

  • REST_teams_id_members.cls @RestResource(urlMapping='/v1/teams/*/members')
  • REST_teams_id_members_id.cls @RestResource(urlMapping='/v1/teams/*/members/*')


This was working fine, but now I can only get one set of routes to work at any given time. Which ever one was compiled first gets precedence. So both GET /teams/123/members and DELETE/teams/123/members/345` get routed to the same class.

So If I compile REST_teams_id_member.cls (making the other class the first compiled), I get the following routing

  • GET /teams/{teamid}/members -> REST_teams_id_members_id.cls -> 405 Method Not Allowed
  • POST /teams/{teamid}/members -> REST_teams_id_members_id.cls -> 405 Method Not Allowed
  • PUT /teams/{teamid}/members/{memberid} -> REST_teams_id_members_id.cls -> Good
  • DELETE /teams/{teamid}/members/{memberid} -> REST_teams_id_members_id.cls -> Good

If I then compile REST_teams_id_members_id.cls (swapping the order), I get this routing

  • GET /teams/{teamid}/members -> REST_teams_id_members.cls -> Good
  • POST /teams/{teamid}/members -> REST_teams_id_members.cls -> Good
  • PUT /teams/{teamid}/members/{memberid} -> REST_teams_id_members.cls -> 405 Method Not Allowed
  • DELETE /teams/{teamid}/members/{memberid} -> REST_teams_id_members.cls -> 405 Method Not Allowed


I feel like I’m taking crazy pills, it doesn’t make any sense how /teams/123/members/345 could possible match @RestResource(UrlMapping='/teams/*/members), and vice versa, I’m at a total loss for how /teams/123/members could route to @RestResource(UrlMapping='teams/*/members/*. They seem wholly distinct!!

We’ve got an imminent rollout and I’m complete stuck. Praying that SFSE community can help me out.


While it’s not clear why that doesn’t already work, to get your code out the door, my suggestion is to build your own REST dispatching service. The following pseudo code implementation works as followed:

  1. Register for all REST requests for a particular url (e.g. /teams/*)
  2. Register different controllers (which implement the interface Dispatchable)
  3. In case the url matches the url of your dispatchable class, the method execute is executed

Pseudo Code

@RestResource(urlMapping = '/teams/*')
global class RestDispatcher
    static Map<String, List<Dispatchable>> dispatchables;
        dispatchables = new Map <String, List<Dispatchable>>
            'POST' => new List<Dispatchable>(),
            'GET' => new List<Dispatchable>()

        // register your class here e.g. dispatchables.get('POST').add(new DispatchableClass());

    global interface Dispatchable
        String getURLMapping(); // e.g. /teams/{teamNumber}/members/{memberId}
        void execute(Map<String, String> parameters);

    global static void doGET()

    global static void doPOST()

    private static void execute(String httpMethod)
        RestRequest request = RestContext.request;
        for (Dispatchable d : dispatchables.get(httpMethod))
            if(match(d.getURLMapping, request.requestURI))
                d.execute(getParamters(request.requestURI, d.getURLMapping()));

    global static Map<String, String> getParamters(String requestURI, String dispatcherURI)
        // To-Do: implement an extraction method here.
        return new Map<String, String>();

    global static boolean match(String dispatchURI, String reuquestURI)
        if(true) // To-Do: add a matching algorith here
            return true;
        return false;



Source : Link , Question Author : David Staley , Answer Author : Ralph Callaway

Leave a Comment