Web Api R4


Introduction

Appframe R4 provides a RESTful interface to its database and framework functionality. Built while strictly following the REST architecture and its constraints, even the commonly ignored HATEOAS constraint.

  • Access via HTTPS, optionally using our .NET client library.
  • Data can be returned as JSON, HTML or XML.
  • Two layer Role based Security: Application layer and Data layer.
  • Authentication: Basic, Windows or Certificate Authentication.
  • Exposed resources and procedures can be discovered by browsing the API using your web browser.
  • Appframe does not expose a resource for every Pims Module or Object, these are defined based on customer needs. This is to not expose more then necessary.

Examples using the API to retrieve data from Pims Document Control module

The following URIs are only example URIs.

Get All Documents -  https://api.pimsdevhosting.com/dcs/documents?take=-1 

Get All Documents with Paging -  https://api.pimsdevhosting.com/dcs/documents 

Get next 5 or x amount of Documents -  https://api.pimsdevhosting.com/dcs/documents?skip=5 

Get Document By ID -  https://api.pimsdevhosting.com/dcs/document/00-01-AIB-A-0001 

Get Documents By Type using Filter -   https://api.pimsdevhosting.com/dcs/documents?fields=DocumentType&take=-1&filter={"equals":{"left":{"field":"DocumentType"},"right":"ZST"}} 

Get Documents By SearchField in Filter -   https://api.pimsdevhosting.com/dcs/documents?fields=DocumentID,DocumentType&take=-1&filter={"contains":{"left":{"field":"SearchColumn"},"right":"00-01-AIB"}} 

Get All Revisions By Document -    https://api.pimsdevhosting.com/dcs/document/00-01-00-01-000001-AOGD-AZST-A00001/revisions 

File download

Download a File, A resource with a file link will have an Object called download that will hold the URI for downloading the file

https://api.pimsdevhosting.com/document/df5480e2-ad4c-45cc-b446-81bf2bc337b3/download/00-01-OM-A-0002_A_STA_01_DCS_Contractor1.pdf 

Sort ordering

By default sort ordering is sorting your response by resource Key field, but you can override it by adding order query parameter like example below: https://api.pimsdevhosting.com/dcs/documents?take=-1&order=[{"asc":"DocumentID"}] 

Filtering 

Filtering consist of one or more expressions which can be grouped in "and" or "or" groups.

Groups are defined by having an object with a "mode" key, and the value is an array of items in the group.

Expressions are defined by having an object where the only key is the operator, and the value being an object defining the operands for that operator.

Fields are referenced using an object with the key "field" and the value being the field name.

See below for more detailed syntax definition.

Filter Examples

"..." - A comma separated list or any of the examples below.
{ and: [ ... ] } 
{ <mode>: [ <filter>, ... ] }

<operand>

  • <field>
  • <string>
  • <number>
  • <boolean>
  • null

{ <field>: <fieldname> }

<unary>

  • isnull
  • isnotnull
  • istrue
  • isfalse
  • isblank
  • isnotblank

{ <unary>: <field> }  

{ 
    isnull: { 
        field: "Closed" 
    } 
}
{ 
    isnotnull: { 
        field: "Closed" 
    } 
}

<binary>

  • equals
  • notequals
  • greaterthan
  • greaterthanorequal
  • lessthan
  • lessthanorequal
  • beginswith
  • notbeginswith
  • endswith
  • notendswith
  • contains
  • notcontains
  • like
  • notlike
{ <binary>: { left: <field>, right: <operand> } }

{ 
    equals: { 
        left: { 
            field: "DocumentType"
        }, 
        right: "ZST" 
    } 
}

{ 
    contains: { 
        left: { 
            field: "SearchColumn" 
        }, 
        right: "00-01-AIB" 
    }
}

