Skip to content

Support more type of request body #1123

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

Closed
1 task done
KotoriK opened this issue Apr 20, 2023 · 17 comments · Fixed by #1189
Closed
1 task done

Support more type of request body #1123

KotoriK opened this issue Apr 20, 2023 · 17 comments · Fixed by #1189
Labels
enhancement New feature or request openapi-fetch Relevant to the openapi-fetch library PRs welcome PRs are welcome to solve this issue!

Comments

@KotoriK
Copy link

KotoriK commented Apr 20, 2023

Description

Currently request body that is not encoded as string will be serialize to JSON https://github.com/drwpow/openapi-fetch/blob/fabfad203c326c91d7a3107f43ab3e5be95bc4f1/src/index.ts#L130
However JSON is not the only citizen, binary data and FormData are also widely used in practice.

Proposal
Improve type check, pass these objects as is:

  • ArrayBuffer
  • TypedArray
  • DataView
  • Blob and File
  • URLSearchParams
  • FormData

(list from https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body)

Checklist

@KotoriK KotoriK added enhancement New feature or request PRs welcome PRs are welcome to solve this issue! labels Apr 20, 2023
@rojvv
Copy link

rojvv commented Apr 24, 2023

Any updates?

@drwpow
Copy link
Contributor

drwpow commented May 1, 2023

I think this is easily-doable and a good idea. Thank you for being willing to open a PR! But I’d be happy to tackle this myself in a future release. The types are still changing rapidly and it may not be clear right this moment how to implement this. But the types will settle relatively soon, and contributions will be easier in the near future.

@drwpow
Copy link
Contributor

drwpow commented May 6, 2023

So I’m actually starting to second-guess this feature request. While, yes, sometimes OpenAPI specs have endpoints that return non-JSON-y things like file downloads, it also is not too common. Further, there’s not really much benefit this library can provide when it comes to non-JSON objects.

Put another way, all this library would be doing for you would be checking the URL. Which I personally would never install an npm package just to tell me my URLs are right or wrong. So if we do support this, it would be minimal support. Which would also make sense considering things like ArrayBuffer vs Blob vs TypedArray can’t really be represented in an OpenAPI schema. Those aren’t MIME types; those are what you choose to do (or not to do) at runtime.

I’d probably lean towards this library simply returning unknown whenever it hits a non-JSON-like response and leaves you to handle the rest.

@KotoriK
Copy link
Author

KotoriK commented May 12, 2023

So I’m actually starting to second-guess this feature request. While, yes, sometimes OpenAPI specs have endpoints that return non-JSON-y things like file downloads, it also is not too common. Further, there’s not really much benefit this library can provide when it comes to non-JSON objects.

Put another way, all this library would be doing for you would be checking the URL. Which I personally would never install an npm package just to tell me my URLs are right or wrong. So if we do support this, it would be minimal support. Which would also make sense considering things like ArrayBuffer vs Blob vs TypedArray can’t really be represented in an OpenAPI schema. Those aren’t MIME types; those are what you choose to do (or not to do) at runtime.

I’d probably lean towards this library simply returning unknown whenever it hits a non-JSON-like response and leaves you to handle the rest.

I agree with you. However this library may do more than validating urls, bodies, params can also be checked. The minimal request is not to treat every response body as JSON.

@drwpow drwpow transferred this issue from drwpow/openapi-fetch May 22, 2023
@drwpow drwpow added the openapi-fetch Relevant to the openapi-fetch library label May 22, 2023
@matthewvolk
Copy link

👋 Thanks for all the work you put into this package, @drwpow - this is an exceptionally useful library!

I wanted to ask if I could clarify your point below:

So I’m actually starting to second-guess this feature request. While, yes, sometimes OpenAPI specs have endpoints that return non-JSON-y things like file downloads, it also is not too common. Further, there’s not really much benefit this library can provide when it comes to non-JSON objects.

I was thinking the original question was focused more on non-JSON request bodies? Your reply is more focused on response bodies...

For example, I have a spec file that defines the following request body:

requestBody:
  content:
    multipart/form-data:
      schema:
        type: object
        properties:
          image_file:
            type: string
            format: binary

The typescript interface generated from openapi-typescript turns that into:

requestBody: {
  content: {
    'multipart/form-data': {
      /** Format: binary */
      image_file?: string;
    };
  };
};

But ultimately at build-time, body is typed as undefined:
Screenshot 2023-06-13 at 8 26 51 PM

The API endpoint I'm trying to hit requires me to send a FormData object. Unfortunately, casting FormData as as unknown as undefined doesn't work either, because at runtime it is serialized into a JSON string by: https://github.com/drwpow/openapi-fetch/blob/fabfad203c326c91d7a3107f43ab3e5be95bc4f1/src/index.ts#L130

Personally, I'm a huge fan of "Improve type check, pass these objects as is" in regard to passing other types of data (not just JSON) to request bodies, like @KotoriK originally mentioned.

Maybe I'm totally misunderstanding the thread... but regardless, if you're open to allowing request bodies of types other than just JSON, I'd be more than happy to contribute to help get that done!

