Skip to content

Commit b65699e

Browse files
Update documentation with new state management store features (#61)
* Created new drawing depicting the state flow in the library * Updated getting started guide with new features * Added documentation for loading features with small api improvements * Updated documentation for new and changed functionality * fixes on documentation build --------- Co-authored-by: Daniel Murrmann <9040811+fancyDevelopment@users.noreply.github.com>
1 parent fab5bf5 commit b65699e

27 files changed

Lines changed: 4635 additions & 2642 deletions

.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
- name: Install Node
2525
uses: actions/setup-node@v4
2626
with:
27-
node-version: 20.x
27+
node-version: 22.x
2828

2929
# Restore dependencies
3030
- name: Restore dependencies for lib

.github/workflows/ngrx-hateoas.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ jobs:
1515
- name: Install Node
1616
uses: actions/setup-node@v4
1717
with:
18-
node-version: 20.x
18+
node-version: 22.x
1919

2020
# Restore dependencies
2121
- name: Restore dependencies

apps/playground/src/app/core/core.routes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ export const CORE_ROUTES: Routes = [{
1111
}, {
1212
path: 'home',
1313
component: HomeComponent,
14-
canActivate: [ () => whenTrue(inject(HomeStore).homeVmState.initiallyLoaded) ]
14+
canActivate: [ () => whenTrue(inject(HomeStore).homeVmState.isLoaded) ]
1515
}];

apps/playground/src/app/flight/flight.routes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ export const FLIHGT_ROUTES: Routes = [{
2828
}, {
2929
path: "create",
3030
component: FlightCreateComponent,
31-
canActivate: [() => whenTrue(inject(FlightCreateStore).flightCreateVmState.initiallyLoaded)]
31+
canActivate: [() => whenTrue(inject(FlightCreateStore).flightCreateVmState.isLoaded)]
3232
}];

doc/docs/guide/01-getting-started.md

Lines changed: 218 additions & 125 deletions
Large diffs are not rendered by default.

doc/docs/guide/02-concept.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ You don't need to follow the exact same layout as in the example to embed metada
8686

8787
## What is HATEOAS?
8888

89-
HATEOAS (Hypermedia as the Engine of Application State) is an architectural paradigm that allows clients to dynamically navigate resources through hyperlinks provided in responses. Possible state changes are provided via actions. Hyperlinks and actions are metadata sent next to the actual payload. Instead of hardcoding API endpoints, clients rely on these links to discover available actions and related resources. For example, if a user is not allowed to navigate to a linked resource or execute an action, the server would not send this metainformation to the client within its response. Finally, the client has the full state of the resource available, the actual payload, and information to related data and possible actions (or state changes). This approach decouples the client from the server, keeps domain logic away from the client and enables more flexible and evolvable APIs.
89+
HATEOAS (Hypermedia as the Engine of Application State) is an architectural paradigm that allows clients to dynamically navigate resources through hyperlinks provided in responses. Possible state changes are provided via actions. Hyperlinks and actions are metadata sent next to the actual payload. Instead of hardcoding API endpoints, clients rely on these links to discover available actions and related resources. For example, if a user is not allowed to navigate to a linked resource or execute an action, the server would not send this metainformation to the client within its response. Finally, the client has the full state of the resource available, the actual payload and information to related data and possible actions (or state changes). This approach decouples the client from the server, keeps domain logic away from the client and enables more flexible and evolvable APIs.
9090

9191
## Hypermedia at the Backend
9292
To create hypermedia responses you can use community libraries for the different technologies:

doc/docs/guide/configuration/01-metadata-provider.md renamed to doc/docs/guide/03-configuration/01-metadata-provider.md

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ To use a custom hypermedia JSON format with **ngrx-hateoas** you have to impleme
6767
export interface MetadataProvider {
6868
isMetadataKey(keyName: string): boolean;
6969
linkLookup(resource: unknown, linkName: string): ResourceLink | undefined;
70+
getAllLinks(resource: unknown): ResourceLink[];
7071
actionLookup(resource: unknown, actionName: string): ResourceAction | undefined;
72+
getAllActions(resource: unknown): ResourceAction[];
7173
socketLookup(resource: unknown, socketName: string): ResourceSocket | undefined;
74+
getAllSockets(resource: unknown): ResourceSocket[];
7275
}
7376
```
7477

@@ -94,7 +97,7 @@ Lets imagine our hypermedia JSON looks like the following:
9497
"_metadata": {
9598
"_link_aLinkToAResource": { "href": "/api/..." },
9699
"_action_anActionOnSubobject": { "href": "/api/...", "verb": "PUT" },
97-
"_sockets_aSocketForSubobject": { "href": "/api/...", "event": "newMessageForSubobject" }
100+
"_socket_aSocketForSubobject": { "href": "/api/...", "event": "newMessageForSubobject" }
98101
}
99102
},
100103
"_metadata": {
@@ -115,15 +118,39 @@ const customMetadataProvider: MetadataProvider = {
115118
linkLookup(resource: unknown, linkName: string): ResourceLink | undefined {
116119
return resource['_metadata']?.['_link_' + linkName];
117120
},
121+
getAllLinks(resource: unknown): ResourceLink[]; {
122+
const linksMetadata = resource['_metadata'];
123+
if(!linksMetadata) return [];
124+
return Object.keys(linksMetadata)
125+
.filter(key => key.startsWith('_link_'))
126+
.map(key => linksMetadata[key]);
127+
},
118128
actionLookup(resource: unknown, actionName: string): ResourceAction | undefined {
119129
const actionMetadata = resource['_metadata']?.['_action_' + actionName];
120130
// ResourceAction has the two keys href and method,
121131
// therefore we have to bring the metadata into the correct format
122132
if(actionMetadata) return { href: actionMetadata.href, method: actionMetadata.verb };
123133
else return undefined;
124134
},
135+
getAllActions(resource: unknown): ResourceAction[] {
136+
const actionsMetadata = resource['_metadata'];
137+
if(!actionsMetadata) return [];
138+
return Object.keys(actionsMetadata)
139+
.filter(key => key.startsWith('_action_'))
140+
.map(key => {
141+
const actionMetadata = actionsMetadata[key];
142+
return { href: actionMetadata.href, method: actionMetadata.verb };
143+
});
144+
},
125145
socketLookup(resource: unknown, socketName: string): ResourceSocket | undefined {
126146
return resource['_metadata']?.['_socket_' + socketName];
147+
},
148+
getAllSockets(resource: unknown): ResourceSocket[] {
149+
const socketsMetadata = resource['_metadata'];
150+
if(!socketsMetadata) return [];
151+
return Object.keys(socketsMetadata)
152+
.filter(key => key.startsWith('_socket_'))
153+
.map(key => socketsMetadata[key]);
127154
}
128155
}
129156
```
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)