5 Replies Latest reply on Dec 10, 2014 1:17 PM by gonmerciel

    PI Web API: Javascript Client

    mhamel

      This is a copy of the blog of Brad Hess, Sr. Software Developer at OSIsoft

       

      In our last post, we built a simple C# application to get all the Pumps in Wichita out of our database.  Today we're going to do that in Javascript.  If you're following along with my code, simply open the attached HTML file in the text editor of your choice.  If you're starting from scratch, just create a new HTML file with the contents here:

       
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      <!DOCTYPE html>
       
      <htmllang="en"xmlns="http://www.w3.org/1999/xhtml">
      <head>
          <metacharset="utf-8"/>
          <title>Wichita Pumps</title>
      </head>
      <body>
      </body>
      </html>

       Much like last time, the first thing we want to do is add a library that'll help us immensely in the rest of our project.  Within the <head> html element, add a reference to jQuery.  jQuery is a javascript library that makes previously painful Javascript tasks easy. 

       
      1
      <scripttype="text/javascript"src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>

      Now that we have jQuery available, we can start writing our own scripts.  I've created a couple of <script> tags within my HTML head in order to allow myself to code inline.

       

      One of our first steps is to define some variables to get our URLs set up.  For this purpose, I'm going to include a quick helper method to get myself a .NET-style string format utility in Javascript.  Thanks much to vCampus Team alum Michael van der Veeken for sharing this one with me!  This extends javascript's string type (the 'prototype') to add a format method.

       
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      if(!String.prototype.format) {
          String.prototype.format = function() {
              varargs = arguments;
              returnthis.replace(/{(\d+)}/g, function(match, number) {
                  returntypeofargs[number] != 'undefined'
                    ? args[number]
                    : match
                  ;
              });
          };
      }

       So now I can go ahead and declare some variables within my script tags.  Of course, as always, you'll want to the server and database names to make sense in your own environment:     

       
      var databasePath = "\\\\phlafs04\\nugreen";
      var databaseUrl = "https://restdemo.osisoft.int/piwebapi/assetdatabases?path={0}".format(databasePath);
      var plantSearchUrl;
      var pumpSearchUrl;
      

       Awesome.  Let's make sure this is working correctly.  We'll load up our (currently empty) page in a browser, and check out databaseUrl in the Javascript console.  Look for this in the Developer Tools in your browser (I use Chrome).

       

      8420.Screenshot-_2800_23_2900_.png

       

       So far, so good.  Now let's use our jQuery library to actually get some data.  Use the jQuery getJSON function to call this URL.  We'll grab the Elements link out of the response, and add our query.

       
      $.getJSON(databaseUrl, function (database) {
          plantSearchUrl = database.Links.Elements + "?templateName=Plant&nameFilter=Wichita&searchFullHierarchy=true";
      });
      

       Now let's take a look again in the browser:

       

       

       

      0216.Screenshot-_2800_24_2900_.png

       

      Oops!  This will happen with a stock PI Web API configuration.  The browser's Same Origin Policy prevents cross-origin requests by default.  PI Web API supports CORS, an industry-standard solution, to work around this problem (see http://enable-cors.org for more information).  PI Web API's CORS support can be adjusted using the PI Web API configuration-- either by making requests against the Web API's /configuration endpoints, or by manually modifying PI Web API's AF configuration database.  You'll want to set "CorsOrigins" to either your hostname, or to "*" to enable CORS traffic from any host.

       

      In this screenshot, "RESTDEMO" is my PI Web API instance name.  Your instance name is usually the same as your hostname.

       

       

       
             $.getJSON(databaseUrl, function (database) {
                  plantSearchUrl = database.Links["Elements"] + "?templateName=Plant&nameFilter=Wichita&searchFullHierarchy=true";
      
                  $.getJSON(plantSearchUrl, function (plant) {
                      pumpSearchUrl = plant.Items[0].Links["Elements"] + "?templateName=Pump&searchFullHierarchy=true";
      
                      $.getJSON(pumpSearchUrl, function (pumps)
                      {
                          var pumpsDomElement = $("#pumps");
                          var jqResults = $(pumps.Items);
      
                          jqResults.each(function (index, element)
                          {
                              pumpsDomElement.append("<li>" + element.Name + "</li>");
                          });
                      });
                  });
              });
      

       What are we doing here?  In the second callback, we're adding a variable to store a reference to the pumps element in the DOM.  DOM traversal is expensive, so you wouldn't want to make that call for each element in the result list.  Next, we're jQuery-ifying our JSON results, so that we can use the convenient shorthand each function from jQuery, which allows for a function to be executed for each object in the list.  Finally, for each object in the list, we're adding HTML to the DOM node of our list, to have the name of the pump appear as a list item.

      Here's our results in the browser!

       

      2867.25.png

       

      Thanks for staying tuned.  This concludes our set of basic posts to get you up and running with the PI System Web API in both C# and Javascript.

       

      Find the file here.

        • Re: PI Web API: Javascript Client
          calmandrysdale

          Hi Mathieu,

           

          "Oops!  This will happen with a stock PI Web API configuration.  The browser's Same Origin Policy prevents cross-origin requests by default.  PI Web API supports CORS, an industry-standard solution, to work around this problem (see http://enable-cors.org for more information).  PI Web API's CORS support can be adjusted using the PI Web API configuration-- either by making requests against the Web API's /configuration endpoints, or bymanually modifying PI Web API's AF configuration database.  You'll want to set "CorsOrigins" to either your hostname, or to "*" to enable CORS traffic from any host."

           

           

           

          We are stilling having issues with how to run cross-origin browser requests. Our configuration is as follows...

           

          {
          "AuthenticationMethods": [
          "Kerberos"
          ],
          "CorsHeaders": null,
          "CorsMethods": "GET,OPTIONS",
          "CorsOrigins": "*",
          "CorsSupportsCredentials": true,
          "DisableWrites": false,
          "SearchBoosts": [
          1.0,
          0.8,
          0.5,
          0.5,
          0.5,
          0.5
          ],
          "SearchPointAttributes": [
          "pointsource",
          "instrumenttag",
          "location1",
          "exdesc"
          ],
          "SearchScanInterval": 180
          }

           

           

           

          However, still getting a HTTP response code of 401 (Unauthorized) when our javascript makes  a call to the webserver. I was wondering how we can pass login details to the webservice? Or how to get around this?

           

          We have tried quite a few different settings on the Pi Web Service server side and not having much success.

           

           

           

          Any pointers appreciated,

           

           

           

          Cheers,

           

          Calman

           

           

           

           

            • Re: PI Web API: Javascript Client
              gonmerciel

              Hi Calman,

               

              Were you able to get this working? I'm having the same issue.

               

              Regards,

               

              Gonzalo

                • Re: PI Web API: Javascript Client
                  Bhess

                  Per the CORS spec, and as documented in the PI Web API users guide, the combination of CorsOrigins = * and CorsSupportsCredentials = true is prohibited.  You'll need to explicitly list the origins in order to pass credentials through.

                    • Re: PI Web API: Javascript Client
                      gonmerciel

                      Thanks Brad,

                       

                      I updated CorsOrigins value to "http://mywebserver" but now I'm getting this response:

                       

                      {"Message":"Authorization has been denied for this request."}

                       

                      I added "Basic" to AuthenticationMethods array, but I still get the same message.

                       

                      Any idea on how I can get this to work?

                       

                      Thanks in advance!

                        • Re: PI Web API: Javascript Client
                          gonmerciel

                          Finally got it!

                           

                          PI Web API Configuration:

                           

                           

                           
                          {
                          
                           "AuthenticationMethods": [
                          
                             "Kerberos"
                          
                           ],
                          
                           "CorsHeaders": "*",
                          
                           "CorsMethods": "GET,OPTIONS",
                          
                           "CorsOrigins": "http://mywebserver",
                          
                           "CorsSupportsCredentials": true,
                          
                           "DisableWrites": false,
                          
                           "SearchBoosts": [
                          
                             1.0,
                          
                             0.8,
                          
                             0.5,
                          
                             0.5,
                          
                             0.5,
                          
                             0.5
                          
                           ],
                          
                           "SearchPointAttributes": [
                          
                             "pointsource",
                          
                             "instrumenttag",
                          
                             "location1",
                          
                             "exdesc"
                          
                           ],
                          
                           "SearchScanInterval": 180
                          
                          }
                          

                           

                           

                          And then, insted of using $.getJSON, I use this function:

                           

                           

                           
                          function getJSONPIWebApi(url, callback) {
                          
                           $.ajax({
                          
                             url: url,
                          
                             dataType: "json",
                          
                             success: callback,
                          
                             xhrFields: {
                          
                                 withCredentials: true
                          
                             },
                          
                             crossDomain: true
                          
                           });
                          
                          }
                          

                           

                           

                          So, in the example this line:

                           

                           

                           
                          $.getJSON(databaseUrl, function (database) {
                          

                           

                           

                          is change for this one:

                           

                           

                           
                          getJSONPIWebApi(databaseUrl, function (database) {
                          

                           Hope it helps!

                           

                           

                           

                          Regards,

                           

                           

                           

                          Gonzalo

                          1 of 1 people found this helpful