Still in pre-pre-pre-alpha stages!
In project root directory, run:
$ (sudo) yarn link
$ cd example/client
$ yarn link hateoas-form
Then run the example server:
cd example/server
yarn
yarn start
Then run the example client:
cd example/client
yarn
yarn start
The browser should open the example client automatically.
In project root directory, run:
$ (sudo) yarn link
Then run the library:
yarn watch
Then run the example server:
cd example/server
yarn
yarn watch
Then run the example client:
cd example/client
yarn
yarn start
The browser should open the example client automatically.
import hateoasForm from 'hateoas-form';
const formInstance = hateoasForm({
// An interceptor for fetch. Here, you may override the fetch calls, for instance appending an authorization header.
fetch: function(url, init) {}
});
// Signals to fetch (i.e. GET) the resource from the URL.
// Returns a promise that resolves to the fetched resource.
formInstance.fetchResource(url);
// Triggers an API update on a property. Property name supports dot-separated syntax and brackets for arrays.
// Returns a promise that resolves to the updated resource.
formInstance.setProperty(resource, propertyName, value);
// Updates resource (and potential sub-resources) with the provided set of properties.
// Returns a promise that resolves to the updated resource.
formInstance.setProperties(resource, properties);const formInstance = hateoasForm();
formInstance.fetchResource('http://api.example.com/person/1')
.then(resource => {
console.log('Resource Fetched!', resource);
// Triggers a PATCH call.
return formInstance.setProperty(resource, 'hobbies[0].description', 'Love HATEOAS');
})
.then(updatedResource => {
console.log('Resource Updated!', updatedResource);
// Triggers another PATCH call.
return formInstance.setProperties(resource, { firstName: 'John', lastName: 'Doe' });
})
.then(updatedResource => {
console.log('Resource Updated Again!', updatedResource);
});HATEOAS Form comes with bindings for React. The two components you need to care about are:
HateoasProvidercreateHateoasComponent
This component provides your HATEOAS components with the functionality needed to perform HATEOAS requests. You should mount this component at the root of your React component tree.
hateoasForm(Object) - The instance of a HATEOAS Form, i.e.hateoasForm().
import hateoasForm, { HateoasProvider } from 'hateoas-form';
const hateoasFormInstance = hateoasForm();
ReactDOM.render(
<HateoasProvider hateoasForm={hateoasFormInstance}>
<App />
</HateoasProvider>,
document.getElementById('root'));This is similar to how the React bindings for Redux works. Incidentally, if you need both Redux and HATEOAS functionality, it does not matter which component wraps the other:
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import hateoasForm, { HateoasProvider } from 'hateoas-form';
// Create some store...
// const store = ...;
const hateoasFormInstance = hateoasForm();
ReactDOM.render(
<Provider store={store}>
<HateoasProvider hateoasForm={hateoasFormInstance}>
<App />
</HateoasProvider>
</Provider>,
document.getElementById('root'));This is a Higher Order Component (HOC) that encapsulates your component. Use this HOC when you want your React component to be enhanced with HATEOAS functionality.
// YourResourceComponent.jsx
import { createHateoasComponent } from 'hateoas-form';
const YourHateoasComponent = ({ resource, fetching }) =>
<pre>
{fetching
? 'Fetching Resource...'
: JSON.stringify(resource, null, 4)}
</pre>;
export default createHateoasComponent()(YourHateoasComponent);
// App.jsx
const App = () =>
<YourHateoasComponent url="https://example.api.com/shipments/1" />;
export default App;resolveUrl(props, fetchResource)(Function) - Optional. A function that returns the URL of the resource that you want your component to work with. The HOC also accepts a promise as the return type. In which case, it will expect the promise to resolve with the URL. In most cases, however, it's recommended to pass the URL to the component as a prop. This functionality is useful when your component receives a resource URL, but you ultimately want it to work with a linked resource from that resource URL. To traverse your API, use thefetchResourceargument that is passed to the function.
import { createHateoasComponent } from 'hateoas-form';
const BlogPostCommentsComponent = ({ resource, fetching }) =>
<pre>
{fetching
? 'Fetching Comments...'
: JSON.stringify(resource, null, 4)}
</pre>;
export default createHateoasComponent({
resolveUrl: (props, fetchResource) =>
fetchResource(props.url)
.then(resource => resource._links.comments.href)
})(BlogPostCommentsComponent);
// App.jsx
const App = () =>
<BlogPostCommentsComponent url="https://example.api.com/blog-posts/1" />;
export default App;Your enhanced component receives a set of props from the HOC:
resource(Object|null) - The resource that your HATEOAS component manages, as defined by the provided URL.resourceFormValues(Object|null) - The resource with the links stripped out and the embeddings merged with the resource.rawResource(Object|null) - The resource exactly as that was passed from the backend.fetching(boolean) - Whether the resource is being fetched from the backend.updating(boolean) - Whether the resource is being updated, i.e. sent to the backend.patch(key, value)- A function that proxies to thesetPropertyfunction for your given resource. Can be useful if you want to update a property upon, e.g., clicking a button. For general inputs, consider usingpatchInputinstead.patchAll(values)- A function that proxies to thesetPropertiesfunction for your given resource. Can be useful if you want to update all values in a form when you submit it.patchInput(event)(function) - Accepts a DOM event triggered from an HTML input element that has a name representing the property to patch, and a value with which to patch the property. The function parses the value based on the type of HTML input element that triggered the DOM event, e.g.text,checkbox,number, etc. Typical usage is to set this function as a callback ononBluroronChangeprops oninputelements.patchBooleanInput(event)(function) - The same aspatchInput, but also parses the target value to a boolean value. Use this if you need the value to be parsed to a boolean value from an input element that otherwise is not considered to manage a boolean value, e.g. aselectcomponent.patchNumberInput(event)(function) - The same aspatchInput, but also parses the target value to a number. Use this if you need the value to be parsed to a numerical value from an input element that otherwise is not considered to manage a numerical value, e.g. aselectcomponent.