@qqilihq
Copy link

qqilihq commented Jun 14, 2023

We're in the same boat as @matthewvolk - the example given is actually great, thank you! We have a very similar scenario: Multipart endpoints which contain a file property in the request body. From what I can see, this would require two additions:

  • handling of multipart/form-data in openapi-fetch (i.e. appropriate treatment of beside the current json content type and serializing them via FormData)
  • allowing to customize the mapping which is generated by openapi-typescript (I would expect a Blob instead of string).

@drwpow
Copy link
Contributor

drwpow commented Jun 16, 2023

v0.3.0 introduces the parseAs option which lets you override the default JSON parsing. This should cover most cases.

Also see the PR notes for more context on why this approach was taken.

This should take care of this issue, but please let me know if any details are missing still.

@drwpow drwpow closed this as completed Jun 16, 2023
@qqilihq
Copy link

qqilihq commented Jun 16, 2023

@drwpow Thank you for that - as far as I can see from the release notes this covers only the response direction though, right?

Another common scenario seems to be request bodies with non-JSON content, like in @matthewvolk's example, such as a request which contains a file Blob to be sent within a multipart request.

@drwpow drwpow reopened this Jun 16, 2023
@drwpow
Copy link
Contributor

drwpow commented Jun 16, 2023

Ah thank you—I did have another item to track more flexible handling of requests. But I don’t have another issue for that, so I can use this one.

psychedelicious added a commit to invoke-ai/InvokeAI that referenced this issue Jun 23, 2023
`openapi-fetch` does not handle non-JSON `body`s, always stringifying them, and sets the `content-type` to `application/json`.

The patch here does two things:
- Do not stringify `body` if it is one of the types that should not be stringified (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body)
- Do not add `content-type: application/json` unless it really is stringified JSON.

Upstream issue: openapi-ts/openapi-typescript#1123

I'm not a bit lost on fixing the types and adding tests, so not raising a PR upstream.
@psychedelicious
Copy link
Contributor

I had a go at fixing this but the types and tests are a bit beyond me, so I'm not submitting a PR - just applied the fix via patch-package.

Thanks for your work on this library!

psychedelicious added a commit to invoke-ai/InvokeAI that referenced this issue Jun 24, 2023
`openapi-fetch` does not handle non-JSON `body`s, always stringifying them, and sets the `content-type` to `application/json`.

The patch here does two things:
- Do not stringify `body` if it is one of the types that should not be stringified (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body)
- Do not add `content-type: application/json` unless it really is stringified JSON.

Upstream issue: openapi-ts/openapi-typescript#1123

I'm not a bit lost on fixing the types and adding tests, so not raising a PR upstream.
psychedelicious added a commit to invoke-ai/InvokeAI that referenced this issue Jun 24, 2023
`openapi-fetch` does not handle non-JSON `body`s, always stringifying them, and sets the `content-type` to `application/json`.

The patch here does two things:
- Do not stringify `body` if it is one of the types that should not be stringified (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#body)
- Do not add `content-type: application/json` unless it really is stringified JSON.

Upstream issue: openapi-ts/openapi-typescript#1123

I'm not a bit lost on fixing the types and adding tests, so not raising a PR upstream.
@jiroscripts
Copy link

I started to write a PR when I realised I can use the bodySerializer option as you can see in this sample test: https://github.com/drwpow/openapi-typescript/blob/main/packages/openapi-fetch/src/index.test.ts#L274-L291

@qqilihq
Copy link

qqilihq commented Jun 28, 2023

@drwpow Thank you for this - looking forward to give it a try!

@nilsso
Copy link

nilsso commented Jun 30, 2023

The newly added serializeBody is just about working for me, but the multipart boundary isn't getting set in headers.

@psychedelicious
Copy link
Contributor

psychedelicious commented Jul 1, 2023

The content type should not be manually set for formData - the browser sets it automatically. Wonder if that's the issue.

@nilsso
Copy link

nilsso commented Jul 1, 2023

I should have said that I don't set it (and maybe I should have posted some code)

const { post } = createClient<paths>({
  baseUrl: 'http://localhost:8000/',
  mode: 'cors',
})

const foo: string
const upload_file: File

await post('/levy-upload', {
  body: {
    foo,
    upload_file,
  },
  bodySerializer (body) {
    const fd = new FormData()
    fd.append('foo', body.foo)
    fd.append('upload_file', body.upload_file)
    return fd
  },
})

The request that gets made is Content-Type: application/json and was only able to get it set by the browser to multipart/form (with boundary) was to provide a fetch that ignores the client.post generated headers

const { post } =  createClient<paths>({
  baseUrl: 'http://localhost:8000/',
  mode: 'cors',
  fetch: (url, init) => {
    const { headers, ...newInit } = init
    return fetch(url, newInit)
  },
})

@psychedelicious
Copy link
Contributor

Yeah - I meant I think the library is manually setting it, not you

@nilsso
Copy link

nilsso commented Jul 1, 2023

Maybe should open an issue 🧐

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request openapi-fetch Relevant to the openapi-fetch library PRs welcome PRs are welcome to solve this issue!
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants