Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/FetchAPI.res
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ type formData = {}

type requestInfo = any

type formDataEntryValue = any
@editor.completeFrom(FormDataEntryValue)
type formDataEntryValue

type requestInit = {
/**
Expand Down
14 changes: 7 additions & 7 deletions src/FetchAPI/FormData.res
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,7 @@ external delete: (formData, string) => unit = "delete"
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/FormData/get)
*/
@send
external get: (formData, string) => null<string> = "get"

/**
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/FormData/get)
*/
@send
external getFile: (formData, string) => null<file> = "get"
external get: (formData, string) => null<formDataEntryValue> = "get"

/**
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/FormData/getAll)
Expand All @@ -51,6 +45,12 @@ external getAll: (formData, string) => array<formDataEntryValue> = "getAll"
@send
external has: (formData, string) => bool = "has"

/**
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/FormData/entries)
*/
@send
external entries: formData => Iterator.t<(string, formDataEntryValue)> = "entries"

/**
[Read more on MDN](https://developer.mozilla.org/docs/Web/API/FormData/keys)
*/
Expand Down
22 changes: 22 additions & 0 deletions src/FetchAPI/FormDataEntryValue.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions src/FetchAPI/FormDataEntryValue.res
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
open Prelude
open FetchAPI
open FileAPI

external fromString: string => formDataEntryValue = "%identity"
external fromFile: file => formDataEntryValue = "%identity"

/**
Represents a decoded version of the abstract `formDataEntryValue` type.
A FormData entry value is either a string or a File.
*/
type decoded =
| String(string)
| File(file)

let decode = (t: formDataEntryValue): decoded => {
if File.isInstanceOf(t) {
File(unsafeConversation(t))
} else {
String(unsafeConversation(t))
}
}
7 changes: 7 additions & 0 deletions src/FileAPI/File.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions src/FileAPI/File.res
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@ external make: (
~fileName: string,
~options: filePropertyBag=?,
) => file = "File"

let isInstanceOf = (_: 't): bool => %raw(`param instanceof File`)
48 changes: 44 additions & 4 deletions tests/FetchAPI/FormData__test.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 37 additions & 2 deletions tests/FetchAPI/FormData__test.res
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,40 @@
external myForm: DOMAPI.htmlFormElement = "myForm"

let formData = FormData.make(~form=myForm)
let phone: null<string> = formData->FormData.get("phone")
let image: null<FileAPI.file> = formData->FormData.getFile("image")

// Get a form field - returns formDataEntryValue which could be string or File
let phoneEntry: null<FetchAPI.formDataEntryValue> = formData->FormData.get("phone")

// Decode the entry to handle both string and File cases
let _ = switch phoneEntry->Null.toOption {
| None => Console.log("No phone field")
| Some(entry) =>
switch entry->FormDataEntryValue.decode {
| FormDataEntryValue.String(value) => Console.log(`Phone: ${value}`)
| FormDataEntryValue.File(file) => Console.log(`Unexpected file: ${file.name}`)
}
}

// Get all values for a field (useful for multi-select or multiple file inputs)
let allImages: array<FetchAPI.formDataEntryValue> = formData->FormData.getAll("images")

// Process all entries
let _ = allImages->Array.forEach(entry => {
switch entry->FormDataEntryValue.decode {
| FormDataEntryValue.String(value) => Console.log(`String value: ${value}`)
| FormDataEntryValue.File(file) => Console.log(`File: ${file.name}`)
}
})

// Create formDataEntryValue from string or file
let stringEntry = FormDataEntryValue.fromString("test value")
let fileEntry = FormDataEntryValue.fromFile(File.make(~fileBits=[], ~fileName="test.txt"))

// Iterate over all entries in the FormData
let entries: Iterator.t<(string, FetchAPI.formDataEntryValue)> = formData->FormData.entries
let _ = entries->Iterator.forEach(((key, value)) => {
switch value->FormDataEntryValue.decode {
| FormDataEntryValue.String(s) => Console.log(`${key}: ${s}`)
| FormDataEntryValue.File(f) => Console.log(`${key}: [File] ${f.name}`)
}
})