Giter VIP home page Giter VIP logo

h54s's Introduction

HTML5 Data Adapter for SAS® (H54S)

npm version install size npm downloads gitter chat

What is H54S?

H54S facilitates and manages bi-directional communication between JavaScript based HTML5 Web Applications (Single Page Web Applications, Progressive Web Apps) and back-end services written in SAS that execute on either SAS Viya or SAS v9. The library aims to facilitate communication between Javascript-based UI developers and SAS developers, enabling them to build and deploy secure, production ready Web Applications with as little friction as possible.

Quick Start

This repository contains the core H54S JavaScript library. If you understand what this does and just want to start creating an App, we highly recommend that you head over to our our Create SAS App repository for a choice of pre-integrated Create React App-based template applications that will make your development much, much easier.

Server Requirements

An instance of either:

  • SAS Viya (3.4 or later, full deployment); or
  • SAS v9 Platform (v9.4) with Integration Technologies and a SAS Web Tier

Client Requirements

  • A modern Web Browser (Chrome, Firefox, Safari, IE11+)

Google Chrome or Firefox are strongly recommended. For development, having Git and Node installed is also very useful.

Why is it called H54S?

It started out as an abbreviation of 'HTML5 4 SAS'. Marketing isn't our strong point. We know it sounds like a strain of Bird Flu, but the project has been active under this name for a few years now so we're sticking to it. It's almost memorable now.

Great. How do I get started?

Using git, clone this repository to somewhere local:

git clone https://github.com/Boemska/h54s

Then if you're a SAS developer, put your SAS hat on, and follow the instructions according which flavour of SAS you're working with.

SAS Back End

