Skip to content
This repository has been archived by the owner on Oct 7, 2021. It is now read-only.

Commit

Permalink
fix(#32): Add support of array of link
Browse files Browse the repository at this point in the history
- links can not be array
- upgrade documentation

close #32
  • Loading branch information
deblockt committed Dec 11, 2018
2 parents c5b637e + 6d14034 commit 00960d8
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 26 deletions.
65 changes: 49 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ halResource.uri.uri // get the uri provided from server
halResource.uri.fill({params: "test"}) // fill the templated uri with given parameters
```

## how to use
## How to use

The library provide two access method :
1. use generic object `HalResource` to map service return
Expand All @@ -48,7 +48,7 @@ const client = createClient();
const client = createClient("http://exemple.com/api");
```

to get a resource, you can use fetchResource method.
To get a resource, you can use fetchResource method.

``` ts
const resource = await client.fetchResource("http://exemple.com/api/resources/5")
Expand All @@ -64,39 +64,72 @@ const resourceURI = resource.uri;
```
for a link, on `link` service return
```ts
const linkValue = resource.prop("link_name");
const link = resource.prop("link_name");
// or
const linkValue = resource.link("link_name");
const link = resource.link("link_name");
```
> link attribute type is `HalResource`
#### Follow a link

links are made to be followed. So you can simply fetch a link using `fetch` method.
Links are made to be followed. So you can simply fetch a link using `fetch` method.
``` ts
const linkValue = resource.link("link_name");
await linkValue.fetch();
const name = linkValue.prop("name");

const link = resource.link("link_name");
await link.fetch();
const name = link.prop("name");
```

Note that `link()` returns an empty `HalResource` with its `uri` set. You need to call `fetch()` to populate the HalResource.

The library also supports arrays of links using Array syntax:

```ts
const link = resource.link("link_name")[0];
await link.fetch();
const name = link.prop("name");
```
> link return an empty `HalResource`, just `uri` is setted. `fetch` populate the HalResource.

#### Follow a templated link

If you link is templated, you can set parameter to fetch to compute fetch URL.
```ts
// link "link_name" is a templated link like this
// /bookings{?projection}
const linkValue = resource.link("link_name");
const bookings = await linkValue.fetch(); // fetch /bookings
const bookingsWithName = await linkValue.fetch({projection : "name"}); // fetch /bookings?projection=name
const link = resource.link("link_name");
const bookings = await link.fetch(); // fetch /bookings
const bookingsWithName = await link.fetch({projection : "name"}); // fetch /bookings?projection=name
```
```ts
// link "link_infos" is like this
// /infos{/path*}
const linkValue = resource.link("link_infos");
const infos = await linkValue.fetch(); // fetch /infos
const infosForFoo = await linkValue.fetch({path: "foo"});
const link = resource.link("link_infos");
const infos = await link.fetch(); // fetch /infos
const infosForFoo = await link.fetch({path: "foo"});
```


#### Links as props

Note that named links are synonymous with props:

```ts
const link = resource.link("link_name");
const prop = resource.prop("link_name");
link === prop // true
```

This means you can navigate a HAL hierarchy (referencing and fetching) using props alone:

```ts
// using .prop()
const foo = await resource.prop("foo").fetch();
const bar = await foo.prop("bar").fetch();

// using .links
bar.props === resource.links.foo.links.bar.props // true
```

#### Update a resource

Resource can be updated, an save with a PATCH query.
Expand Down Expand Up @@ -182,7 +215,7 @@ const resource = await client.fetch("/resource/5", Resource);
```
> fetch return a promise. you can use `then` and `catch` to get result. Otherwise you can use `await` see [this article](https://blog.mariusschulz.com/2016/12/09/typescript-2-1-async-await-for-es3-es5)
read props is simply call object attributs.
Read props is simply call object attributes.
``` ts
const name = resource.name;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hal-rest-client",
"author": "Thomas Deblock <deblock.thomas.62@gmail.com>",
"version": "0.3.4",
"version": "0.4.0",
"description": "Hal rest client for typescript",
"tags": [
"HAL",
Expand Down
22 changes: 15 additions & 7 deletions src/hal-json-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,27 @@ export class JSONParser {
// get translation between hal-service-name and name on ts class
const halToTs = Reflect.getMetadata("halClient:halToTs", c.prototype) || {};

const processLink = (link, type) => {
const href = this.extractURI(link);
const linkResource = createResource(this.halRestClient, type, href);
for (const propKey of Object.keys(link)) {
linkResource.prop(propKey, link[propKey]);
}
return linkResource;
};

for (const key in json) {
if ("_links" === key) {
const links = json._links;
for (const linkKey in json._links) {
if ("self" !== linkKey) {
const href = this.extractURI(links[linkKey]);
const type = Reflect.getMetadata("halClient:specificType", c.prototype, linkKey) || HalResource;
const type = Reflect.getMetadata("halClient:specificType", c.prototype, linkKey) || HalResource;
const propKey = halToTs[linkKey] || linkKey;
const linkResource = createResource(this.halRestClient, type, href);
for (const propInLinkKey of Object.keys(links[linkKey])) {
linkResource.prop(propInLinkKey, links[linkKey][propInLinkKey]);
}
resource.link(propKey, linkResource);
const link = links[linkKey];
const result = Array.isArray(link)
? link.map((item) => processLink(item, type))
: processLink(link, type);
resource.link(propKey, result);
}
}
if (links.self) {
Expand Down
2 changes: 1 addition & 1 deletion src/hal-resource-interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export interface IHalResource {
* @param name : the link name
* @param value : the new resource. If you want reset a link use null and not undefined
*/
link(name: string, value ?: IHalResource): IHalResource;
link(name: string, value ?: any): any;

/**
* function called when object is populated
Expand Down
2 changes: 1 addition & 1 deletion src/hal-resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class HalResource implements IHalResource {
/**
* to clear value use null not undefined
*/
public link(name: string, value ?: IHalResource): HalResource {
public link(name: string, value ?: any): any {
if (value !== void 0) {
this.links[name] = value;
if (this.initEnded) {
Expand Down
58 changes: 58 additions & 0 deletions src/test/test-issue-32.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { test } from "tape-async";

import { createClient, HalResource, resetCache } from "../";

import * as nock from "nock";

// mock list response
function initTests() {
nock.cleanAll();
resetCache();
const project1 = {
_links: {
related: [
{ href: "http://test.fr/projects/1" },
{ href: "http://test.fr/projects/2" },
{ href: "http://test.fr/projects/3" },
],
self: {
href: "http://test.fr/projects/1",
},
},
test: "test",
};

const project2 = {
_links: {
self: {
href: "http://test.fr/projects/2",
},
},
};

const testNock = nock("http://test.fr/");

testNock
.get("/projects/1")
.reply(200, project1);

testNock
.get("/projects/2")
.reply(200, project2);
}

test("list of links are resources", async (t) => {
initTests();
const project = await createClient().fetch("http://test.fr/projects/1", HalResource);
const related = project.link("related");
t.equals(Array.isArray(related), true);
t.equals(related.every((item) => item instanceof HalResource), true);
});

test("list links can be fetched", async (t) => {
initTests();
const project = await createClient().fetch("http://test.fr/projects/1", HalResource);
const related = project.link("related");
await related[0].fetch();
t.equals(related[0].prop("test"), "test");
});

0 comments on commit 00960d8

Please sign in to comment.