Skip to main content

Creating the URL Map for REST

Creating the URL Map for REST

The XDATA UrlMap associates the REST call with the method that implements the service. It can either directly send the call to a method based on the contents of the URL or it can forward the call to another subclass of %CSP.RESTOpens in a new tab based on the URL. If the web application is handling a small number of related services, you can send the call directly to the method that implements it. However, if the web application is handling a large number of disparate services, you can define separate subclasses of %CSP.RESTOpens in a new tab, each of which handles a set of related services. Then the subclass of %CSP.RESTOpens in a new tab that handles the web application simply forwards the REST call to the appropriate subclass.

If the subclass of %CSP.RESTOpens in a new tab is sending the call directly to the methods, the URLMap contains a Routes definition that contains a series of Route elements. Each Route specifies a class method to be called for the specified URL and HTTP operation. Typically REST uses the GET, POST, PUT, or DELETE operations, but you can specify any HTTP operation. The URL can optionally include parameters that are specified as part of the REST URL and passed to the specified method as parameters.

If the subclass of %CSP.RESTOpens in a new tab is forwarding the calls to other subclasses of %CSP.RESTOpens in a new tab, the UrlMap contains a Routes definition that contains a series of Map elements. The Map statement forwards all calls with the specified prefix to its associated %CSP.RESTOpens in a new tab subclass, which will then implement the behavior. It can implement the behavior by sending the call directly to a method or by forwarding it to another subclass.

Caché compares the incoming REST URL with the Route URL property or the Map Prefix property. It starts at the first Route or Map element and continues to test each following element until it finds a match. Once it finds a match it either sends the incoming call to the call specified in the Route or forwards the URL to the class specified in the Map. In both cases, it ignores any elements in the Routes after the matching element; consequently, the order of the elements in the Routes is significant. If an incoming URL could match multiple elements of the Routes, Caché uses the first matching element and ignores any subsequent possible matches.

URLMap with Route Elements

Caché compares the incoming URL and the HTTP request method to each Route element in Routes. It calls the method specified in the first matching Route element. The Route element has three parts:

  • Url—specifies the format of the last part of the REST URL to call the REST service. The Url consists of text elements and parameters prefaced by : (colon).

  • Method—specifies the HTTP request method for the REST call: typically these are GET, POST, PUT, or DELETE, but any HTTP request method can be used. You should choose the request method that is appropriate for the function being performed by the service, but the %CSP.RESTOpens in a new tab class does not perform any special handling of the different method. You should specify the HTTP request method in all uppercase letters.

  • Call—specifies the class method to call to perform the REST service. By default, this class method is defined in the class that subclasses %CSP.RESTOpens in a new tab, but you can explicitly specify a class method in any Caché class.

For example, the DocServer sample defines the following Route:

