Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typed relations #464

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

remidewitte
Copy link

It is very convenient to type relations when we follow links.

@evert
Copy link
Collaborator

evert commented Mar 16, 2023

Hey, generally a good idea. Been sitting on this a bit. The feature I really want is something like this:

type Article = State< { title: string}, {
    author: Author
}>;

The idea here is that if I later on have a Resource

, and I call await article.follow('author');, Typescript would know that I got a Resource<Author> as a result.

A next step after that is that we can start writing an OpenAPI-like document that lets us generate types and understand what kind of resources we are getting as we're traversing the graph.

So this PR is a step in the right direction I think, but there's a lot more to be done, I don't want to introduce this and potentially alter it after.

P.S. If you ever want to chat, I'm on matrix: @evert:badgateway.net and we could do a ketting room =)

@remidewitte
Copy link
Author

Thanks for your answer. Let me add a bit more context !

What we (Synako) really use is a hook like this. I would be happy to make a PR as well to react-ketting :

export interface UseResourceResponse<T, L extends string = never> {
    useFollow: <TFollow, LFollow extends string = never>(rel: L, variables?: Partial<LinkVariables>) => UseResourceResponse<TFollow, LFollow>;
    useFollowCollection: <TFollow>(rel: L, variables?: Partial<LinkVariables>, options?: UseCollectionOptions) => UseCollectionResponse<TFollow>;
    useFollowAll: <TFollow>(rel: L, variables?: Partial<LinkVariables>) => UseResourcesResponse<TFollow>;
    deleteResource: () => Promise<void>;
    loading: boolean;
    error: Error | null;
    resource: Resource<T>;
    data?: T;
    links?: Links<L>;
}

export default function useResource<T, L extends string = never>(
    resourceLike: RootRels | Resource<T> | FollowPromiseOne<T> | State<T>,
    variables?: Partial<LinkVariables>,
    options?: UseResourceOptions<T>,
): UseResourceResponse<T, L> {

... implementation based on useReadResource...

}

Which results in the usage with :

const {data: article, useFollow} = useResource<Article, links.Article>(resourceLike);
const {data: author, useFollowCollection} = useFollow<Author, links.Author>('author');
const {items: otherArticles} = useFollowCollection<Article>('other_articles');

where ...

interface Article {
 ...
}
interface Author {
 ...
}
export namespace links {
  export type Article = 'author' | 'section';
  export type Author = 'other_articles' | 'belongs_to';
}

We derive all types from OpenAPI schema :

  • State data interfaces T in State<T>
  • Link names by state Rels in State<T, Rels>
    Example :
title: Article
type: object
properties:
  title:
    type: string
  _links:
    type: object
    properties:
      author:
        $ref: ../util/link.yaml
      section:
        $ref: ../util/link.yaml

What we really miss is a ketting native way for type-safe links to avoid typos while we traverse the graph. We have not found a way yet to explain in OpenAPI the target type of a link but we don't really suffer from this as it is quite easy to get the target type thanks to auto-completion.

We have found the approach to be very flexible and especially opt-in.

I'll try to think a bit more about you really want !

@evert
Copy link
Collaborator

evert commented Mar 16, 2023

Cool, based on this I think the feature I would like would still work for your use-case. I hope I can spend some time of this soon. I would feel bad if you did a bunch of work but it doesn't fit with the goals i have for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants