Hi @Michael Davidovich - it's been a while! Here's a quick sample for how I'd do this:

Class Mike.Demo.REST Extends %CSP.REST
{

/// This method gets called prior to dispatch of the request. Put any common code here
/// that you want to be executed for EVERY request. If pContinue is set to 0, the
/// request will NOT be dispatched according to the UrlMap. In this case it's the
/// responsibility of the user to return a response.
ClassMethod OnPreDispatch(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean) As %Status
{
    #dim %request As %CSP.Request
    Set pContinue = 0
    Set version = %request.GetCgiEnv("HTTP_X_API_VERSION","unspecified; use X-API-VERSION header")
    Set class = $Case(+version,
        1:"Mike.Demo.v1",
        2:"Mike.Demo.v2",
        :"")
    If (class = "") {
        Set error = $$$ERROR($$$GeneralError,$$$FormatText("Invalid API version: %1",version))
        // Shoud be HTTP 400, but you probably want to report this differently/better.
        Do ..ReportHttpStatusCode(..#HTTP400BADREQUEST,error)
        Quit $$$OK
    }
    
    Quit $classmethod(class,"DispatchRequest",pUrl,pMethod,1)
}

}

Class Mike.Demo.v1 Extends %CSP.REST
{

Parameter VERSION = 1;

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/version" Method="GET" Call="GetVersion" />
</Routes>
}

ClassMethod GetVersion() As %Status
{
    Write {"version":(..#VERSION)}.%ToJSON()
    Quit $$$OK
}

}

Class Mike.Demo.v2 Extends Mike.Demo.v1
{

Parameter VERSION = 2;

XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/version" Method="GET" Call="GetVersion" />
</Routes>
}

}

You can use parameters on the return type. For example:

Class DC.Demo.SqlProcCollation
{

ClassMethod Test() As %String [ SqlProc ]
{
    return "Abe Lincoln"
}

ClassMethod Test2() As %String(COLLATION="SQLUPPER") [ SqlProc ]
{
    return "Abe Lincoln"
}

}

Given that:

select DC_Demo.SqlProcCollation_Test(),DC_Demo.SqlProcCollation_Test2()
where DC_Demo.SqlProcCollation_Test() = 'ABE LINCOLN'

Returns no results

select DC_Demo.SqlProcCollation_Test(),DC_Demo.SqlProcCollation_Test2()
where DC_Demo.SqlProcCollation_Test2() = 'ABE LINCOLN'

Returns 1 row

The general pattern that I would recommend is:

https://github.com/intersystems/isc-perf-ui is a simple example of how this all fits together - see especially https://github.com/intersystems/isc-perf-ui/blob/main/module.xml.

I just used this toolset to build a small but meaningful IRIS-based application in about a week. I didn't hand-code a single REST endpoint in ObjectScript, and I got my OpenAPI spec and all my Angular services and TypeScript interfaces for free*.

Of course, if you already have a significant hand-coded REST API, this doesn't help much. For one application my team manages we've added a Forward in our main REST dispatch class to one using isc.rest and gradually migrated endpoints over to use the standardized approach.

* ok, not totally free - there's the small price of writing better ObjectScript and e.g. having methods that return a registered JSON-enabled type rather than e.g. %DynamicArray and %DynamicObject.

@Evgeny Shvarov you're correct that no further configuration is needed - although if you want to commit direct from the IDE / Web UI you should set up the username/email for attribution.

At a technical level, see: https://github.com/intersystems/git-source-control/blob/main/cls/SourceC...

git-source-control doesn't reference module.xml directly; there's a method in IPM to get the package to which a given "InternalName" (e.g., Foo.Bar.CLS) belongs, so it calls that.