<between> 

  • between
  • notbetween
  • timebetween
  • timenotbetween
{ <between>: { test: <field>, begin: <operand>, end: <operand> } }
{ 
    between: {
        test: { 
            field: "Created"
        }, 
        begin: "2016-01-01T00:00:00.000Z",
        end: "2016-07-01T00:00:00.000Z"
    } 
}

<inlist>

  • inlist
  • notinlist

{ <inlist>: { left: <field>, list: [ <operand>, ... ] } 
{ 
    inlist: { 
        left: {
            field: "Name"
        }, 
        list: [ 
            <operand>, 
            ... 
        ] 
    } 
}

Request Validation

By default the ASP.NET pipeline checks the input for potentialy dangerous values.
In order to accept JSON or XML as input to procedure parameters change the requestValidationMode in web.config to 2.0
<httpRuntime requestValidationMode="2.0"/>

Javascript usage examples

Using Rest API to return result a API resource

    
    function getDocuments(){
        jQuery.ajax({
                url: "https://api.pimsdevhosting.com/dcs/documents/?take=100",
                type: "GET",
                beforeSend: function(xhr) {
                xhr.setRequestHeader("Authorization", "Basic " + btoa("Username" + ":" + "Password"));
                xhr.setRequestHeader("Accept","application/json");
                },
                success: function(resultData) {
                    //here is your json.
                    console.log(resultData);
                },
                error : function(jqXHR, textStatus, errorThrown) {
                },
                timeout: 120000,
            });
    }
    

Using Rest API to execute a procedure


    
    function execProcOnAPI(){
        var vData = {
            "Timeout": 30,
            "AwaitResult": true,
            "DocumentType": "AA",
            "Title": "Sample Doc",
            "DocGroup": "Administrative",
            "FacilityID":"A",
            "OriginatorCompany":"AOGD",
            "Discipline": "A",
            "NewDocumentID":"",
            "AddSheetNo":false,
            "ContractNo":null,
            "WorkPackID":null,
            "SubProjectID":null,
            "System":null,
            "Area":null,
            "PONumber":null
            };

        jQuery.ajax({
                url: "https://api.pimsdevhosting.com/procedure/dcsCreateNewDocumentID/call",
                data: JSON.stringify(vData),
                contentType: "application/json",
                dataType: "json",
                type: "POST",
                beforeSend: function(xhr) {
                xhr.setRequestHeader("Authorization", "Basic " + btoa("UserName" + ":" + "Password"));
                },
                success: function(resultData) {
                    //here is your json.
                    console.log(resultData);
                },
                error : function(jqXHR, textStatus, errorThrown) {
                    console.log(errorThrown);
                },
                timeout: 120000
            });
    }
    

.Net Examples

Authentication header

To authenticate request you can use similar function

    
    private static void SetBasicAuthHeader(WebRequest request, string userName, string userPassword)
    {
        var authInfo = Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(userName + ":" + userPassword));
        request.Headers.Add("Authorization", "Basic " + authInfo);
    }

Getting data XML type

