npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

hal-http-client

v0.12.1

Published

A status code driven JSON HAL HTTP client based on the fetch API.

Downloads

727

Readme

hal-http-client

A status code driven JSON HAL HTTP client based on the fetch API.

The API doc can be found here.

What is HAL and where does this client come into play?

HAL (Hypertext Application Layer), as the name already states, is an application level layer on top of JSON or XML that provides conventions for linking between different resources. For RESTful APIs it helps to reach level 3 of the Richardson Maturity Model . Additionally it defines how to embed related resources into the response of their parent resource for efficient APIs and lowering the need for actual HTTP requests over the wire.

The hal-http-client defines a convenient API for accessing resources represented as HAL on top of JSON (XML is currently not supported and there are no plans in doing so):

  • It allows navigating through resources with application/hal+json media type by following the available relations
  • If a resource is embedded, it transparently reads the embedded representation instead of making a real HTTP request
  • Flow control is supported by providing a status code driven API

Templated URLs (RFC6570) are supported via the url-template library.

Installation and Usage

npm install hal-http-client

Basically import the library, make a new instance and start discovering resources by making a GET request to the root URL of your API.

import * as halHttp from '../hal-http-client';

const hal = halHttp.create( {
   headers: { 'accept-language': 'de' },
   on: {
      // globally define how responses for status codes should be handled that were not handled locally
      '5xx': ( data, response ) => {
         console.error( `Caught unhandled 5xx error (status: ${response.status})` );
      }
   }
} );
hal.get( 'http://my-server/api/root' )
// See the example below on how to go on from here

Example

Lets take the following simple model of a person and his cars from the specs:

// person
{
   "name": "Peter",
   "age": 34
}
// his address
{
   "street": "Mainstreet 12",
   "postalCode": "12345",
   "city": "Faketown"
}
// his cars
[
   {
      "type": "VW",
      "model": "T3 Vanagon"
   },
   {
      "type": "DMC",
      "model": "DeLorean"
   }
]

An according JSON response with all sub resources embedded could look like this:

{
   "name": "Peter",
   "age": 34,
   "_links": {
      "self": { "href": "peter" },
      "address": { "href": "peter/address" },
      "cars": { "href": "peter/cars" }
   },
   "_embedded": {
      "address": {
         "street": "Mainstreet 12",
         "postalCode": "12345",
         "city": "Faketown",
         "_links": { "self": { "href": "peter/address" } }
      },
      "cars": {
         "_links": {
            "self": { "href": "peter/cars" },
            "car": [ { "href": "peter/cars/0" }, { "href": "peter/cars/1" } ]
         },
         "_embedded": {
            "car": [
               {
                  "type": "VW",
                  "model": "T3 Vanagon",
                  "_links": { "self": { "href": "peter/cars/0" } }
               },
               {
                  "type": "DMC",
                  "model": "DeLorean",
                  "_links": { "self": { "href": "peter/cars/1" } }
               }
            ]
         }
      }
   }
}

Getting the cars starting from the person can be achieved in the following way:

hal.get( '/peter' )
   .on( {
      '200': hal.thenFollow( 'cars' )
   } )
   .on( {
      '200': hal.thenFollowAll( 'car' )
   } )
   .on( {
      '200': carList => {
         console.log( carList );
         // will print:
         /*
           [
               {
                  "type": "VW",
                  "model": "T3 Vanagon",
                  "_links": { "self": { "href": "peter/cars/0" } }
               },
               {
                  "type": "DMC",
                  "model": "DeLorean",
                  "_links": { "self": { "href": "peter/cars/1" } }
               }
            ]
         */
      }
   } );

The hal.thenFollow method is a convenience factory for creating a function, which takes the response of the previous request, then follows the given relation in the response body and finally returns a ResponsePromise for further on chaining. So instead this part could have been written the following way:

hal.get( '/peter' )
   .on( {
      '200': ( peterResource, response ) => {
         return hal.follow( peterResource, 'cars' );
      }
   } )

The method hal.thenFollowAll basically works the same, only that it expects to find an array of relations to follow on the given resource and return all results again as an array.

Optional relations

For some resources a relation may be optional. If it is sufficient to just check whether the relation is available or not, the function halHttp.canFollow() is the right choice. Simply pass it the representation as first and the relation to test as second argument:

halHttp.canFollow( peterResource, 'cars' ); // => true
halHttp.canFollow( peterResource, 'job' ); // => false

If on the other hand two different tasks should be executed in either case, the "virtual" status code 'norel' can instead be used as an on-handler:

hal.follow( peterResource, 'work' )
   .on( {
      '200': () => {
         console.log( 'Peter currently is employed' );
      },
      'norel': () => {
         console.log( 'Peter currently is unemployed' );
      }
   } );

From here on you should consult the API doc to have a look at all the other APIs available on the hal-http-client.