API How To's

From Pengower
Jump to: navigation, search

Learn how to use different APIs for your application.

How to set and create APIs

The builder developed a better process in creating APIs which makes it more intuitive.

Setup Steps:

1. Add an API user type by going to the User Types tab in the builder. Tick on the API box.

API.png

2. Using the same user type, add an API user. This would be the same credentials that you will use to connect to the API.


Add action for API use:

1. On the Action, tick on the "API Call" box and save.

Api2.png


How to use Web Services and API calls

Introduction

The Pengower web application development platform now supports a web services based API (Application Programming Interface) facility. This allows Pengower application developers to expose a set of script based actions that can be called programmatically from other software applications running anywhere on the Internet. This facility will allow full integration of Pengower applications with other applications – though some effort will be required to construct the appropriate middle-ware and the appropriate external ‘interface’ from the Pengower application. It will also facilitate the scheduling of application actions through a simple command line executable program. A simple program has been written to make use of the API facility that can be configured to execute any exposed action on any application through the use of a simple XML configuration file. This program can then be added into the MS Windows Task Scheduler and so call the required action at the required intervals.

Creating and Exposing an API for a Pengower Application

An API for a Pengower Application will comprise a number of script based actions. The API facility has been designed to allow secure, authenticated access to a selected set of actions. To create an API the following steps are required;

  1. Create a View in the application called ‘API’ (please use upper case). The view should be marked as secure and should be of ‘Toolbar Only’ layout. The name of the view is critical!
  2. Create a user type that has access to the API view (e.g. ‘webAPI’). It should not be connected to an application type – i.e. the user will not be identified with a specific item within the application.
  3. Create at least one instance of the User Type created in step 2. This Username and Password will be used to authenticate access to the API.
  4. Create the Script based actions required in the API. This will be a function of the business processes being supported.
  5. Build a toolbar containing the required actions and link it to the view created in step 1

Once the application meta-cache has been cleared the API will be ready for use by external applications.

Issues when writing script actions for inclusion in an API

  • The API cannot execute standard actions. It can only execute script based actions.
  • It is expected that both script output variables (‘Output’ and ‘Report’) will be specified at the completion of the script.
  • The API facility will translate (serialize) the script Output variable into XML for transportation across the Internet to the calling application/system. As such the following types of variables are supported as script Output;
    • String – any string variable can be returned
    • Number – any number variable can be returned
    • Date and Time
    • Timespan
    • Array – an array of variables can be returned. When the constituent variables are simple in nature (string, number etc.) then a simple csv list will be constructed. In the case of an array of objects (Accounts, Staff Members etc.) then an XML representation of a list of these items will be produced. See below for details of list format. Group – The script supports an output of the form [ Output = “GROUP All People” ]. In this case an XML representation of the list of items will be returned. See below for details of list format.
    • SQL – The script supports an output of the form [ Output = “SQL Person Where Surname ~ Do%” ]. As with the Group output an XML representation of the list of items returned by the SQL statement will be returned. See below for details of list format.
    • Item – In the case where an item is returned (an Account object or a Person etc.) then an XML representation of the item’s elements will be produced. See below for an example of how this XML is configured. Currently the API model does NOT support Section exclusion – thus all Sections of an item will be returned. It is assumed that any issues of data visibility can be managed in the middle-ware. If this is not the case then a custom string output could be constructed including only the appropriate item data.
  • The API operates in a stateless fashion – thus it is not possible to link one action call to a previous action call and it is not possible to use the script Cache mechanism, i.e. do not try to put items in the script cache or to access the script cache in any API actions.
  • All other aspects of the script language are available – including (and importantly) object locking.


Complex output styles

Group, SQL and item array output from a script will be represented by an XML summary of the items included. In this way such outputs closely mimic the standard listings produced in a Pengower application.

An item (a Person, a Customer Account) is also represented / serialized as XML.