Following example is using GET method and content type and aceept headers are set to XML type.

    
    private XmlDocument GetXMLResponse(string requestUrl)
    {
        try
        {
            //Setting security protocol
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            var request = WebRequest.Create(requestUrl) as HttpWebRequest;
            SetBasicAuthHeader(request, "UserID", "Password");
            request.ContentType = "application/xml";
            request.Accept = "application/xml";
            request.Method = "GET";
            //Setting to use default system proxy
            HttpWebRequest.DefaultWebProxy = WebRequest.GetSystemWebProxy();
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            var xmlDoc = new XmlDocument();
            xmlDoc.Load(response.GetResponseStream());
            return xmlDoc;
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

Using stored procedure

Following example executes a stored procedure with parameters and returns JSON or XML.

    
            var baseAddress = new Uri("https://api.pimsdevhosting.com");
            var username = ConfigurationManager.AppSettings["username"];
            var password = ConfigurationManager.AppSettings["password"];
            var resourceName = "GetDomain";

            try
            {
                byte[] data = Encoding.ASCII.GetBytes("Timeout=60&AwaitResult=on&Domain=Balder&Data=test2");
                HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create($"{baseAddress}/procedure/{resourceName}/call");
                WebRequest.DefaultWebProxy = WebRequest.GetSystemWebProxy();
                SetBasicAuthHeader(webRequest, username, password);
                webRequest.Method = "POST";
                webRequest.Accept = "application/json"; //or application/xml
                webRequest.ContentType = "application/x-www-form-urlencoded";                
                webRequest.ContentLength = data.Length;                
                
                string vResult = string.Empty;
                
                using (var vStream = webRequest.GetRequestStream())
                    vStream.Write(data, 0, data.Length);

                using (StreamReader reader = new StreamReader(webRequest.GetResponse().GetResponseStream()))
                    vResult = reader.ReadToEnd();

            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
            
            private static void SetBasicAuthHeader(WebRequest request, string userName, string userPassword)
            {
                var authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(userName + ":" + userPassword));
                request.Headers.Add("Authorization", "Basic " + authInfo);
            }

File upload

File can be uploaded directly to Filestore, after upload is complete you will get uploaded FileRef, which you can use to add data into application table.

    
    
    NameValueCollection values = new NameValueCollection()
    {
        { "Domain", gDomain},
        { "DocumentID", gDocumentID },
        { "RevisionItemNo", "1" },
        { "Type", "Original" },
        { "SortOrder", "1" },
        { "IsAppendix", "false" },
        { "FileName", System.IO.Path.GetFileName(FilePath) },
        { "FileSize", System.IO.File.ReadAllBytes(FilePath).ToString() }
    };

    NameValueCollection files = new NameValueCollection()
    {
        {"FileName", FilePath }
    };

    UploadFile("Resource name", values, files);

    
    private string UploadFile(string pMethodUrl, NameValueCollection values, NameValueCollection files = null)
    {
        //"API URL" - migth be https://api.pimsdevhosting.com
        //pMethodUrl - api resource
        string vUrl = string.Format("{0}/{1}", "API URL", pMethodUrl);
        string vResult = null;
        try
        {
            string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundaryBytes = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] trailer = System.Text.Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(vUrl);
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            request.Method = "POST";
            request.KeepAlive = true;
            request.Credentials = CredentialCache.DefaultCredentials;

            Stream requestStream = request.GetRequestStream();
            foreach (string key in values.Keys)
            {
                byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}", key, values[key]));
                requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                requestStream.Write(formItemBytes, 0, formItemBytes.Length);
            }

            if (files != null)
            {
                foreach (string key in files.Keys)
                {
                    if (File.Exists(files[key]))
                    {
                        int bytesRead = 0;
                        byte[] buffer = new byte[2048];
                        byte[] formItemBytes = System.Text.Encoding.UTF8.GetBytes(string.Format("Content-Disposition: form-data; name=\"file\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n", key, files[key]));
                        requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
                        requestStream.Write(formItemBytes, 0, formItemBytes.Length);

                        using (FileStream fileStream = new FileStream(files[key], FileMode.Open, FileAccess.Read))
                        {
                            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                            {
                                // Write file content to stream, byte by byte
                                requestStream.Write(buffer, 0, bytesRead);
                            }

                            fileStream.Close();
                        }
                    }
                }
            }

          
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            requestStream.Write(trailer, 0, trailer.Length);
            requestStream.Close();
            HttpWebRequest.DefaultWebProxy = WebRequest.GetSystemWebProxy();
            SetBasicAuthHeader(request, "UserID", "Password");
            using (StreamReader reader = new StreamReader(request.GetResponse().GetResponseStream()))
            {
                vResult = reader.ReadToEnd();
            };
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.StackTrace.ToString());
        }
        return vResult;
    }

Check IIS settings for maximum allowed content length.

Related articles

Placeholder "LocalizeWeb2016" failed