Crafting HTTP Requests for the AppFxWebService.asmx
Infinity's Web API is fairly well documented, especially if you're going to be referencing the web service as a web reference in a .NET (Visual Studio), PowerShell, or Java project. This content attempts to explain how HTTP requests to AppFxWebService.asmx can be manually crafted for use and/or testing with tools like Fiddler.
Choosing an endpoint
To begin using the API, you must first choose what functionality you want to use. This endpoint will determine what data you will send, and what you can expect to receive in response. This document does not describe each endpoint in detail, but rather how to find the endpoints and explore them.
The Endpoint Reference Page
The Endpoint Reference page is a very useful tool for Infinity systems (such as Blackbaud CRM or ResearchPoint) that will allow you to see functionality exposed to you via the Web API. There are a couple ways to access the Endpoint Reference page, but not all of them may be applicable depending on how you access your Infinity product. If, when accessing your Infinity product you come to the splash or "Candy Store" page with many choices of how to continue, including: Web Shell, Web dashboard, Mobilize, Utilities,Endpoints, and Browser, then finding your endpoints is simple. All you have to do is click on the Endpoints link and it will take you to the Endpoint Reference page.
If you do not have the above landing page available to you, you can still access it. From inside your Infinity application, copy the entire URL up to `/webui/...`
For example, if your starting page URL after logging in is http://localhost/bbappfx/webui/webshellpage.aspx?databasename=BBInfinity you should copy http://localhost/bbappfx.
Once you have this base URL, add /endpointhelp.aspx?databasename=BBInfinity to the end of it. The resulting URL, http://localhost/bbappfx/endpointhelp.aspx?databasename=BBInfinity, will take you to the Endpoint Reference page.
Once on the page, there are many things to explore, but if you're reading this document the one you probably care about is Blackbaud AppFx Web Service.
The AppFxWebService documentation lists the available operations. Your integration software can use these operations to get things done in Blackbaud CRM or ResearchPoint..
AppFxWebService.asmx Endpoint Description
Blackbaud’s Infinity Web Services APIs can be used by custom third party software to interact with individual features via HTTP. Every application feature is accessible via standard web services accessible from any programming tool that utilizes XML, HTTP, and SOAP.This page describes the multitudes of operations that are supported by the Web API. It's up to you to scan the list to find an operation that might suite your needs, but for the rest of the document we will look at SimpleDataListLoad.
The table below provides an abbreviated guide to some of the most essential operations for performing CRUD type activities (Create, Read, Update, and Delete), along with other operations like record searches and listing records and look-up code table values. These operations typically require the ID of the feature. For more information on locating and securing Infinity features, see Add Features to Infinity System Role.
Operation Type | Operation | Description |
---|---|---|
Create | DataFormSave | Saves (insert or update) the data for a record defined by the supplied (Data) Form ID. Call DataFormSave to save an update provided by an Edit Data Form or to save an insert by an Add Data Form. |
Create | CodeTableEntryAdd | Creates a new CodeTable entry item. |
Read | DataFormLoad | Gets the data (for edit or view) for a record defined by the supplied Form ID.Call DataFormLoad to retrieve the data pulled by the load implementation of an Edit Data Form or View Data Form. |
Read | CodeTableEntryGetData | Gets the data for an individual code table entry item |
Update | DataFormSave | Saves (insert or update) the data for a record defined by the supplied Form ID. Call DataFormSave to save an update provided by an Edit Data Form or to save an insert by an Add Data Form. |
Update | CodeTableEntryUpdate | Updates a CodeTable entry description and active status |
Update | RecordOperationPerform | Performs the operation on a record as defined by the supplied Record Operation name or ID |
Delete | RecordOperationPerform | Performs the operation on a record as defined by the supplied Record Operation name or ID |
Delete | CodeTableEntryDelete | Deletes a CodeTable entry item |
List | DataListLoad | Loads the data for a datalist given the ID or Name and any parameters. Use DataListLoadMore to load a rows from a previous call to DataListLoad which had more TotalAvailableRows than the TotalRequestRows in the reply. Used to support paging of data in large result sets. |
List | SimpleDataListLoad | Gets the data for a simpledatalist given the ID or Name and any parameters |
List | CodeTableEntryGetList | Returns the list of table entries for the given code table. |
Search | SearchListLoad | Gets the data for a search list given the search list ID or Name and any filters |
Example: Essential AppFxWebService.asmx CRUD Operations
When you click on an operation description, you will be taken to a page with lots of XML. This is a helpful description of the SOAP requests and responses that the API consumes and produces. Specifications for SOAP 1.1 and SOAP 1.2 are shown for each endpoint. The first XML document shown is the SOAP request, which you will need to craft. The second XML document shown is the SOAP response, which you will have to handle.
Although we all wish that this operation description page was the end of the story, there is a bit more to be done before a request can be successfully sent.
Headers
Most of the headers that you'll need are described in the Endpoint description page above the SOAP request example. For example:
POST /bbappfx.dev.firebird/AppFxWebService.asmx HTTP/1.1
Host: localhost
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "Blackbaud.AppFx.WebService.API.1/SimpleDataListLoad"
are all but one of the headers you will need to make a successful SOAP 1.1 POST request. The one that is missing is the `Authorization` header.
Authentication
Since you must be logged in to use the application, the API is only available to authenticated users, and that includes your application. Infinity supports a few types of authentication, including Basic and NTLM. For more information on authorization, see Authentication and Authorization.
Basic Authentication
Basic authentication is simple.
- Create a string username:password from your Infinity login credentials or create a username PAT for a proxy user.
- Base64 encode that string.
Take that string and add the following header
Authorization: Basic YOURBASE64ENCODEDAUTHENTICATIONSTRING
And that's it! Your request will be authenticated now.
NTLM Authenticaion
Describing how to manually compute an NTLM signature and use it in this context is currently beyond the scope of this document. It is an option, though, if you cannot use Basic authentication.
Most of the SOAP request body is perfectly described by the endpoint description page. You can copy-paste and modify the sample request and be 90% of the way to a perfectly functioning request. However, there are two bits of information that you will need to add to the request to make it work correctly.
ClientAppInfo
One thing that the sample request does not describe is an element that must be included called `ClientAppInfo`. Its format is as follows:
<ClientAppInfo
REDatabaseToUse="YOUR DATABASE IDENTIFIER/KEY"
ClientAppName="THE NAME OF YOUR REQUESTING APPLICATION"
TimeOutSeconds="THE NUMBER OF SECONDS BEFORE A REQUEST TIMES OUT"
/>
REDatabaseToUse
Your database identifier/key will vary. For this example, I am using 'BBInfinity'. Your database key will most likely vary. Read below.
This is the identifier of the database your Infinity product uses. This is also known as the 'database key'. You can find this value in the URL when you are using the product. For example, on the landing page of Blackbaud CRM/Research Point the URL is
http://localhost/.../webshellpage.aspx?databasename=BBInfinity
and we can see that the database identifier is `BBInfinity`.
ClientAppName
This is a name that you should come up with to identify your application to the API. It should be unique and specific to your application. The Infinity application can use this application name for auditing purposes when additions, edits, or deletes occur to the data within the database tables.
TimeOutSeconds
The number of seconds before the request times out. I will use 120 seconds for this setting.
There are other attributes within the ClientAppInfo element. A brief description is provided below:
RunAsUserID
Optional. This attribute is not relevant for API Development and should be omitted. Within the Infinity user interface, this attribute is necessary to support system administrators who which to verify security for specific users.
SessionKey
Optional. The value for this attribute can be obtained via a prior call to the SessionStart operation on the AppFxWebService.asmx. SessionStart returns a session key to be used to main client state between calls to the service. Using this setting provides a slight performance benefit as some internal data is cached for the user during the session.
SOAP gotchas
Because Infinity's web service uses SOAP, it is important to be aware of some of the intricacies of SOAP that might not be immediately obvious and are not present in the sample request. It may be beneficial to have the SOAP standard definition on hand.
Strict typing of ambiguous data
In SOAP, data values that have an ambiguous type must have their type declared in the request so they can be properly serialized. With Infinity applications, this mostly only applies to the `Values` elements in a request's `Parameters`. The Rules for Encoding Types in XML can help to describe what you must do, and a list of included datatypes in XML is also useful when typing request parameters.
A complete SimpleDataListLoad SOAP 1.2 request
Non-functional, with parameters
Here is an example of a complete SimpleDataListLoad, with parameters. Sending this request, while valid, will probably not return meaningful results.
Headers:
Host: localhost
Content-Type: application/soap+xml; charset=utf-8
Content-Length: LENGTH
Authorization: Basic 11111111111111111111
Request Body:
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<SimpleDataListLoadRequest xmlns="Blackbaud.AppFx.WebService.API.1">
<ClientAppInfo REDatabaseToUse="BBInfinity" ClientAppName="Test App" TimeOutSeconds="100" RunAsUserID="00000000-0000-0000-0000-000000000000" xmlns="Blackbaud.AppFx.WebService.API.1" />
<DataListID>1d5fc077-0049-483f-a65c-0c17d57476a4</DataListID>
<DataListName>Scheduled Programs By Date Simple List</DataListName>
<Parameters>
<Values xmlns="bb_appfx_dataforms">
<fv ID="DATE">
<Value xsi:type="xsd:string">08/21/2013</Value>
<ValueTranslation>08/21/2013</ValueTranslation>
</fv>
<fv ID="EVENTDATE">
<Value xsi:type="xsd:string">08/22/2013</Value>
<ValueTranslation>08/22/2013</ValueTranslation>
</fv>
<fv ID="SALESMETHODTYPECODE">
<Value xsi:type="xsd:int">0</Value>
<ValueTranslation>0</ValueTranslation>
</fv>
</Values>
</Parameters>
<SecurityContext>
<SecurityFeatureID>1d5fc077-0049-483f-a65c-0c17d57476a4</SecurityFeatureID>
<SecurityFeatureType>SimpleDataList</SecurityFeatureType>
<RecordContext>
<RecordID/>
<RecordType/>
</RecordContext>
<AttributeContext>
<AttributeCategoryID/>
</AttributeContext>
</SecurityContext>
</SimpleDataListLoadRequest>
</soap12:Body>
</soap12:Envelope>
Functional, without parameters
This request has no parameters, but once adjusted to use values specific to your Infinity product, will return meaningful results in a response for you to examine.
Headers:
Host: localhost
Content-Type: application/soap+xml; charset=utf-8
Content-Length: LENGTH
Authorization: Basic 11111111111111111111
Request Body:
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<SimpleDataListLoadRequest xmlns="Blackbaud.AppFx.WebService.API.1">
<ClientAppInfo REDatabaseToUse="BBInfinity" ClientAppName="Test App" TimeOutSeconds="100" RunAsUserID="00000000-0000-0000-0000-000000000000" xmlns="Blackbaud.AppFx.WebService.API.1" />
<DataListID>ea2c8565-85cb-433c-94f8-229e079f0445</DataListID>
<DataListName>Record Types</DataListName>
<Parameters/>
<SecurityContext>
<SecurityFeatureID>ea2c8565-85cb-433c-94f8-229e079f0445</SecurityFeatureID>
<SecurityFeatureType>SimpleDataList</SecurityFeatureType>
<RecordContext>
<RecordID/>
<RecordType/>
</RecordContext>
<AttributeContext>
<AttributeCategoryID/>
</AttributeContext>
</SecurityContext>
</SimpleDataListLoadRequest>
</soap12:Body>
</soap12:Envelope>
Tip: Those new to Infinity API development or those who want more details on the underlying concepts need to check out our step by step tutorial: Using Fiddler to Compose HTTP Requests