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

Return type of transformResponse on enhanceEndpoints can not differ from original definition in createApi #1441

Closed
bkempe opened this issue Aug 25, 2021 · 6 comments · Fixed by #2953
Labels
enhancement New feature or request rtk-query

Comments

@bkempe
Copy link

bkempe commented Aug 25, 2021

Currently, the return type of transformResponse on enhanceEndpoints has to match the original return type from createApi.
This diminishes the value and ability of enhanceEndpoints:
Often, it is preferred to have client code use different shapes than the ones exposed by an API and transformResponse is the mechanism to do so.
However, once RTK codegen is used, transformResponse should be defined on enhanceEndpoints and not on the (generated) createApi.

Example

Using the enhancedEndpoints example from the docs, this usage of transformResponse currently fails to compile:

getPetById: {
    providesTags: (result, error, arg) => [{type: 'Pet', id: arg.petId}],
    transformResponse: ({id, name, category, photoUrls, tags, status}) => ({id, name}),
},
@harrisj1
Copy link

I just ran into this myself. A bit annoying.

However, I think I understand why this limitation might exist.

Disclaimer: My team uses React hooks, so I don't know much about how enhanceEndpoints might be used elsewhere.

But what I do know, is that enhanceEndpoints does not create new hooks.

The same hooks that get returned from createApi and/or injectEndpoints, are the exact same hooks returned by enhanceEndpoints (tested with ===).

e.g. if a React component imports a useQuery hook from the createApi call, and a different module later calls enhanceEndpoints, the existing useQuery hook will be affected.

Therefore, changing the return type of transformResponse would require that the types within the existing hooks get updated as well, which is impossible especially across modules.

The only way that a change of return type would be realistically possible, would be if enhanceEndpoints just returned a whole new api object with new, separate hooks and whatnot.

But that sounds really complicated and potentially confusing to use.

@phryneas
Copy link
Member

It is theoretically possible, but depending on what file you import from you will get things of different types - and enhanceEndpoints does not create a new instance, but changes the original instance, but cannot change it's types, so you'd have multiple versions of the same api with the same (enhanced) behaviour, but very different types.

So we kinda stayed away from it for now. But I understand the use and I will take another look into it, given the time.

@phryneas phryneas added the enhancement New feature or request label Aug 26, 2021
@quodlibetor
Copy link

(Thanks for rtkq, I'm transitioning some code to it now and it's amazing.)

I don't know if one of the things that's holding this up is lack of ideas for how to make it ergonomic, but in case that is the issue I have an idea that might work as a jumping off point for brainstorming.

In the OpenAPI context -- which is where I think of this coming up the most -- would it be possible to handle this by treating the enhancing api as an intermediate phase specified in config, changing the way that code generation ends up?

What I'm imagining is that where right now the outputFile contains the result of injectEndpoints its types, and all the hook exports, you could just generate another file that has all the modified types and use statements.

I can imagine that if a user specifies a trio of new enhance* fields it might be possible to make make this work pretty well.

As a walkthrough of the simple case of only one input file:

Where right now you specify:

const config = {
    schemaFile: "...",
    apiFile: "empty.ts",
    apiImport: "empty",
    outputFile: "api.ts",
}

You could add enhanceInputFile, enhanceFile, enhanceImport:

const config = {
    schemaFile: "...",
    apiFile: "empty.ts",
    apiImport: "empty",
    enhanceInputFile: "middle.ts", // <-- new
    enhanceInputExport: "middle",  // <-- new
    enhanceFile: "enhance.ts",     // <-- new
    enhanceImport: "enhance",      // <-- new
    outputFile: "api.ts"
}

The openapi-codegen program then generates the enhanceInputFile looks exactly like the current outputFile except it does not include any of the use* reexports. This is mostly just to make it more clear that it should not be used by itself.

After that, the enhanceFile contains either an middle.enhanceEndpoints or some new api that returns a new object. This file is written by humans who would like to provide transforms/etc.

Then, the openapi codegen reads this new file, does magic with types -- or just requires that all types be defined explicitly in the middle file -- and outputs basically a duplicate of the inhanceInputFile but with fully correct types.

Does that seem... possible?

@Hypnosphi
Copy link

Hypnosphi commented Jun 30, 2022

It is theoretically possible, but depending on what file you import from you will get things of different types - and enhanceEndpoints does not create a new instance, but changes the original instance, but cannot change it's types, so you'd have multiple versions of the same api with the same (enhanced) behaviour, but very different types.

That's no problem for me personally, as I'm only going to import from the enhancedApi file (and maybe even enforce it with eslint or something)

Anyway, you still change the api instance type in terms of tags, so I don't see why not in terms of return types
https://github.com/reduxjs/redux-toolkit/blob/master/packages/toolkit/src/query/apiTypes.ts#L110

@phryneas
Copy link
Member

If you want to open a PR to it, I'd be open for it. I just don't have the time to work on that at the moment.

@misterjame
Copy link

+1

I am using codegen for GraphQL queries and would like transform the result.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request rtk-query
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants