Skip to content

Analysis of Heracles.ts #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/doczrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
"Quickstart",
{name: 'Tutorial', menu:['First Tutorial']},
{name: 'How To Guides', menu: ['First How to Guide']},
{name: 'Conceptual Guides', menu: ['Conceptual Guide 1']},
{name: 'Conceptual Guides', menu: ['Analysis of Heracles.ts']},
{name: 'Modules', menu: ['Hydra in Depth']},
{name: 'FAQ', menu: ['Some Questions']},
],
Expand Down
178 changes: 178 additions & 0 deletions docs/src/content/conceptual-guides/analysis_heracles.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
---
name: Analysis of Heracles.ts
menu: Conceptual Guides
---

# Analysis of Heracles.ts

HydraClient, known as Heracles.ts, is a generic client for Hydra-powered Web APIs. You can find the code at this repository [here](https://github.com/HydraCG/Heracles.ts). It is the reference implementation of a Hydra client in TypeScript.

## Client Part in Hydra

The basic idea behind Hydra is to provide a vocabulary which enables a server to advertise valid state transitions to a client. A client can then use this information to construct HTTP requests which modify the state of server so that a certain desired goal is achieved. Since all the information about the valid state transitions is exchanged in a machine-processable way at runtime instead of being hardcoded into the client at design time, clients can be decoupled from the server and adept to changes.

Index of Heracles.ts:

- Enumerations
- Classes
- Interfaces
- Type Aliases
- Variables
- Functions
- Object Literals

Enumerations define a set of named constants. For example, `CrawlingDirection` contains members named `backwards` and forwards `defining` possible partial collection view directions. Similarly, Level has members named `FullSupport` and `None` demonstrating Hypermedia support level. FullSupport=100 means exact support of response whereas None=0 means not a supported response. `LinksPolicy` defines various possible link policies.

Classes are a blueprint from which objects are created. Classes used in Heracles.ts are:

The `HydraClientFactory` class provides a factory of HydraClient, meaning HydraClient can be configured and created using this class. By default, JSON-LD hypermedia processor, bodyResourceIRITemplateExpansionStrategy and fetch components are used to initialise HydraClient.

`BodyResourceIRITemplateExpansionStrategy` class provides a simple implementation of `IRITemplateExpansionStrategy` interface where an input resource is used to fill all the possible IRI Templates with values.

An IRI template is a template literal and a set of mappings.

The `MappingsBuilder` Class provides a builder for IRI template variable mapping values. `MappingsCollection` class is an IRI template variable mappings collection.

While requesting for a resource one may construct a query that is known only to the client and that’s where Templated Resources come into picture. The TemplatedResource Class provides the base functionality for resources that has an expandable template. TemplatedLink Class provides a link that can have a URI template. Whereas TemplatedOperation class defines an abstract hydra operation that uses a URI template to point to the target of the request.

The somehow related resources are grouped together in a collection. For eg: `OperationCollection` provides a collection of abstract hydra operations that can be filtered with relevant criteria. Similarly LinkCollection provides a collection of a link that describes another resource and that filtered with relevant criteria. This filtering capability is provided by the `FilterableCollection` Class. The `ResourceFilterableCollection` inherits this basic functionality from `FilterableCollection` Class. Similarly `LinksCollection` and `OperationsCollection` class inherits from the `ResourceFilterableCollection` Class.

The collection can get large and the need of pagination might occur. In Hydra this is achieved via `PartialCollectionView` that may contain links to first, next, previous and last PartialCollectionView. The client will have to crawl through the `PartialCollectionView`. This in, Heracles.ts is achieved by `PartialCollectionCrawler` class. It provides capability of crawling through partial collection views.

The API Documentation consists of all the valid state changes, but chances are that EntryPoint might be missing from the API Documentation. To rectify that Heracles.ts uses `EntryPointCorrectingGraphTransformer`. It tries to correct missing entry point in hydra:ApiDocumentation resource.

Interfaces contain the abstract functions and types. A Class then implements the interface. Interfaces are for classes discussed above are `IApiDocumentation`, `IClass`, `ICollection`, `ICrawlingOptions`, `IHydraClient`, `ILink`, etc.

Type Alias gives a semantic name to the types. It's an alias for a type. For Eg: `Literal` is type alias for union type of string, boolean and number. Similarly `HeaderMatcher` is a type alias for a function of type that takes in header as param and returns boolean. `Hypermedia` is a type alias for functions that take in context and returns Hypermedia Processor.

Variable `dependentTypes` is an array of two strings which helps in checking whether a resource is Hydra independent. Likewise JSONLdContext contains the IRI http://www.w3.org/ns/json-ld#context. `RdfNamespace` as the name suggests contains the IRI http://www.w3.org/1999/02/22-rdf-syntax-ns#.

Several helper functions are used in Heracles.ts. `AddTo` adds an item to the collection. `discoverCollectionsFrom` function finds out collections from given hypermedia. The collection function is used to create mapping of a collection and initialises with default values. `isLink` functions checks whether is type is `hydra:Link` or `hydra:TemplatedLink`. `linksAndOperations` function creates mappings of template, variable, expects, returns, etc with target values.

Object Literals like `hydra` are defined in `namespaces.ts` file it defines the core vocabulary terms. JSONLd Helper contains a `validKeys` method that returns all the valid keys. The `rdf` object defines useful RDF terms. The `rdfs` defined useful RDFS terms.

Load on server and speed can be a limitation for the client. But in [python-hydra-agent](https://github.com/HTTP-APIs/python-hydra-agent) we are discussing mainly how to reduce the load on the server and fast querying from the client. For this we are using Redis to reduce load on the server and we implemented indexing (specially secondary/faceted indexing) of objects and their properties in Redis with a good querying mechanism which makes operations faster and efficient.


### Run Heracles.ts in Browser

Create a project folder and navigate into it.

Make sure you have `node.js` installed. If not, follow the instructions [here](https://nodejs.org/en/download/).

Install typescript.
```bash
npm install -g typescript
```

Run
```bash
npm init --yes
```

Install `browserify`, `tsify` (to bundle JS files), and Heracles.

```bash
npm install browserify tsify @hydra-cg/heracles.ts --save
```

Create a new file `main.ts` and Import Heracles and create a new Instance of the client.
```typescript
//main.ts
import HydraClientFactory from "@hydra-cg/heracles.ts";

let hydraClient = HydraClientFactory.configure().withDefaults().andCreate();
```


Now let's fetch a resource. Anything that can be dereferenced by an IRI can be considered as a resource.

```typescript
//main.ts
const main = async () => {
const resource = await hydraClient.getResource("http://myapi/");
// Do something with resource
}
main();
```

The getResource method returns a HypermediaContainer. To keep things simple, use a Hydra-powered API provided by the server of this ecosystem. Installing and running `hydrus` is pretty straightforward. Follow the instructions [here](https://github.com/HTTP-APIs/hydrus).

Once the server is up and running, its API can be used. To see the results, console the resource.

```typescript
//main.ts
const main = async () => {
const resource = await hydraClient.getResource("http://localhost:8000/api/vocab");
console.log('resource', resource);
}
main();
```

To compile our code into ES2018, run in the terminal:

```bash
tsc --init --target es2018
```

To run npm packages in the browser, they need to be bundled. In the terminal run:

```bash
browserify main.ts -p [ tsify --noImplicitAny ] > bundle.js
```
To run `bundle.js` in the browser, create an HTML file index.html and include that script.
```html
<!--index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>title</title>
</head>
<body>
<h1>Heracles.ts Demo </h1>
</body>
<script src="bundle.js"> </script>
</html>
```
Open the file in the browser and in the console of dev tools you can see the response. It should look like this.

```json
{
"@context": {
"ApiDocumentation": "hydra:ApiDocumentation",
"description": "hydra:description",
"expectsHeader": "hydra:expectsHeader"
...
}​
"@id": "http://localhost:8080/api/vocab"
"@type": "ApiDocumentation"
"description": "API Documentation for the server side system"
​}
```
The client can be customised by choosing which resource relations should be treated as links and exposed in the links property. By calling either

- `.withAllLinks()` - treats all related resources as links

- `.withAllHttpLinks()` - similar as above, but only HTTP(S) URLs will be considered

- `.withSameRootLinks()` - only URLs from the same root of the requested resource will be considered

- `.withStrictLinks()` - this is the default - only links exposed as hydra:link will be considered

```typescript
let hydraClient = HydraClientFactory.configure().withDefaults().withAllLinks().andCreate();
```
By default, JSON-LD serialisation is used, any other serialisations of RDF can be used. This can be achieved by calling either of the functions :

- `.with(component: IHypermediaProcessor)` - accepts a custom implementation of the IHypermediaProcessor interface

- `.withFactory(method: HypermediaProcessorFactory)` - accepts a parameter factory method that will provide the instance as required.


Refs:
- [Hydra Specification](https://www.hydra-cg.com/spec/latest/core/)


- [Heracles.ts Documentation](https://github.com/HydraCG/Heracles.ts/tree/master/docs)
2 changes: 1 addition & 1 deletion docs/src/styles/global.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap");

* {
html {
font-family: "Roboto", sans-serif !important;
}