Routes - quandis/qbo3-Documentation GitHub Wiki

QBO supports a full REST API using custom routes. By default, QBO core method signatures are mapped to concrete classes via web handlers that implement an abstract HttpAsyncHandler, which implements Microsoft's native HttpTaskAsyncHandler. For example, Message functionality is invoked with the following relative URLs:

POST /Message/Message.ashx/Save?Subject=My First Message
GET /Message/Message.ashx/Summary?ID=1
POST /Message/Message.ashx/[email protected]&Subject=Hello World
POST /Message/Message.ashx/Delete?ID=1

The examples in this page include query string parameters for brevity. The core QboRouteHandler class supports form encoded parameters as well. Sensitive data should always be passed as part of the request body, and not the query string.

Custom routes can be used to support a standard RESTful API, like this:

PUT /message?Subject=My First Message
GET /message/1
POST /message/[email protected]&Subject=Hello World
DELETE /message/1

Route Configuration

Routes can be defined from Design > Configuration > Routes.

Route Properties

Property Required Description
Name yes Name of the route. Routes are loaded in alphabetic order by Name.
Url yes Url to match route to. Parameters may be specified in the route name with curly braces.
Defaults no Default parameters to add to any requests.
HttpMethods no Http methods supported by the route: get|post|delete|patch|put (may be comma delimited)
MethodSignature no A method signature to invoke; defaults to {class}/{operation} if not defined.
Handler no Injects an alternate IQboHttpHandler, to hook custom functionality into a route.
ExceptionHandler no Injects an alternate IExceptionHandler to handle routes for a route.

Route Parameters

The QboRouteHandler requires two parameters:

Parameter Description
class Name of the class to be invoked. E.g. Attachment, Message, Organization, etc.
operation Name of the operation (method, service, or statement) to be invoked.

These parameters may be define in the Url, as a DefaultParameter, or as part of the MethodSignature. All other route parameters will be passed as parameters to the method signature being invoked.

Route parameters may have the following type constraints applied:

Constraint Example Description
int {userId:int} Will only bind to the route if the userId parameter is an integer. (Regex \d+)
date {payment:date} Will only bind to the route if the payment parameter is an date formatted as YYYY-MM-DD.
isodate {created:isodate} Will only bind to the route if the created parameter is an date formatted as YYYY-MM-DDTHH:MM:SE.

Standard Routes

Below are the standard routes that are part of the core QBO configuration:

<?xml version="1.0"?>
<Routes>
  <CustomRoutes>
    <CustomRoute Name="Default-1-Queue" Url="api/{class}/queue/{operation}"/>
    <CustomRoute Name="Default-2-Parent" Url="api/{Object}/{ObjectID:int}/{class}/{operation}"/>
    <CustomRoute Name="Default-3-Singleton" Url="api/{class}/{operation}/{id:int}"/>
    <CustomRoute Name="Default-4-Default" Url="api/{class}/{id:int}"/>
    <CustomRoute Name="Default-5-Any" Url="api/{class}/{operation}"/>
  </CustomRoutes>
</Routes>

Route Ordering

Route ordering is important; the CustomRouteConfiguration will order routes alphabetically. If you wish to add routes that are applied ahead of QBO's default routes, ensure your route name precedes the word 'Default' (e.g 'Custom-*'). If you wish your custom routes to be applied after QBO's default routes, ensure your route name succeed the word 'Default' (e.g. 'Post-*').

Queue routes

api/{class}/queue/{operation}

This will queue a method signature {class}/{operation} to a queue. Optional parameters include:

  • Queue: name of the queue to use; defaults to DefaultQueue

Parent routes

api/{Object}/{ObjectID:int}/{class}/{operation}

Parent routes are typically used to invoke a Search or List operation for a generic object against a parent. Examples include:

api/Organization/12345/Attachment/Search
api/Loan/23456/Message/Search
api/Decision/34567/DecisionStep/Search

This pattern simply translates the method signature to {class}/{operation}?Object={Object}&ObjectID={ObjectID}.

QBO uses a pattern of Object/ObjectID(aka Object/ID) to identify a 'soft' parent key. For example, our Message class can be a child of any QBO class, such as Organization, Contact, Property, Loan, Policy, etc.

Singleton operations

api/{class}/{operation}/{id}?{parameters}

This will invoke a method signature equivalent to {class}/{operation}?ID={id}&{parameters}

Default routing

api/{class}/{id:int}?{parameters}