All elements types are supported, including Groups, Relationships and Attachments. Elements of type ‘Action Button’ and ‘Information’ are not exported. Attachments (files) are exported in one of 2 ways depending on the nature of the content of the file. In the case of text based files – html, XML, csv and basic text – the content of the file is output as XML-encoded text (i.e. ‘<’ and ‘>’ are translated to > and < etc.) to ensure that the underlying XML is not invalidated. In fact all string based output is XML-encoded this way to ensure the integrity of the XML (see below for details). The content of binary files such as images or pdf’s is encoded to a hex-byte string that can safely be incorporated into XML for transport. Note, this form of transport will NOT be suitable for large files!

Group elements are serialized in the same way as Group output statement and produce XML of the form <rows><row><field…/></row>…</rows>.

Relationship elements list the relationship display string for each related item in a list of XML that takes the form


XML Encoding

All text elements that are output from the script are encoded to ensure that they do not disrupt the integrity of the surrounding XML (which could be possible!). The following conversions take place (the order of the conversions is important!);

"&" replaced by "&amp;"
"<" replaced by "&lt;" 
">" replaced by "&am;pgt"
""" replaced by "&quot"
"'"  replaced by  "&apos"

With these replacements having been made on the script text output it is important that any receiving application reverses the replacements (including reversal of order) to ensure the original text is recovered.

Writing an Application To Utilise An Exposed API

The Pengower Web Services API really only exposes 2 methods;

Login : This method will return an authentication token that will allow authenticated access to API actions. It takes the following parameters;

Client – the name of the client to whom the application belongs (as in Builder) Application Name – the name of the application Username – the name of a user that has valid access to the API view Password – the password for the username provided


The authentication token return has a limited life span and thus it is advisable to obtain a fresh token prior to each action call. This will not prove problematic in terms of licencing as the Platform does not count API users against the application licence count and neither does it monitor which API users are logged in or not – this is a product of the stateless nature of the API (each call is treated as a fresh access to the application with no inherent history associated with it).

In the event that the Login action fails, the return string will include the word “ERROR”.

RunAction : This method executes an actual action as exposed in the application API. It takes the following parameters;

Token : the authentication token provided by the login action ActionName : the name of the action being called Parameters : an XML representation of any input parameters that are to be passed in from the calling application. These will be translated into variables that will be accessible in the called script. See below for more details.


As the API in question is linked to a specific application which exists within a specific Pengower Implementation it should be evident that the API facility is bound to an Implementation and as such must be accessed through the correct URL. The view launch URL for the API view can be used to obtain the necessary URL. See below in the action sequencing section for an example of this.

WSDL

Most clients that make calls into Web Services obtain an understanding of the methods exposed through the associated WSDL (Web Service Description Language) file (including the MS .Net Platform). An example of a WSDL file for the Pengower API can be found at;

http://www.pengower.com/Applications/penAPI.asmx?WSDL

Note any client built around this WSDL file must have its URL altered to reflect the particular Pengower implementation being accessed.


Parameters

Key to the success of the API facility is the ability to pass data/information into API actions. The ‘parameters’ element enables this. The parameters take the form of XML. The following variable types are supported;

  • String
  • Number
  • Date / Time
  • Timespan
  • File
  • Array


Note all string variables should be encoded for XML to ensure they do not disrupt the integrity of the main XML request. Note, all variables created from input parameters have been XML-decoded, i.e. the reverse replacements have taken place to reproduce the original text.

Input File Variables

In the case of ‘file’ type parameters 2 further attributes are required on the ‘param’ XML node;

Filename – the name of the file Filetype – the extension associated with the file (.doc, .txt etc)

Input Parameters Example


In the case of text based files (.txt, .csv etc.) the content of the file should be properly XML encoded string data. In the case of binary files (images, pdfs etc.) the content should be a hex-byte string of the file content.

Input Array Variables

In the case of Array type input variables the content of the array should be encapsulated as XML

Date/Time Formats Supported

Any input date time information must be provided in one of the supported formats these are;

  • hh:mm
  • hh:mm:ss
  • dd/MM/yyyy
  • dd/MM/yyyy hh:mm
  • dd/MM/yyyy hh:mm:ss

Returned Values

The return from the action call is provided in the form of XML.


This can be read by a standard XML parser and thus the relevant node values extracted.

In the event that the action could not be executed correctly the output will include the word “ERROR”.

SSL

Calls can be made to the API over SSL to ensure encryption and security of data. Simply replace the ‘http:’ part of the URL for the API call to ‘https:’. Please note the client application must be capable of correctly authenticating and accepting the server side SSL Certificate used.


Scheduling Actions

One immediate use to which the API facility can be put is to allow the scheduled running of actions within a given application. This has to date not been support, but through appropriate use of the API capability and MS Windows ‘Scheduled Tasks’ it is possible to enable the scheduled execution of application actions.

To this end a small command line utility program has been written, which when coupled with and XML based configuration file will allow the execution of any exposed application API action (on any Pengower implementation),


The first line is a standard definition of an XML file and must be included. The second line describes the action to be run, including implementation details;

  • Name = name of action to be run
  • Url = the view launch url of the API view being accessed
  • Username = the name of API user
  • Password = password for the API user
  • Logfile = This optional parameters indicates a file where a report on the execution of the API call will be recorded. If this parameter is omitted then the report will be written into the Application section of the Windows Event Viewer


The range of parameter types support are;

  • String
  • Number
  • Date / Time / Datetime
  • Timespan
  • Array
  • File

The format of the ‘param’ entry in the file closely matches the ‘param’ entry in a RunAction API call (not surprisingly!). Each parameter will be mapped to a script variable that will be accessible in the action script. In the case of a file the value entered in the configuration file should be the path to the actual file to be mapped into the script. The formats of date supported are the same as those listed above. Note, it is perfectly acceptable to call an action that requires no parameters – simply exclude the ‘param’ entries from the file.

The name of the command line utility is ‘PengowerAPIClient.exe’.

Note, if the full name of the configuration file, including path, includes spaces then the full entry should be enclosed in speech marks as shown above. Note, putting the path to the configuration file in speech marks will prove problematic if the path to the executable also includes spaces – so you must ensure that one or both of the files has a full path that does not include spaces.

The Windows ‘Scheduled Tasks’ utility is found in the Control Panel. The steps required to set up a scheduled task are;

  • Launch ‘Scheduled Tasks’ list via double click on the icon.
  • Select ‘Add Scheduled Task’ to launch the “Scheduled Task Wizard”.
  • Select “Next>”
  • Select the ‘Browse’ option and navigate to the location of the pengowerAPIClient.exe file and select this file
  • Select a frequency option that closely matches your requirements (note this can be refined later)
  • Ensure that the name for the task (given in the text box) is unique and meaningful
  • Select ‘Next>’
  • Select an appropriate time for the task to run (please ensure you avoid the recycle time for the implementation you are accessing – view IIS on the Pengower Web Server to find this time (generally early hours of the morning))
  • Select ‘Next>’
  • Confirm the details of the User under whose authority the task should be run.
  • Select ‘Next>’
  • Check the ‘Open advanced properties…’ check box on the next dialog and then select ‘Finish’
  • In the launched dialog you should now modify the text in the ‘Run:’ box so that it includes the full name of the configuration file after the name of the executable.
  • At this time you can use the ’Schedule’ tab to configure a more complex schedule (or range of schedules) if required.

The process of setting up a scheduled task is now complete. Note, the scheduled task can be on any machine that has access to the Internet – and thus the API, so long as it will be on at the required times. The load incurred due to the running of these tasks should be minimal – though clearly the actual load on the production servers will be dependent on the action called.

Use the API from non C# languages

Using the API without C# When you use the API from a language other than C# (and probably VB.Net) you need to create the SOAP package yourself. This can be quite a challenge as C# hides a lot of underlying complexity from you.


Creating the right SOAP XML This is based on work I have done in Javascript to support Ajax, but I have not explicitly tested the examples shown here! Please edit this with your findings.


Example 1 (will throw an exception)

This is what the documentation makes you think you need to send (Note: The documentation is actually correct if you read it closely, it's just the human mind that tends to jump to conclusions!)

POST /appsnewo/penapi.asmx HTTP/1.1
Host: www.pengower2.com
Content-Type: text/XML; charset=utf-8
Content-Length: length
SOAPAction: "http://www.pengower.com/penapi/Login"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.XMLsoap.org/soap/envelope/">
  <soap:Body>
    <RunAction xmlns="http://www.pengower.com/penapi">
      <token>string</token>
      <actionName>APIGetSettingsForOrganisation</actionName>
      <parameters>
            <param title="OrgID" type="string">3</param>
            <param title="Type" type="string">Football</param>
      </parameters>
    </RunAction>
  </soap:Body>
</soap:Envelope>

However, that will fail with an exception.


Example 2 – better but still not there

You need to essentially double up on the parameters tag - it needs to be there twice.

POST /appsnewo/penapi.asmx HTTP/1.1
Host: www.pengower2.com
Content-Type: text/XML; charset=utf-8
Content-Length: length
SOAPAction: "http://www.pengower.com/penapi/Login"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.XMLsoap.org/soap/envelope/">
  <soap:Body>
    <RunAction xmlns="http://www.pengower.com/penapi">
      <token>string</token>
      <actionName>APIGetSettingsForOrganisation</actionName>
      <parameters>
         <parameters>
            <param title="OrgID" type="string">3</param>
            <param title="Type" type="string">Football</param>
         </parameters>
      </parameters>
    </RunAction>
  </soap:Body>
</soap:Envelope>


Example 3 – should work

However, the stuff between parameters is treated as a string, so you need to encode it, until you end up with this:

POST /appsnewo/penapi.asmx HTTP/1.1
Host: www.pengower2.com
Content-Type: text/XML; charset=utf-8
Content-Length: length
SOAPAction: "http://www.pengower.com/penapi/Login"
 
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.XMLsoap.org/soap/envelope/">
  <soap:Body>
    <RunAction xmlns="http://www.pengower.com/penapi">
      <token>string</token>
      <actionName>APIGetSettingsForOrganisation</actionName>
      <parameters>
         <parameters>
            <param title="OrgID" type="string">3</param>
            <param title="Type" type="string">Football</param>
         </parameters>
      </parameters>
    </RunAction>
  </soap:Body>
</soap:Envelope>

Note, I have not actually tested the above, it’s just an example.


JavaScript encoding

To encode the parameters, you can use this function:

function apiEncode (str)
{
    return str.replace(/&/g,"&amp;").replace(/</g, "&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&apos;");
}


Sample Javascript to build a complete SOAP package

It references a bunch of existing string variables.
apiEncode(string) is the function shown above.

r params = "<parameters>" +
               "<param title=\"EntityID\" type=\"string\">" + EntityID + "</param>" +
               "<param title=\"EntityType\" type=\"string\">" + EntityType + "</param>" +
               "<param title=\"ReportFrom\" type=\"datetime\">" + FromParam + "</param>" +
               "<param title=\"ReportTo\" type=\"datetime\">" + ToParam + "</param>" +
               "<param title=\"EnergyTypes\" type=\"string\">" + energyTypes + "</param>" +
               "<param title=\"DetailLevel\" type=\"string\">" + detailLevel + "</param>" +
               "<param title=\"IncludeEmissons\" type=\"number\">" + 1 + "</param>" +
               "<param title=\"ProjectID\" type=\"string\">" + requestProjectID + "</param>" +
               "<param title=\"CollapseEnergy\" type=\"number\">" + 0 + "</param>" +
               "<param title=\"RequestID\" type=\"string\">" + requestID + "</param>" +
             "</parameters>" ;
 
params = apiEncode(params);
 
var soapMessage = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
soapMessage = soapMessage + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">";
soapMessage = soapMessage + "<soap:Body>";
soapMessage = soapMessage + " <RunAction xmlns=\"http://www.pengower.com/penapi\">";
soapMessage = soapMessage + "  <token>" + ApiToken + "</token>";
soapMessage = soapMessage + "  <actionName>api Get Consumption</actionName>";
soapMessage = soapMessage + "  <parameters>" + params + "</parameters>";
soapMessage = soapMessage + " </RunAction>";
soapMessage = soapMessage + "</soap:Body>";
soapMessage = soapMessage + "</soap:Envelope>";    

Calling from jQuery

There is one other little thing you need to be aware of when calling from jQuery (and presumably Javascript), namely the need to set the header appropriately. This is an example of how to do it with jQuery;

 
$.ajax({
   url: url,
   type: "POST",
   beforeSend: function(request) {request.setRequestHeader("SOAPAction", "http://www.pengower.com/penapi/RunAction"); return request; },
   dataType: "xml",
   data: soapMessage,
   complete: RenderResults,
   contentType: "text/xml; charset=\"utf-8\"",
   processData: true,
   async: true
 });

beforeSend is the line that works the magic.
RenderResults is just the function my example is calling on returning, you can call it whatever you like.


Unpacking the result

What you get back from the platform is an XML document. However, the payload is encoded as a string inside the RunActionResult element. So, you need to grab that string and convert that into an XML document in order to access the results.

This is an example of a function and a ParseXML helper function (to deal with our old friend Internet Explorer) that will do that. If you are not running in a browser then the ParseXml function is redundant.
Note: In my code I am returning just a string in "Output" (I hand-craft some JSON to make my usecase easy), however, if you let the platform return a record set or an array, you may find that the contents of "output" is yet another XML document encoded as a string, so you may need to grab that and parse that as XML as well. If you are doing this, please update this entry with the facts as I am not sure.

//Will return an object where you can access the results
function apiParseResult(xmlHttpRequest)
{
    var responseXml = xmlHttpRequest.responseXML;
    var t = $(responseXml).find("RunActionResult").text();
    var response = ParseXml(t);
    var status = $(response).find("status").text();
    var report = $(response).find("report").text();
    var output = $(response).find("output").text();
    var ret = {status: status, report: report, output: output};
    return ret;
 
}
 
//Only relevant when running from a browser. Deals with IE being non-standard.
function ParseXml(str) {
    if (window.DOMParser)
      {
        parser=new DOMParser();
        xmlDoc=parser.parseFromString(str,"text/xml");
      }
    else // Internet Explorer
      {
        xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async="false";
        xmlDoc.loadXML(str);
      }
      return xmlDoc;
 
}
$.soap({

    url: 'https://www.pengower.net/AppPool/penAPI.asmx',
    method: 'Login',
	appendMethodToURL: false,
	namespaceURL: 'http://www.pengower.com/penapi',
	SOAPAction: "http://www.pengower.com/penapi/Login",
	envAttributes:{
	'xmlns:xsi':'http://www.w3.org/2001/XMLSchema-instance',
	'xmlns:xsd':'http://www.w3.org/2001/XMLSchema'
	},
    data: {
        client: 'client',
	application: 'application',
	username: 'username',
	password: 'password'
    },

    success: function (soapResponse) {
        // do stuff with soapResponse
        // if you want to have the response as JSON use soapResponse.toJSON();
        // or soapResponse.toString() to get XML string
        // or soapResponse.toXML() to get XML DOM
		console.log(soapResponse.toString());
    },
    error: function (SOAPResponse) {
        // show error
		console.log(SOAPResponse.toString());
    },
	
	enableLogging: true
});