ketting icon indicating copy to clipboard operation
ketting copied to clipboard

Ketting 9 and beyond

Open evert opened this issue 7 months ago • 0 comments

I just wanted to leave a rough draft of the plans for Ketting 9. The plan for Ketting 9 is to fix several long standing issues and API inconsistencies that have been annoying me and others for years.

Allow relationships to be typed.

Right now resources can be typed, and you can specify what type you expect when you follow() a link, like this:

const article: Resource<Article> = client.go('/article/1');
const author = await article.follow<Author>('author');

That works fine, but the drawback with this is that it's up to the user to specify 'Author'. It would be nicer if the type system could express something like

If a user follows the author link on a Resource<Article>, they will get a Resource<Author>`.

That work is underway, and this will be done with a major BC break.

Roughly future types for resource will look something like this:

type AuthorSchema = {
  properties: {
    name: string;
    email: string;
  }
}

type ArticleSchema = {
  properties: {
    name: string;
    email: string;
  }
  links: {
    author: Author;
  }
}

In the future you could then do:

const article: Resource<ArticleSchema> = client.go('/article/1');
const author = await article.follow('author');

And now author would be inferred as a Resource<AuthorSchema>

Fluid interface improvements

Details of the issues can be read in #492.

The broad solution for this is that in the future the Resource can be in 2 possible states:

  • It knows its own URL.
  • It does not know its own URL.

Effectively all resources will operate in a 'lazy' way, and following a resource as such:

const foo = res1.follow('a').follow('b').follow('c');

Will give you a resource and does not need to be awaited. But when it becomes important to do something with foo, only then all the intermediate hops will be resolved:

const result = await foo.get();

Since Ketting supports actions, this would also work:

const foo = await res1
  .follow('a')
  .follow('b')
  .follow('c')
  .submit('action', 'parameters');

But lastly what we would also want is that if you submitted an action, the result of that is also a lazy resource again, so it can be further followed:

const foo = await res1
  .follow('a')
  .follow('b')
  .follow('c')
  .submit('create', 'parameters')
  .follow()
  .get();

Both 'submit' and 'get' are actions that fire off resolving the graph.

Ignoring missing links

In #478 it was asked to allow quiet errors if links are missing. I think with this pattern, it's possible to end .follow() chain with:

const foo = await res1
  .follow('a')
  .follow('b')
  .catch( err => {
    // handle or ignore error
  });

This will be a valid solution to #478 i think.

The internal changes to make both happen are pretty dramatic, so this is probably going to lean to 'complete rewrite' that has strong inspiration from Ketting 8.

evert avatar May 31 '25 23:05 evert