Note: You may notice that while the process differs, the code is exactly the same for both SAS Viya and SAS v9. The design of H54S ensures that all applications built with it are portable between SAS v9 and SAS Viya, with no changes in code required to deploy or promote applications across the two platforms

  1. Copy the sasautos directory to your SAS server. On Viya this is your Compute Server node, on SAS v9 this is your Application Server context (e.g. SASApp) compute node. In this example we copied it to /pub/apps/h54s/sasautos on the compute node filesystem.

  2. Register a new back-end code object. On Viya this is a File of type Job Definition, and can be registered through the SASJobExecution WebApp (https://[yourViyaServer]/SASJobExecution/). On SAS v9 this is a Stored Process and can be registered through SAS Management Console or Enterprise Guide. In both cases you'll be registering the code object to a SAS folder that you have permission to write to. In both Viya and v9, I created mine in my user's My Folder location ("chris") and called it myFirstService:

  3. Edit the code for the newly registered code object, and register the following code:

* get H54s (from wherever you placed it in step 1) ;
%include '/pub/apps/h54s/sasautos/h54s.sas';

* Process and receive datasets from the client ;
%bafgetdatasets();

* Do some SAS. Can be Anything. Just get some data;
data mydata;
  set sashelp.class;
run;

proc sort data=mydata;
  by name;
run;

* Return a resulting dataset to the client ;
%bafheader()
  %bafOutDataset(processed, work, myData)
%bafFooter()
  1. Configure the output type for your newly registered code object.

On Viya, right click on the job name and select properties. From the properties menu select "Parameters". Add the following parameter and then click save:

  • Name: _output_type
  • Default value: html
  • Field type: Character
  • Required: false

On SAS v9, make sure you enable Streaming Output as the output type. If you are using Enterprise Guide to do this, also be sure to check "Global Macro Variables" and uncheck "Include STP Macros" under the "Include code for" dropdown.

  1. Execute the newly registered code. On Viya do this through the same SASJobExecution WebApp, by right clicking on the Job and selecting "Submit job". On SAS v9 do this through the Stored Process WebApp, by logging on to [yourserver]/SASStoredProcess/, locating the job in the UI and clicking on it.

In both cases, you should see output similar to the following:

{ "processed" : [{"Name":"Alfred","Sex":"M","Age":14,"Height":69,"Weight":112.5},{"Name":"Alice","Sex":"F","Age":13,"Height":56.5,"Weight":84},{"Name":"Barbara","Sex":"F","Age":13,"Height":65.3,"Weight":98},{"Name":"Carol","Sex":"F","Age":14,"Height":62.8,"Weight":102.5},{"Name":"Henry","Sex":"M","Age":14,"Height":63.5,"Weight":102.5},{"Name":"James","Sex":"M","Age":12,"Height":57.3,"Weight":83},{"Name":"Jane","Sex":"F","Age":12,"Height":59.8,"Weight":84.5},{"Name":"Janet","Sex":"F","Age":15,"Height":62.5,"Weight":112.5},{"Name":"Jeffrey","Sex":"M","Age":13,"Height":62.5,"Weight":84},{"Name":"John","Sex":"M","Age":12,"Height":59,"Weight":99.5},{"Name":"Joyce","Sex":"F","Age":11,"Height":51.3,"Weight":50.5},{"Name":"Judy","Sex":"F","Age":14,"Height":64.3,"Weight":90},{"Name":"Louise","Sex":"F","Age":12,"Height":56.3,"Weight":77},{"Name":"Mary","Sex":"F","Age":15,"Height":66.5,"Weight":112},{"Name":"Philip","Sex":"M","Age":16,"Height":72,"Weight":150},{"Name":"Robert","Sex":"M","Age":12,"Height":64.8,"Weight":128},{"Name":"Ronald","Sex":"M","Age":15,"Height":67,"Weight":133},{"Name":"Thomas","Sex":"M","Age":11,"Height":57.5,"Weight":85},{"Name":"William","Sex":"M","Age":15,"Height":66.5,"Weight":112}], "usermessage" : "blank", "logmessage" : "blank", "requestingUser" : "chris", "requestingPerson" : "Chris", "executingPid" : 1054, "sasDatetime" : 1906323243.9 , "status" : "success"}

This is good enough for now. Time for some Front End Development.

HTML5 Front End

Vanilla Javascript

This is the most basic approach. Assuming that you have a local Web Server installed for development:

  1. Create an index.html or start a new project in your chosen IDE.

  2. Copy the /dist/h54s.js file to your project and include it. Your index.html might look like this:

<!DOCTYPE html>
<html>
  <body>
    <script src="h54s.js"></script>
    <h1>Look Ma, Front End!</h1>
  </body>
</html>

For IE, you may need to add <meta http-equiv="X-UA-Compatible" content="IE=edge;" />.

  1. If you are hosting your index.html and project files from within a deployed static.war, or behind the same reverse proxy as your SPWA, you don't need this step. Otherwise, for most people:

    Fire up your browser. This is where Chrome comes in handy, as it allows developers to disable Same-Origin Policy. To tell your browser to allow background requests to non-local pages while you develop, you need to start Chrome with the --disable-web-security command line flag. For example, on Mac OS, first close Chrome and run the following in the Terminal: open /Applications/Google\ Chrome.app --args --disable-web-security When you see this warning, you're in business:

    Chrome with --disable-web-security

  2. Load your index.html page, Open Chrome Developer Tools (F12), Open the Console tab.

  3. Create an instance of the adapter. In the console, try typing h5... Chrome should autocomplete to h54s, meaning the script is sourced correctly.

    Assuming your SAS webapp URIs are the default SASStoredProcess and SASLogon, the following should be enough to get you started:

// Instantiate adapter. If SPWA was located at
// http://myServer:7980/SASStoredProcess/, you would do a
var adapter = new h54s({hostUrl: 'http://myServer:7980'});

// then create a dataset to send to SAS, which in JS is an
// object array that looks a bit like this
var myFirstTable = [
  { name: 'Abdul', sex: 'M', weight: 101.1 },
  { name: 'Jane', sex: 'F', weight: 133.7 }
];

// add it to a h54s SasData object
var data = new h54s.SasData(myFirstTable, 'datain');

// make your first call to SAS
adapter.call('/User Folders/Christopher Blake/My Folder/myFirstService', data, function(err, res) {
  if(err) {
    //Houston we have a problem
    console.log(err);
  } else {
    //res is an object returned from the server
    console.log(res);
  }
});

If you're logged into your SPWA and have a session cookie already, you should see this:

h54s example

Otherwise, if you're not logged in yet, you should see this:

h54s logon error message

The easiest thing to do at this point is to log into your SPWA in another tab, refresh your page and try running the code again. However, if you're feeling adventurous you could skip ahead and try this in the console:

adapter.login('mysasusername','mysaspassword'); // More on this later

Any queued adapter.call() calls should resume after a successful adapter.login().

What just happened? What did I do?

First, we registered a SAS program as either an STP or Job as a back-end service. When the "service" is called the program would do some SAS-based stuff (which given the power and flexibility of SAS could have been anything, from a secured lookup into a legacy mainframe-based system so you can pre-populate a form, to an on-the-fly Hadoop query built into your app). For this example, we just told it to select records from the good old SASHELP.CLASS into a new temporary dataset called WORK.MYDATA, sort it, and return the resulting dataset to the client as an object array called processed.

Then, from the Web side, we started a new project by creating an index.html page which sources the client-side h54s.js script. We then used the Chrome Dev Console to run some JavaScript code - to create a configured instance of the h54s Adapter, create a sample dataset, attach that dataset to a call to SAS as datain, fire it over, and use a simple function to either show us the dataset that was returned by SAS as processed, or have a look at any errors that might have occured.

Easy, right? Want to know more, read our docs

Development and Testing of JS adapter code

We love contributions! If you'd like to get involved, check out the build instructions.

Any questions or comments? Come join the chat. Join the chat at https://gitter.im/Boemska/h54s

License

This work is dual-licensed under Apache 2.0 and GPL 3.0 (or any later version). You can choose between one of them if you use this work.

SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later

h54s's People

Contributors

bcboemska avatar boemska-richard avatar bojan88 avatar boomskats avatar bozazec avatar cj13579 avatar dependabot[bot] avatar gitter-badger avatar i-vuckovic avatar mlmilos avatar mobeenash avatar mr-357 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

h54s's Issues

Standardisation of Status message and Error object

This is an extension of issue #41

At the moment, SAS returns a status from the adapter, which was a placeholder that we were always going to standardise.

So how about this:

a "status": "success" is the standard response for a successful execution of whatever it is that SAS was doing. A status of anything else (an example of which is the existing "status" : "inputTableNotFound" returned by %hfsErrorCheck and already outlined in the README), should be considered an error and throw an err object that is already documented in the readme.

For this type of SAS-thrown backend error we should implement a new err.type of programError, and the err.type = 'programError' object should then include two new properties: err.status and err.message.

I'll document the mechanisms to implement this error throwing from the SAS side separately.

non-ascii characters (such as en-dash) being url encoded as Windows-1252 instead of UTF-8

This issue was discovered in a Windows 9.3 environment, and is tricky to replicate from a code sample and so a dataset is attached.
endash.zip

When returning via the adapter, the json appears valid:

{ "columnspec" : [ {"NAME":"TESTVAR", "TYPE":2, "LENGTH":2000, "LABEL":" "} ], "tabledata" : [ {"TESTVAR":"ITCO%20%96%20Data"} ], "usermessage" : "blank", "logmessage" : "blank", "requestingUser" : "Allan Bowe", "requestingPerson" : "t'other Allan Bowe", "executingPid" : 3968, "sasDatetime" : 1790069921 , "status" : "success"}

But the adapter returns an error:

Object { message: "malformed URI sequence", type: "unknownError", stack: "[7]</module.exports.unescapeValues@…" }

As per http://www.w3schools.com/tags/ref_urlencode.asp, if the UTF-8 equivalent (%E2%80%93) is returned, then the adapter works fine.

@boemska-nik has already identified a potential solution (which works fine for me) which is to apply the following option in the relevant sas session:

options URLENCODING=UTF8;

documentation update for IE users

In corporate environments using IE the following tag may be necessary:

<meta http-equiv="x-ua-compatible" content="ie=edge">

This should be part of the readme

Rewrite core parser

Currently we're loading all macro params into a single-variable work dataset and using prx to work through one 32k chunk at a time. DS2 might give us a way of parallelising the processing of multiple frames when datasets exceed the 32k limit.

Also look at JSON package in 9.4m3

Endless loop when authenticating

I have followed the instructions how to setup h54s, but cannot get authentication to work. I tried to use the h54s-angular-seed application, but after entering username / pass (in the popup), I end up in a redirect loop (status code 302). Creating a small app where I manually call adapter.login(..) I get the same.

Really cant figure out why. Currently using SAS 9.4 M3. Opening the stored process (via sas portal) using h54s works fine. Using Chrome.

Any help would be appreciated.

Retry request needs program context

XHR retry requests need a property of 'programName' so that the program which failed/was retried can be noted in an Application Log if required

Optimize the code for converting json to dataset

The code for converting json to sas dataset seems to be slow, and should be looked closer at. This is the macro named hfsGetDataset. A dataset with around 4000 rows and 9 columns take around 10 sec to process.

Change to multipart/form-data

As it stands our POST requests are being sent as application/x-www-form-urlencoded. There seems to be a bug in the 9.4 STP webapp where it takes over a minute, sometimes even ten minutes, to deserialise the POST body into params / activemq messages. This also seems to depend on the length of the longest parameter - so one single 32,000 parameter takes exactly 70 seconds every time, two 16,000 parameters (so same amount of data) would take 35 seconds, 6 lots of 5,000 would take 12-13 secs.

The fix is to upload the POST body as multipart/form-data, which seems to work much better.

Example of it taking 10 mins to pass params from JVM to multibridge stp runner:

image

Semi-duplicate of issue #52

sasCsv += '"' + JSON.stringidy(val).replace('"', '""') + '"';

The replace here should also be global (and the typo needs to be corrected)

We also need to consider whether we need this, or if it is better to allow developers to explicitly stringify objects and have them stored as strings, as we do now where this is uesd. Either is doable but we need a solid mechanism for identifying these on the way back from SAS (eg. a column name prefix), same as we do with the dates.

triple trouble

The presence of particular macro variables (type and name) can cause the adapter to fail due to incorrect use of triple ampersands (&&&) - eg &&&type&colNo. In these cases, a double ampersand is needed to cause the desired resolution.

hfsOutDataset macro doesn't support case sensitive DBMS objects

Need to add upcase function to left side of where clause when querying DICTIONARY.COLUMNS for memname/dsn.

This only applies when the libname option PRESERVE_COL_NAMES is used (default for SAS generated libnames), however since we cannot easily determine if this option has been set, the upcase solves the problem. i.e.:

CREATE TABLE tempcols as 
  SELECT upcase(name) as name, 
         type, 
         length 
  FROM   dictionary.columns 
  WHERE  upcase(memname) = upcase("&dsn.") 
         AND libname = upcase("&libn.");  

Change how SAS ERRORs are reported

Currently the SAS Erros array fills up with each occurrence of an error pulled out of the SAS log, with no context. What we need it to do is populate the ERRORs array in the same way that the Debug log array is handled.

So:

  • When an error occurs in non-debug mode (an error being a json parsing failure), the entire HTML body that is returned should be pushed onto the SAS Errors Array.
  • When in Debug mode, all logs can continue to go into debug mode using the existing mechanisms.

No error message facility in adapter

The adapter provides a neat way to surface messages to the user (usermessage) or specific runtime issues (logmessage). It would be nice if a similar mechanism existed for returning an error message (eg errormessage). This would allow developers to use SAS side logic to gracefully surface a user friendly error message back to the front end - such as user Jim not found or unable to access xyz.

ajaxTimeout: 0 not working

I'm seeing instances where ajaxTimeout: 0 is basically timing out immediately. I don't know if this is related to the fact I am calling multiple instances of the adaptor.. But setting the value back (eg to 60000) prevents the following in the console:

TypeError: res is undefined

adding my .js file and my copy of the adaptor for info.
h54s.js.txt
myJS.txt

Data step variables named USER getting populated with &SYSUSERID in client

Sent from SAS:

data sasparams;
  USER="Sugarhill Gang";
run;
%hfsHeader;
%hfsOutDataset(jsParams,WORK, sasparams);
%hfsFooter;

Received by browser:
image

So maybe USER is a reserved variable name in H54s.. If so should probably be documented somewhere? Ideally though this variable name would be available to developers, in order to avoid unexpected behaviour.

Process not found

When a response to a request to the SASStoredProcess webapp includes the following string, regardless of debug/nondebug mode:

<h2>Stored process not found:

The adapter should throw a new class of error. The condition here is that the program has not been found, or more likely, access to it has been denied to the user in question.

The error message should include the following:

You have not been granted permission to perform this action, or the STP is missing.

Minor typo in README.md

At line 195 in the README.md there's a minor typo I suppose, DHS() should be DHMS()?
For the rest it is a great project! I'm just starting to experiment with the code.

Provide metadata mechanism for identify DATETIME variables

The current version of the adaptor will attempt to convert any variables prefixed with DT_ to a javascript datetime (and vice versa when coming back to SAS).

This can feasibly cause issues / require workarounds should such variables be passed without the intention to translate them.

A mechanism should exist to allow datetime variables to be identified separately from the variable name itself.

Possible to specify encoding when serializing json

Is it possible to specify somehow what encoding to use when serializing json? I mean inside config of h54s.
I have run into issue with using norwegian letters in javascript, and trying to send that over to sas.

loss of numerical precision in JSON from SAS

line 566 of h54s.sas wipes all the formats (providing a consistent numerical value to the js side).

data _null_;
  file &h54starget.;
  set tempOutputView end=lastrec;
  format _all_;
  ....

The issue is that the default best12. format is applied - resulting in a loss of precision (as can be evidenced by running the code below).

data _null_;
  x=3815842.11116;
  put x=;
run;

SPKs containing the STPs are missing from Examples

The Stored Procedures that are required for the example applications to work are not included as part of the repository rendering the examples from a "seeing an functioning fully" perspective useless.

SAS 9.4 not returning error logs

SAS 9.3 is outputting error messages event if debug is not set, but 9.4 is not with both debug settings.
You can see error messages in 9.4 starting with "ERROR" colored in red.
Can you investigate this?

additional info in the h54 response

The following attributes would be helpful in the h54s response:

  • &syssite (site id)
  • &syshostname (server name)
  • &sysscp (operating system)
  • &sysvlong (full version including release number)

Internet Explorer aborts calls to h54s for no apparent reason.

At my client (a large UK bank) we have been using h54s very successfully except for one issue we have with Internet Explorer when we call the adapter. The adapter.call is done and the timings from the network tab in the IE tools show that it waited for about 40 secs, and shows that Result as (Aborted). Occasionally this will work properly and make the call. But usually we get the abort, and our webapp gets stuck. Please provide some kind of fix. Looking at stack overflow I could see some other people having problems with IE and POST requests like this suddenly aborting for no apparent reason. So it seems more of an IE issue than a h54s issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.