Skip to content

Fix empty object required 2nd param #1366

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

Merged
merged 1 commit into from
Oct 5, 2023
Merged

Fix empty object required 2nd param #1366

merged 1 commit into from
Oct 5, 2023

Conversation

drwpow
Copy link
Contributor

@drwpow drwpow commented Oct 5, 2023

Changes

Fixes the elusive/annoying #1127. Now, rather than .GET('/url', {}) being required, you can just write .GET('/url'). Minor QoL improvement, but very important fix!

How to Review

Tests should pass.

Checklist

  • Unit tests updated
  • docs/ updated (if necessary)
  • pnpm run update:examples run (only applicable for openapi-typescript)

@changeset-bot
Copy link

changeset-bot bot commented Oct 5, 2023

🦋 Changeset detected

Latest commit: 5310b1b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
openapi-fetch Patch
openapi-typescript-helpers Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Oct 5, 2023

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: 5310b1b
Status: ✅  Deploy successful!
Preview URL: https://99f038b7.openapi-ts.pages.dev
Branch Preview URL: https://fix-optional-param.openapi-ts.pages.dev

View logs

@@ -48,7 +48,7 @@ describe("client", () => {

// data
mockFetchOnce({ status: 200, body: JSON.stringify(["one", "two", "three"]) });
const dataRes = await client.GET("/string-array", {});
const dataRes = await client.GET("/string-array");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: the removal of all , {}) in the test suite is a good sign. The test suite has quite a few // @ts-expect-error comments which are vital to testing the type assertions.

But in addition, the test suite also has runtime tests to ensure the function is behaving as-expected. The fact that no tests were modified, while still passing, is a great sign.

@drwpow drwpow force-pushed the fix-optional-param branch from 4223436 to 5310b1b Compare October 5, 2023 22:25
async GET<P extends PathsWithMethod<Paths, "get">>(url: P, init: FetchOptions<FilterKeys<Paths[P], "get">>) {
return coreFetch<P, "get">(url, { ...init, method: "GET" } as any);
async GET<P extends GetPaths>(url: P, ...init: HasRequiredKeys<GetFetchOptions<P>> extends never ? [GetFetchOptions<P>?] : [GetFetchOptions<P>]) {
return coreFetch<P, "get">(url, { ...init[0], method: "GET" } as any);
Copy link
Contributor Author

@drwpow drwpow Oct 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix was weird, and not straightforward. Essentially, it involved multiple complicated steps:

  1. First, convert the function parameters into an array (...init) (though for simplicity, we can do this starting at the 2nd param, rather than having to do it for the full spread)
  2. Next, we’ll need to take each method’s individual FetchOptions and introspect whether it has a single required key. (we needed to create a helper for this)
  3. Lastly, expand the parameter array into a tuple type, marking it either optional ([T?]) or not ([T]) based on the result of the previous step

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, all of this is very annoying, very strange TypeScript introspection. But that’s the name of the game here, so it’s all worth it… I guess.

@@ -145,8 +166,8 @@ export function defaultBodySerializer<T>(body: T): string {
}

/** Construct URL string from baseUrl and handle path and query params */
export function createFinalURL<O>(url: string, options: { baseUrl?: string; params: { query?: Record<string, unknown>; path?: Record<string, unknown> }; querySerializer: QuerySerializer<O> }): string {
let finalURL = `${options.baseUrl ? options.baseUrl.replace(TRAILING_SLASH_RE, "") : ""}${url as string}`;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small micro-optimization: we don’t need to be running a dynamic RegEx to remove a trailing slash. It’s much more performant to just remove a single character if needed (done above on createClient(), also to save cycles on running a RegEx every request

@drwpow drwpow merged commit 04dbd6d into main Oct 5, 2023
@drwpow drwpow deleted the fix-optional-param branch October 5, 2023 22:28
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.

1 participant