badgateway/react-ketting

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:

image

evert commented

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.

Thanks, changing it to item totally makes sense - awesome!

image