Depending on the HTTP Method, this will:

  • GET: invoke {class}/Summary?ID={id}&{parameters}
  • DELETE: invoke {class}/Delete?ID={id}&{parameters}
  • PATCH: invoke {class}/Save?ID={id}&{parameters}
  • POST: invoke {class}/Save?ID={id}&{parameters}
  • PUT: invoke {class}/Save?ID={id}&{parameters}

Any

api/{class}/{operation}

This is a hook to invoke any QBO operation via a RESTful syntax where all parameters are part of the query string or form post.

Aliasing

Aliases of QBO classes can be implement with custom routes, and include standard parameters. For example, the Process class might be used to manage Projects, using a custom route:

<CustomRoute Name="Projects" Url="projects/{operation}" MethodSignature="Process/{operation}"/>

Posting sensitive data

Most examples we provide demonstrate passing parameters via the query string. QBO supports parameters via GET (on the query string) or POST (as form URL encoded, XML, or JSON).

Contact/Save?FirstName=John&LastName=Doe&USSSN=123-45-6789

is an easy-to-read example, but bad practice, since sensitive data is being included in the URL, and will thus appear in logs and other inappropriate places. Instead:

POST https://qbo.acmefinancial.com/Contact/Save HTTP/1.1
Accept: application/javascript
Content-type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: ...

FirstName=John&LastName=Doe&USSSN=123-45-6789

This will ensure that the name and USSSN are encrypted in transit, and not be subject to logging plain text.

Posting XML data

POST https://qbo.acmefinancial.com/Contact/Save HTTP/1.1
Accept: application/javascript
Content-type: text/xml; charset=UTF-8
Cookie: ...
<ContactCollection>
  <ContactItem>
    <FirstName>John</FirstName>
    <LastName>Doe</LastName>
    <USSSN>123-45-6789</USSSN>
  </ContactItem>
</ContactCollection>

Pluralizing a QBO object

The decision to make RESTful URLs from nouns that are singular or plural is a bit of a religious war. The W3C REST protocol does not dictate best practice either way.

QBO was created in part with code generators, for which abstracting the correct English plural of a given class was annoying at best. Thus, we chose to make our SQL tables, their identity and label columns, matching class names and web endpoint singular.

If you prefer plural, you can easily use custom routes to enable them. For example, if you wish to access the Attachment module via a documents endpoint:

<CustomRoute Name="Documents" Url="documents/{operation}" MethodSignature="Attachment/{operation}"/>

Deviations from strict RESTful conventions

Post

POST is supposed to create a new record. QBO deviated from this; if you POST with a valid identifier, this acts as a PUT (database UPDATE statement).

Patch and Post

The standard POST operation (/{class}/{id}) will invoke QBO's Save method, which is equivalent of a RESTful PATCH instead of POST. This means that if a client POST omits a property from the target class, the property will remain unchanged, instead of NULLed. If the client intends to NULL a property, they should POST the property with no value. For example:

// This will update a Contact's FirstName and LastName, but leave the MiddleName alone
/contact/1?FirstName=Jane&LastName=Doe

// This will update a Contact's FirstName, LastName, and NULL out the MiddleName
/contact/1?FirstName=Jane&MiddleName=&LastName=Doe

Enable PUT and DELETE on IIS

IIS default settings do not provide for PUT and DELETE operations.

The following items must be set to enable:

  • Website Application Pool Managed Pipeline Mode must be set to Integrated
  • HTTP Verbs must be supported in IIS

Set Application Pool Pipeline Mode

  • Go to IIS Manager > Application Pools
  • Locate Application Pool for target website > Edit (double-click) > Managed pipeline mode: Integrated

HTTP Verb Update

The following snippet should be added to web.config to enable all verbs, and to ensure that WebDAV does not intercept and reject PUT and DELETE. If the default WebDAV is configured, WebDAV will intercept PUT and DELETE verbs, returning 405 errors (method not allowed).

<system.webServer>
    <handlers>
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <remove name="WebDAV" />
      <add name="dotless" path="*.less" verb="GET" type="dotless.Core.LessCssHttpHandler,dotless.AspNet" resourceType="File" preCondition="" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0" responseBufferLimit="0" />
    </handlers>
    <modules>
        <remove name="WebDAVModule" />
    </modules>
</system.webServer>

If you prefer a GUI to add verbs, go to IIS Manager > Handler Mappings. Find ExtensionlessUrlHandler-Integrated-4.0, double click it. Click Request Restrictions... button and on Verbs tab, add both DELETE and PUT.

IIS Verbs

⚠️ **GitHub.com Fallback** ⚠️