Skip to content
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

Synchronous fromJSON in hal #471

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
6 changes: 6 additions & 0 deletions src/state/base-state.ts
Original file line number Diff line number Diff line change
@@ -226,6 +226,12 @@ export class BaseState<T> extends BaseHeadState implements State<T> {

}

toJSON() {

return this.data;

}

/**
* Certain formats can embed other resources, identified by their
* own URI.
36 changes: 28 additions & 8 deletions src/state/hal.ts
Original file line number Diff line number Diff line change
@@ -11,14 +11,18 @@ import * as hal from 'hal-types';
/**
* Represents a resource state in the HAL format
*/
export class HalState<T = any> extends BaseState<T> {
export class HalState<T extends Record<string, any> = any> extends BaseState<T> {

serializeBody(): string {

return JSON.stringify({
toJSON(): hal.HalResource<T> {
return {
_links: this.serializeLinks(),
...this.data
});
};
}

serializeBody(): string {

return JSON.stringify(this.toJSON());

}

@@ -75,6 +79,22 @@ export const factory:StateFactory = async (client, uri, response): Promise<HalSt

const body = await response.json();
const links = parseLink(uri, response.headers.get('Link'));
const headers = response.headers;

return buildState(client, uri, body, links, headers);

};

export const fromJSON = (client: Client, body: hal.HalResource, uri?: string) : HalState => {

uri = uri || body._links.self.href;
const links = new Links(uri);
const headers = new Headers();
return buildState(client, uri, body, links, headers);

};

export const buildState = (client: Client, uri: string, body: hal.HalResource, links: Links, headers: Headers) : HalState => {

// The HAL factory is also respondible for plain JSON, which might be an
// array.
@@ -83,7 +103,7 @@ export const factory:StateFactory = async (client, uri, response): Promise<HalSt
client,
uri,
data: body,
headers: response.headers,
headers,
links,
});
}
@@ -102,9 +122,9 @@ export const factory:StateFactory = async (client, uri, response): Promise<HalSt
client,
uri: uri,
data: newBody,
headers: response.headers,
headers,
links: links,
embedded: parseHalEmbedded(client, uri, body, response.headers),
embedded: parseHalEmbedded(client, uri, body, headers),
actions: parseHalForms(uri, body),
});

7 changes: 6 additions & 1 deletion src/state/interface.ts
Original file line number Diff line number Diff line change
@@ -77,6 +77,11 @@ export type State<T = any> = {
*/
serializeBody(): Buffer|Blob|string;

/**
* Returns a JSON of the state that can be used in a HTTP response.
*/
toJSON(): any;

/**
* Content-headers are a subset of HTTP headers that related directly
* to the content. The obvious ones are Content-Type.
@@ -116,7 +121,7 @@ export type State<T = any> = {
* Some information in HEAD responses might be available, but many aren't.
* Notably, the body.
*/
export type HeadState = Omit<State, 'data' | 'action' | 'actions' | 'hasAction' | 'serializeBody' | 'getEmbedded' | 'client' | 'clone'>;
export type HeadState = Omit<State, 'data' | 'action' | 'actions' | 'hasAction' | 'serializeBody' | 'toJSON' | 'getEmbedded' | 'client' | 'clone'>;

/**
* A 'StateFactory' is responsible for taking a Fetch Response, and returning
34 changes: 33 additions & 1 deletion test/unit/state/hal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect } from 'chai';
import { factory } from '../../../src/state/hal';
import { factory, fromJSON } from '../../../src/state/hal';
import { Client } from '../../../src';

describe('HAL state factory', () => {
@@ -229,6 +229,38 @@ describe('HAL state factory', () => {
happy: 2020,
});

});
it('should correctly rebuild HAL documents', async() => {

const base = {
_links: {
self: {
href: '/foo',
},
author: {
href: 'https://evertpot.com/',
},
foo: [
{
href: '/bar',
},
{
href: '/bar2',
},
{
href: '/bar3',
},
]
},
happy: 2020,
};
const hal = await callFactory(base, base._links.self.href);
// const json = (hal as HalState).toJSON();
const json = hal.toJSON();
const result = fromJSON(hal.client, json);
expect(result.uri).to.eql(hal.uri);
expect(JSON.parse(result.serializeBody())).to.eql(base);

});
it('should handle JSON documents that are arrays', async () => {