React + Siren
AlexZeitler opened this issue · 3 comments
I'm trying to render a list of customer
resources in a react app using a Siren
response like this:
import express from 'express'
import cors from 'cors'
export const app = express()
app.use(cors())
const siren = {
class: ['customer', 'collection'],
properties: {
length: 3
},
entities: [
{
class: ['info', 'customer'],
rel: ['http://x.io/rels/customer'],
properties: {
customerId: '123',
name: 'AWS'
},
links: [{ rel: ['self'], href: '/customers/123' }]
},
{
class: ['info', 'customer'],
rel: ['http://x.io/rels/customer'],
properties: {
customerId: '234',
name: 'DigitalOcean'
},
links: [{ rel: ['self'], href: '/customers/234' }]
},
{
class: ['info', 'customer'],
rel: ['http://x.io/rels/customer'],
properties: {
customerId: '345',
name: 'Google'
},
links: [{ rel: ['self'], href: '/customers/345' }]
}
]
}
app.get('/customers', (req, res) => {
res.set('Content-Type', 'application/vnd.siren+json')
return res.status(200).send(siren)
})
This is my react app so far:
import React from "react";
import "./App.css";
import { Client } from "ketting";
import { KettingProvider } from "react-ketting";
import { CustomersView } from "./CustomersView";
const client = new Client("http://localhost:5000/");
function App() {
return (
<KettingProvider client={client}>
<CustomersView></CustomersView>
</KettingProvider>
);
}
export default App;
My CustomersView.tsx
looks like this:
import React from "react";
import { useCollection } from "react-ketting";
export type Customer = {
customerId: string;
name: string;
};
export const CustomersView = () => {
const { loading, error, items } = useCollection<Customer>("/customers");
if (loading) return <p>Loading...</p>;
if (error) return <div className="error">{error.message}</div>;
console.log("items", items);
return <div></div>;
};
The console.log("items", items)
is []`.
How do I get the entities
from the Siren
response to be returned here?
I've updated my CustomersView.tsx
like this:
import React from "react";
import { useCollection } from "react-ketting";
import { CustomerView } from "./CustomerView";
export type Customer = {
customerId: string;
name: string;
};
export const CustomersView = () => {
const { loading, error, items } = useCollection<Customer>("/customers");
if (loading) return <p>Loading...</p>;
if (error) return <div className="error">{error.message}</div>;
console.log("items", items);
return <ul>{items.map(item => <CustomerView resource={item} />)}</ul>
};
I've also added a CustomerView.tsx
:
import { Resource } from "ketting";
import React from "react";
import { useResource } from "react-ketting";
import { Customer } from "./CustomersView";
export function CustomerView({resource}: { resource: Resource<Customer> }) {
const {
loading,
error,
data
} = useResource(resource);
if (loading) return <div>loading...</div>;
if (error) return <div className="error">boo</div>;
return <li>{data.customerId} - {data.name}</li>;
}
This is what KettingProvider
looks like in react developer tools:
Hi!
Thanks for all the great detail.
The way Ketting behaves, is that every relationship is expressed as a web link. In your case, your list of entities have a relationship of http://x.io/rels/customer
to it's collection.
By default, useCollection
will look for the item
rel. To change this, you can tell it to use your own rel:
useCollection<Customer>("/customers", { rel: 'http://x.io/rels/customer');
Semantically speaking though, the rel
should be used to express the relationship type between the parent and sub-entity, so I I would question if the rel http://x.io/rels/customer
is really the most appropriate. What is the relationship between the list of customers and the collection they are in? To me that relationship is item
as defined here:
https://tools.ietf.org/html/rfc6573
Because each customer in this case is not a "customer of the collection", it's just a "member of the customer collection".
Either way, this should solve your problem.