11import gleam/dynamic . { type Dynamic }
2- import gleam/fetch/fetch_options . { type FetchOptions }
32import gleam/fetch/form_data . { type FormData }
43import gleam/http/request . { type Request }
54import gleam/http/response . { type Response }
@@ -46,6 +45,13 @@ pub fn raw_send(
4645 request : FetchRequest ,
4746) -> Promise ( Result ( FetchResponse , FetchError ) )
4847
48+ /// Bridge for Request with FetchOptions between Gleam and JavaScript.
49+ @ external ( javascript , "../gleam_fetch_ffi.mjs" , "raw_send" )
50+ fn raw_send_converted_options (
51+ request : FetchRequest ,
52+ options : FetchOptionsNative ,
53+ ) -> Promise ( Result ( FetchResponse , FetchError ) )
54+
4955/// Call directly `fetch` with a `Request` and `FetchOptions`,
5056/// then convert the result back to Gleam.
5157/// Let you get back a `FetchResponse` instead of the Gleam
@@ -56,13 +62,24 @@ pub fn raw_send(
5662/// |> request.set_host("example.com")
5763/// |> request.set_path("/example")
5864/// |> fetch.to_fetch_request
59- /// |> fetch.raw_send_with (fetch_options.new())
65+ /// |> fetch.raw_send_options (fetch_options.new())
6066/// ```
61- @ external ( javascript , "../gleam_fetch_ffi.mjs" , "raw_send" )
62- pub fn raw_send_with (
67+ pub fn raw_send_options (
6368 request : FetchRequest ,
6469 options : FetchOptions ,
65- ) -> Promise ( Result ( FetchResponse , FetchError ) )
70+ ) -> Promise ( Result ( FetchResponse , FetchError ) ) {
71+ raw_send_converted_options (
72+ request ,
73+ FetchOptionsNative (
74+ cache : cache_to_string ( options . cache ) ,
75+ credentials : credentials_to_string ( options . credentials ) ,
76+ keepalive : options . keepalive ,
77+ mode : cors_to_string ( options . mode ) ,
78+ priority : priority_to_string ( options . priority ) ,
79+ redirect : redirect_to_string ( options . redirect ) ,
80+ ) ,
81+ )
82+ }
6683
6784/// Call `fetch` with a Gleam `Request(String)`, and convert the result back
6885/// to Gleam. Use it to send strings or JSON stringified.
@@ -95,7 +112,7 @@ pub fn send(
95112/// Use it to send strings or JSON stringified.
96113///
97114/// If you're looking for something more low-level, take a look at
98- /// [`raw_send_with `](#raw_send_with ).
115+ /// [`raw_send_options `](#raw_send_options ).
99116///
100117/// ```gleam
101118/// let my_data = json.object([#("field", "value")])
@@ -104,15 +121,15 @@ pub fn send(
104121/// |> request.set_path("/example")
105122/// |> request.set_body(json.to_string(my_data))
106123/// |> request.set_header("content-type", "application/json")
107- /// |> fetch.send_with (fetch_options.new())
124+ /// |> fetch.send_options (fetch_options.new())
108125/// ```
109- pub fn send_with (
126+ pub fn send_options (
110127 request : Request ( String ) ,
111128 options : FetchOptions ,
112129) -> Promise ( Result ( Response ( FetchBody ) , FetchError ) ) {
113130 request
114131 |> to_fetch_request
115- |> raw_send_with ( options )
132+ |> raw_send_options ( options )
116133 |> promise . try_await ( fn ( resp ) {
117134 promise . resolve ( Ok ( from_fetch_response ( resp ) ) )
118135 } )
@@ -152,7 +169,7 @@ pub fn send_form_data(
152169/// decoded as-is on servers.
153170///
154171/// If you're looking for something more low-level, take a look at
155- /// [`raw_send_with `](#raw_send_with ).
172+ /// [`raw_send_options `](#raw_send_options ).
156173///
157174/// ```gleam
158175/// request.new()
@@ -162,15 +179,15 @@ pub fn send_form_data(
162179/// form_data.new()
163180/// |> form_data.append("key", "value")
164181/// })
165- /// |> fetch.send_form_data_with (fetch_options.new())
182+ /// |> fetch.send_form_data_options (fetch_options.new())
166183/// ```
167- pub fn send_form_data_with (
184+ pub fn send_form_data_options (
168185 request : Request ( FormData ) ,
169186 options : FetchOptions ,
170187) -> Promise ( Result ( Response ( FetchBody ) , FetchError ) ) {
171188 request
172189 |> form_data_to_fetch_request
173- |> raw_send_with ( options )
190+ |> raw_send_options ( options )
174191 |> promise . try_await ( fn ( resp ) {
175192 promise . resolve ( Ok ( from_fetch_response ( resp ) ) )
176193 } )
@@ -207,23 +224,23 @@ pub fn send_bits(
207224/// and you probably want a proper content-type added.
208225///
209226/// If you're looking for something more low-level, take a look at
210- /// [`raw_send_with `](#raw_send_with ).
227+ /// [`raw_send_options `](#raw_send_options ).
211228///
212229/// ```gleam
213230/// request.new()
214231/// |> request.set_host("example.com")
215232/// |> request.set_path("/example")
216233/// |> request.set_body(<<"data">>)
217234/// |> request.set_header("content-type", "application/octet-stream")
218- /// |> fetch.send_bits_with (fetch_options.new())
235+ /// |> fetch.send_bits_options (fetch_options.new())
219236/// ```
220- pub fn send_bits_with (
237+ pub fn send_bits_options (
221238 request : Request ( BitArray ) ,
222239 options : FetchOptions ,
223240) -> Promise ( Result ( Response ( FetchBody ) , FetchError ) ) {
224241 request
225242 |> bitarray_request_to_fetch_request
226- |> raw_send_with ( options )
243+ |> raw_send_options ( options )
227244 |> promise . try_await ( fn ( resp ) {
228245 promise . resolve ( Ok ( from_fetch_response ( resp ) ) )
229246 } )
@@ -363,3 +380,250 @@ pub fn read_text_body(
363380pub fn read_json_body (
364381 a : Response ( FetchBody ) ,
365382) -> Promise ( Result ( Response ( Dynamic ) , FetchError ) )
383+
384+ /// Gleam equivalent of JavaScript
385+ /// [`RequestInit`](https://developer.mozilla.org/docs/Web/API/RequestInit).
386+ ///
387+ /// The Node target supports only the `redirect` and `priority` options.
388+ pub opaque type FetchOptions {
389+ Builder (
390+ cache : Cache ,
391+ credentials : Credentials ,
392+ keepalive : Bool ,
393+ mode : Cors ,
394+ priority : Priority ,
395+ redirect : Redirect ,
396+ )
397+ }
398+
399+ // Converted internal FetchOptions to be send via JavaScript.
400+ type FetchOptionsNative {
401+ FetchOptionsNative (
402+ cache : String ,
403+ credentials : String ,
404+ keepalive : Bool ,
405+ mode : String ,
406+ priority : String ,
407+ redirect : String ,
408+ )
409+ }
410+
411+ /// Cache options, for details see
412+ /// [`cache`](https://developer.mozilla.org/docs/Web/API/RequestInit#cache).
413+ ///
414+ /// Change how responses are stored and retrieved from cache.
415+ pub type Cache {
416+ /// Default cache behaviour.
417+ ///
418+ /// Fresh record will be returned from the cache.
419+ /// If the record in cache is stale and server responds with not
420+ /// changed, then the value from cache is used. Otherwise makes normal
421+ /// request and updates the cache.
422+ Default
423+ /// Response is not fetched from the cache and not stored in the cache.
424+ NoStore
425+ /// Response is not fetched from the cache but gets stored.
426+ Reload
427+ /// If the record in cache is fresh or stale and server responds with not
428+ /// changed, then the value from cache is used. Otherwise makes normal
429+ /// request and updates the cache.
430+ NoCache
431+ /// If record is in cache, it is always used. Otherwise makes normal
432+ /// request.
433+ ForceCache
434+ }
435+
436+ fn cache_to_string ( cache : Cache ) -> String {
437+ case cache {
438+ Default -> "default"
439+ NoStore -> "no-store"
440+ Reload -> "reload"
441+ NoCache -> "no-cache"
442+ ForceCache -> "force-cache"
443+ }
444+ }
445+
446+ /// Credentials options, for details see
447+ /// [`credentials`](https://developer.mozilla.org/docs/Web/API/RequestInit#credentials).
448+ ///
449+ /// Control whether browser sends credentials with the request and whether
450+ /// Set-Cookie response headers are respected.
451+ pub type Credentials {
452+ /// Never send credentials or include credentials in the response.
453+ CredentialsOmit
454+ /// Only send and include credentials for same-origin requests.
455+ CredentialsSameOrigin
456+ /// Always include credentials.
457+ CredentialsInclude
458+ }
459+
460+ fn credentials_to_string ( credentials : Credentials ) -> String {
461+ case credentials {
462+ CredentialsOmit -> "omit"
463+ CredentialsSameOrigin -> "same-origin"
464+ CredentialsInclude -> "include"
465+ }
466+ }
467+
468+ /// CORS options, for details see
469+ /// [`mode`](https://developer.mozilla.org/docs/Web/API/RequestInit#mode).
470+ ///
471+ /// Set cross-origin behaviour of a request.
472+ pub type Cors {
473+ /// Disallows cross-origin requests.
474+ SameOrigin
475+ /// Defaults to
476+ /// [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS)
477+ /// mechanism.
478+ Cors
479+ /// Disables CORS for cross-origin requests.
480+ NoCors
481+ /// Used only by HTML navigation.
482+ Navigate
483+ }
484+
485+ fn cors_to_string ( cors : Cors ) -> String {
486+ case cors {
487+ SameOrigin -> "same-origin"
488+ Cors -> "cors"
489+ NoCors -> "no-cors"
490+ Navigate -> "navigate"
491+ }
492+ }
493+
494+ /// Priority options, for details see
495+ /// [`priority`](https://developer.mozilla.org/docs/Web/API/RequestInit#priority).
496+ ///
497+ /// Increase priority of a request relative to other requests.
498+ pub type Priority {
499+ /// Higher priority.
500+ High
501+ /// Lower priority.
502+ Low
503+ /// No preference of priority.
504+ Auto
505+ }
506+
507+ fn priority_to_string ( priority : Priority ) -> String {
508+ case priority {
509+ High -> "high"
510+ Low -> "low"
511+ Auto -> "auto"
512+ }
513+ }
514+
515+ /// Redirect options, for details see
516+ /// [`redirect`](https://developer.mozilla.org/docs/Web/API/RequestInit#redirect).
517+ ///
518+ /// Change the redirect behaviour of a request.
519+ pub type Redirect {
520+ /// Automatically redirects request.
521+ Follow
522+ /// Errors out on redirect.
523+ Error
524+ /// Expects user to handle redirects manually.
525+ Manual
526+ }
527+
528+ fn redirect_to_string ( redirect : Redirect ) -> String {
529+ case redirect {
530+ Follow -> "follow"
531+ Error -> "error"
532+ Manual -> "manual"
533+ }
534+ }
535+
536+ /// Creates new `FetchOptions` object with default values.
537+ ///
538+ /// Useful if more precise control over fetch is required, such as using
539+ /// signals, cache options and so on.
540+ ///
541+ /// ```gleam
542+ /// let options = fetch_options.new()
543+ /// |> fetch_options.cache(fetch_options.NoStore)
544+ /// ```
545+ pub fn fetch_options ( ) -> FetchOptions {
546+ Builder (
547+ cache : Default ,
548+ credentials : CredentialsSameOrigin ,
549+ keepalive : False ,
550+ mode : Cors ,
551+ priority : Auto ,
552+ redirect : Follow ,
553+ )
554+ }
555+
556+ /// Set the
557+ /// [`cache`](https://developer.mozilla.org/docs/Web/API/RequestInit#cache)
558+ /// option of `FetchOptions`.
559+ ///
560+ /// ```gleam
561+ /// let options = fetch_options.new()
562+ /// |> fetch_options.cache(fetch_options.NoStore)
563+ /// ```
564+ pub fn cache ( fetch_options : FetchOptions , which : Cache ) -> FetchOptions {
565+ Builder ( .. fetch_options , cache : which )
566+ }
567+
568+ /// Set the
569+ /// [`credentials`](https://developer.mozilla.org/docs/Web/API/RequestInit#credentials)
570+ /// option of `FetchOptions`.
571+ ///
572+ /// ```gleam
573+ /// let options = fetch_options.new()
574+ /// |> fetch_options.credentials(fetch_options.CredentialsOmit)
575+ /// ```
576+ pub fn credentials (
577+ fetch_options : FetchOptions ,
578+ which : Credentials ,
579+ ) -> FetchOptions {
580+ Builder ( .. fetch_options , credentials : which )
581+ }
582+
583+ /// Set the
584+ /// [`keepalive`](https://developer.mozilla.org/docs/Web/API/RequestInit#keepalive)
585+ /// option of `FetchOptions`.
586+ ///
587+ /// ```gleam
588+ /// let options = fetch_options.new()
589+ /// |> fetch_options.keepalive(True)
590+ /// ```
591+ pub fn keepalive ( fetch_options : FetchOptions , keepalive : Bool ) -> FetchOptions {
592+ Builder ( .. fetch_options , keepalive : keepalive )
593+ }
594+
595+ /// Set the
596+ /// [`cors`](https://developer.mozilla.org/docs/Web/API/RequestInit#mode)
597+ /// option of `FetchOptions`.
598+ ///
599+ /// ```gleam
600+ /// let options = fetch_options.new()
601+ /// |> fetch_options.cors(fetch_options.SameOrigin)
602+ /// ```
603+ pub fn cors ( fetch_options : FetchOptions , which : Cors ) -> FetchOptions {
604+ Builder ( .. fetch_options , mode : which )
605+ }
606+
607+ /// Set the
608+ /// [`priority`](https://developer.mozilla.org/docs/Web/API/RequestInit#priority)
609+ /// option of `FetchOptions`.
610+ ///
611+ /// ```gleam
612+ /// let options = fetch_options.new()
613+ /// |> fetch_options.cors(fetch_options.High)
614+ /// ```
615+ pub fn priority ( fetch_options : FetchOptions , which : Priority ) -> FetchOptions {
616+ Builder ( .. fetch_options , priority : which )
617+ }
618+
619+ /// Set the
620+ /// [`redirect`](https://developer.mozilla.org/docs/Web/API/RequestInit#redirect)
621+ /// option of `FetchOptions`.
622+ ///
623+ /// ```gleam
624+ /// let options = fetch_options.new()
625+ /// |> fetch_options.redirect(fetch_options.Follow)
626+ /// ```
627+ pub fn redirect ( fetch_options : FetchOptions , which : Redirect ) -> FetchOptions {
628+ Builder ( .. fetch_options , redirect : which )
629+ }
0 commit comments