Question
· Oct 30, 2019

API RESTful Version

Hello,

We need to create a versioning of an existing API, so we going to set a default version (so far) for current connections to version 1

My first attempt is:

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
    <Route Url="(?i)/check" Method="GET" Call="CheckApi"/>
    <Route Url="(?i)/getcustomer" Method="POST" Call="GetCustomerDefault"/>
    <Route Url="(?i)/revoke" Method="DELETE" Call="RevokeDefault"/>
    <Route Url="(?i)/:version/getcustomer" Method="POST" Call="GetCustomer"/>
    <Route Url="(?i)/:version/revoke" Method="DELETE" Call="Revoke"/>
</Routes>
}
 
Parameter DEFAULTVERSION = 1;
 
Parameter CURRENTVERSION = 2;
/// Get customer info (API version default)
ClassMethod GetCustomerDefault() As %Status
{
    quit ..GetCustomer(..#DEFAULTVERSION)
}
 
ClassMethod GetCustomer(pVersion As %IntegerAs %Status
{
    // This is the code for all version. Get the Id and pass into the message
    ........
    quit $$$OK
}
 
 

 

Also, I have a parameter called DEFAULTVERSION with value 1

By this way, the newer calls will have the version number and response according the version of API

The URL will be:

apiserver.com/api/2/getCustomer

I'm checking if the version is less than a CURRENTVERSION, the call is fine

According to a new especification, the URL will be "api/v2/getCustomer", before it was an integer, and now will be a string.

 

How can I check if this parameter is well formed (v and number), then I can evaluate if the number is an valid API version?

 

We can change our versioning, so any suggest will be welcome

Discussion (5)3
Log in or sign up to continue

Good approach, thanks for your answer.

The methods will be exactly the same as before. The changes in version is a slight change in BP, so I need which version is calling. If I user the version number as parameter, I can add into a message and calls to BP with the version and not replay all methods for each version.

I'll be in mind for future versions.

Thanks

Approach 1

I would be tempted to have your Dispatch class have a forwarding rule for the API version eg v1 or v2 and this will help ensure a clear hierarchical separation both in the URL and in the class definitions between versions. You might also be interested in the %request.URL property for checking relative paths. An example based on your route map might look like 

<Map Prefix="/v1/customer" Forward="MyApp.APIVersion1.Customer" />
<Map Prefix="/v2/customer" Forward="MyApp.
APIVersion2.Customer" />

And your class MyApp.APIVersion1.Customer might look like

<Routes>
        <Route Url="/getcustomer" Method="Post" Call="GetCustomer" />
</Routes>

Personally, I like the classmethod names to reflect the HTTP Method so if I see a GetCustomer method I know that's a HTTP Get method but this is based on personal preference and convention rather than a rule.

Approach 2

The alternative approach is to have everything in the same class but over time this may cause your classes to be rather bloated and unwieldy

<Map Prefix="/v1/customer" Method="Post"  Call="GetCustomerV1" />
<Map Prefix="/v2/customer" Method="Post"  Call="GetCustomerV2" />

Other Thoughts

I do not know if there's a specific function that can be called prior the classmethod in the route map that can validate or invalidate routes. Perhaps the OnPreHTTP method could be used? I noted that some of your methods had the word "default" in them. You can define default route as "/" in your route map.