XData UrlMap
{
<Routes>
  <Route Url="/echo" Method="POST" Call="Echo" Cors="false" />

This specifies that the REST call will end with /echo and use the POST method. It will call the Echo class method in the REST.DocServer class that defines the REST service. The Cors property is optional, has a value of "true" or "false" and controls CORS header processing. See “Configuring a REST Service to Use CORS” for details on using CORS.

The complete REST URL consists of the following pieces:

  • Server name and port of the Caché server. In this chapter, the server name and port http://localhost:57772/ is used in the examples.

  • Name of the web application as defined on the Web Application page (click System Administration > Security > Applications > Web Applications). For the DocServer sample, the name is /csp/samples/docserver, but you can specify any text that is allowed in a URL.

  • The remainder of the REST URL is defined by the Route Url element. If a segment of the Url element is preceded by a : (colon), it represents a parameter. A parameter will match any value in that URL segment. This value is passed to the method as a parameter.

For the preceding example, the complete REST call as shown by a TCP tracing utility is:

POST /csp/samples/docserver/echo HTTP/1.1
Host: localhost:57772

The following Route definition defines two parameters, namespace and class, in the URL:

<Route Url="/class/:namespace/:classname" Method="GET" Call="GetClass" />

A REST call URL starts with /csp/samples/docserver/class/ and the next two elements of the URL specify the two parameters. The GetClass method uses these parameters as the namespace and the class name that you are querying. For example, the REST call:

http://localhost:57772/csp/samples/docserver/class/samples/Cinema.Review

calls the GetClass method and specifies “samples” and “Cinema.Review” as the parameter values. The definition of the GetClass method starts with:

/// This method returns the class text for the named cache class
ClassMethod GetClass(
  pNamespace As %String,
  pClassname As %String) As %Status
{

You can define a different method for each HTTP request method for a single URL. For example, you could define the following:

<Route Url="/request" Method="GET" Call="GetRequest" />
<Route Url="/request" Method="POST" Call="PostRequest" />

With these routes, if the URL /csp/samples/docserver/request is called with an HTTP GET method, the GetRequest() method is invoked. If it is called with an HTTP POST method, the PostRequest() method is invoked. In the DocServer sample, both HTTP request methods are handled by a single Call method. The Route definitions in the sample is

<Route Url="/request" Method="GET" Call="Request" />
<Route Url="/request" Method="POST" Call="Request" />

In this case, the Request() method handles the call for either a GET or a POST operation. If this method needs to distinguish between a GET and a POST operation, it can do this by examining the CSP request object, which contains the text of the URL.

If you want to separate the code implementing the REST services from the %CSP.RESTOpens in a new tab dispatch code, you can define the methods implementing the REST services in another class and specify the class and method in the Call element.

Regular Expressions in the Route Map

You can use regular expressions within the route map. InterSystems suggests that you do so only if there is no other way to define the REST service to meet your needs. This section provides the details. (For information on regular expressions in ObjectScript, see “Regular Expressions” in Using ObjectScript.)

Internally, the :parameter-name syntax for defining parameters in the URL is implemented using regular expressions. Each segment specified as :parameter-name is converted to a regular expression that contains a repeating matching group, specifically to the ([^/]+) regular expression. This syntax matches any string (of non-zero length), as long as that string does not include the / (slash) character. So the GetClass() sample, which is Url="/class/:namespace/:classname", is equivalent to:

<Route Url="/class/([^/]+)/([^/]+)" Method="GET" Call="GetClass" />

where there are two matching groups that specify two parameters.

In most cases this format provides enough flexibility to specify the REST URL, but advanced users can use the regular expression format directly in the route definition. The URL must match the regular expression, and each matching group, which is specified by a pair of parentheses, defines a parameter to be passed to the method.

For example, consider the following route map:

<Routes>
<Route Url="/Move/:direction" Method="GET" Call="Move" />
<Route Url="/Move2/(east|west|north|south)" Method="GET" Call="Move" />
</Routes>

For the first route, the parameter can have any value. No matter what value the parameter has, the Move() method is called. For the second route, the parameter must be one of east west north or south; if you call the second route with a parameter value other than those, the Move() method is not called, and REST service returns a 404 error because the resource cannot be found.

This simple example is meant only to demonstrate the difference between the usual parameter syntax and a regular expression. In the case discussed here, there is no need for a regular expression because the Move() method can (and should) check the value of the parameter and respond appropriately. In the following cases, however, a regular expression is helpful:

  • If a parameter is optional. In this case, use the regular expression ([^/]*) instead of the :parameter-name syntax. For example:

    <Route Url="/Test3/([^/]*)" Method="GET" Call="Test"/>
    

    Of course, the method being called must also be able to handle having a null value for the parameter.

  • If the parameter is the last parameter and its value can include a slash. In this case, if the parameter is required, use the regular expression ((?s).+) instead of the :parameter-name syntax. For example:

    <Route Url="/Test4/((?s).+)" Method="GET" Call="Test"/>
    

    Or, if this parameter is optional, use the regular expression ((?s).*) instead of the :parameter-name syntax. For example:

    <Route Url="/Test5/((?s).*)" Method="GET" Call="Test"/>
    

URLMap with Map Elements

Caché compares the incoming URL to the prefix in each Map element in Routes. It forwards the incoming REST call to the %CSP.RESTOpens in a new tab subclass specified in the first matching Map element. That class processes the remainder of the URL, typically calling the method that implements the service. The Map element has two parts:

  • Prefix—specifies the segment of the URL to match. The incoming URL typically has other segments after the matching segment.

  • Forward—specifies another subclass of %CSP.RESTOpens in a new tab that will process the URL segments that follow the matching segment.

Consider the following URLMap that contains three Map elements.

XData UrlMap
{
  <Routes>
    <Map Prefix="/coffee/sales" Forward="MyLib.coffee.SalesREST"/>
    <Map Prefix="/coffee/repairs" Forward="MyLib.coffee.RepairsREST"/>
    <Map Prefix="/coffee" Forward="MyLib.coffee.MiscREST"/>
  </Routes>
}

This UrlMap forwards the REST call to one of three subclasses of %CSP.RESTOpens in a new tab: MyLib.coffee.SalesREST, MyLib.coffee.RepairsREST, or MyLib.coffee.MiscREST.

The complete REST URL to call one of these REST services consists of the following pieces:

  • Server name and port of the Caché server, such as http://localhost:57772/.

  • Name of the web application as defined on the Web Application page (click System Administration > Security > Applications > Web Applications). For example, the web application for these REST calls could be named /coffeeRESTSvr.

  • One of the prefixes define in the Map elements.

  • The remainder of the REST URL. This is the URL that will be processed by the %CSP.RESTOpens in a new tab subclass that receives the forwarded REST request.

For example, the following REST call:

http://localhost:57772/coffeeRESTSvr/coffee/sales/reports/id/875

matches the first map with the Prefix /coffee/sales and forwards the REST call to the MyLib.coffee.SalesREST class. That class will look for a match for the remainder of the URL, "/reports/id/875".

As another example, the following REST call:

http://localhost:57772/coffeeRESTSvr/coffee/inventory/machinetype/drip

matches the third map with the Prefix /coffee and forwards the REST call to the MyLib.coffee.MiscREST class. That class will look for a match for the remainder of the URL, "/inventory/machinetype/drip".

Note:

In this URLMap example, if the Map with the Prefix="/coffee" was the first map, all REST calls with /coffee would be forwarded to the MyLib.coffee.MiscREST class even if they matched one of the following Map elements. The order of the Map elements in Routes is significant.

FeedbackOpens in a new tab