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.
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.
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
- 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.
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.
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.
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
-
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. -
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'sMy Folder
location ("chris") and called itmyFirstService
: -
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()
- 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.
- 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.
This is the most basic approach. Assuming that you have a local Web Server installed for development:
-
Create an
index.html
or start a new project in your chosen IDE. -
Copy the
/dist/h54s.js
file to your project and include it. Yourindex.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;" />
.
-
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: -
Load your
index.html
page, Open Chrome Developer Tools (F12), Open the Console tab. -
Create an instance of the adapter. In the console, try typing
h5
... Chrome should autocomplete toh54s
, meaning the script is sourced correctly.Assuming your SAS webapp URIs are the default
SASStoredProcess
andSASLogon
, 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:
Otherwise, if you're not logged in yet, you should see this:
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()
.
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
We love contributions! If you'd like to get involved, check out the build instructions.
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