README
hyper : Interactive Hypermedia Shell
Exploring an interactive REPL/shell for interacting with HTTP-based hypermedia services
Summary
The hyper utility is a simple command-line style shell/REPL for interacting with an online services/APIs. While a fully-functional HTTP client, hyper is especially good at dealing with hypermedia services including Collection+JSON, SIREN, and HAL. There are plans to add support for PRAG+JSON, MASH+JSON, and possibly UBER in the future.
Along with HTTP- and mediatype-aware commands, hyper also supports some convience functionality like SHELL commands, configuration file management, and a LIFO stack to handle local memory variabes.
Importantly, hyper is not just a shell/REPL, it is a hypermedia DSL. It encourages users to `think' in hypermedia. Rather than writing complex HTTP queries that look like this (an example that works fine in hyper):
ACTIVATE http://localhost:8181/task/
WITH-METHOD PUT
WITH-BODY title=testing&tags=hyper&completeFlag=false
WITH-ENCODING application/x-www-form-urlencoded
WITH-HEADERS {"if-none-match":"*"}
The hyper shell can also use mediatype-aware convience commands to locate, parse, fill, and execute inline hypermedia controls. This results in a much more readable hyper exeperience:
STACK PUSH {
"title":"testing",
"tags":"hyper",
"completeFlag":"false"
}
ACTIVATE http://locahost:8181/home/
ACTIVATE WITH-FORM taskFormAdd WITH-STACK
In both cases, the same work is completed. In the first example, a human can read all the docs and examples and craft a successful HTTP PUT request. This works until the server changes a parameter (e.g. moves from PUT to POST).
In the second example, the hyper engine loads available data (it could have been from disk using STACK LOAD task-record.txt
) and uses identified hypermedia controls (in this case the taskFormAdd
control) to complete the request. This will continue to work even if HTTP details are changed (like changing PUT to POST)-- as long as the hypermedia form taskFormAdd
is included in the response.
Motivation
The idea for this shell comes from other REPL-style interactive CLIs like node
and command-line tools like curl
. You can start a stateful client session by typing hyper
at the command line. Then you can make an HTTP request (ACTIVATE
) and manipulate the responses. You can also write hyper commands in a file and pipe this file into hyper for a scripted experience: (hyper < scripts/sample.txt > scripts/sample.log
).
Hyper is "mediatype-aware" -- that is, it recognizes well-known media types and offers convience methods for dealing with them. For example after loading a SIREN response, you can use the following commands:
# SIREN example
GOTO http://rwcbook10.herokuapp.com
SIREN LINKS
SIREN ENTITIES
SIREN ACTIONS
GOTO WITH-REL taskFormListByUser WITH-QUERY {"assignedUser" : "alice"}
That last command 1) uses the href
associated with the SIREN action element identified by the rel:taskFormListByUser
, 2) supplies a querystring argument and 3) makes the HTTP request.
Another way to use hyper is to load the data stack with some name/value pairs and then use a named form within the response to execute an action. Like this:
# read list
GOTO http://rwcbook10.herokuapp.com
# add data to the stack and execute the write operation
STACK PUSH {"title":"just another one","tags":"with-test","completeFlag":"false"}
GOTO WITH-FORM taskFormAdd WITH-STACK
# check the write results using the same stack data
GOTO WITH-FORM taskFormListByTag WITH-STACK
SIREN PATH $..*[?(@property==='tags'&&@.match(/with-test/i))]^
NOTE: Spaces are significant in HYPER commands. The above example shows spaces are properly handed within embeded quotes (STACK PUSH {"title":"just another one","tags":"with-test","completeFlag":"false"}
). However, there must be no spaces between elements in the JSON segments.
Note that the client will use whatever URL, HTTP method, and body encoding the server indicates. Also, notice that the client will automatically match up any form fields on the stack to fill in the form. Even when the server changes details (new URL, different method, etc.), the client will be able to handle the write operation without changes.
You can also use JSONPath to query responses:
SIREN PATH $.entities.*[?(@property==='id'&&@.match(/rmqzgqfq3d/i))]^.[id,title,href,type]
You can also use hyper to program a modificaiton of existing records:
REQUEST WITH-URL http://rwcbook10.herokuapp.com WITH-ACCEPT application/vnd.siren+json
REQUEST WITH-PATH $.entities[0].href WITH-ACCEPT application/vnd.siren+json
STACK PUSH WITH-PATH $.properties
STACK SET {"tags":"fishing,skiing,hiking"}
REQUEST WITH-FORM taskFormEdit WITH-STACK WITH-ACCEPT application/vnd.siren+json
EXIT
In the above example, the hyper :
- Calls the root resource of the serivce asking for a SIREN formatted response
- Locates the first item in the collection, pulls its HREF value and calls that record
- Pushes the item properties of the record onto the local stack
- Updates the
tags
value on the stack to reflect the change - Uses the
taskFormEdit
form, fills it with values from the stack and makes the request - Once all is done, the script exits
Similar options exist for HAL, CollectionJSON, JSON+FORMS, and other formats. These various format types are defined using external plug-ins that can be created and just dropped into the /plugins/
folder to be loaded at runtime.
Examples
See the scripts folder for lots of working examples.
Futures
Some notes on future enhancements
Feature tracking
This is a work in progress and totally unstable/unreliable. Here the current workplan and status for this project:
- : Initial CLI loop
- : support for piped scripts (in and out)
- : support for # - comment lines
- : support for VERSION - returns version info
- : support for EXIT|STOP - halt and exit with 0
- : support for EXIT-ERR - halt and exit with 1
- : support for EXIT-IF - halt and exit with 1 if simple condition is met
- : support for .. INVALID-URL <url|#