I’m building a CRUD app with reason-apollo and one feature I want to have is a mutation query that uploads a file. I’m having a difficult time using the DOM’s File object as a variable in my particular mutation render prop. It looks like this, when there is a file in state a button render that invokes the mutation on click.
let str = ReasonReact.string;
module Data = {
type file = {
lastModified: int,
lastModifiedDate: string,
name: string,
size: int,
type_: string,
webkitRelativePath: string,
};
};
type fileArray = array(Data.file);
type state = {files: fileArray};
type actions =
| HandleFileChange(fileArray);
let component = ReasonReact.reducerComponent("NewTracks");
module SingleUpload = [%graphql
{|
mutation singleUpload($file: Upload!, $path: String!) {
singleUpload(file: $file, path: $path) {
filename
}
}
|}
];
module SingleUploadMutation = ReasonApollo.CreateMutation(SingleUpload);
let make = _children => {
...component,
initialState: () => {files: [||]},
reducer: (action, _state) =>
switch (action) {
| HandleFileChange(fileArray) => ReasonReact.Update({files: fileArray})
},
render: ({state, send}) =>
<div>
<button
className=Styles.basicButton
onClick=(_event => ReasonReact.Router.push("/"))>
(str("Home"))
</button>
<div className=Styles.segment>
<p> ("Upload a new track here" |> str) </p>
<input
id="track"
type_="file"
onChange=(
event => {
let files = ReactEvent.Form.target(event)##files;
send(HandleFileChange(files));
}
)
/>
</div>
<SingleUploadMutation>
...(
(mutate, _) =>
switch (Array.length(state.files)) {
| 0 => <div> ("Put a file!" |> str) </div>;
| _ =>
let selectedFile = Belt.Array.getExn(state.files, 0);
let singleUploadMutation =
SingleUpload.make(~file=selectedFile, ~path="/tracks", ());
<button
className=Styles.basicButton
onClick=(
_event =>
mutate(~variables=singleUploadMutation##variables, ())
|> ignore
)>
("Upload!" |> str)
</button>;
}
)
</SingleUploadMutation>
</div>,
};
With this current code, SelectedFile
has type Data.file
but is expected to be Js.Json.t
. I’ve tried encoding as Json with this module following this thread on Working with results from DOM API, but no luck.
module Encode = {
let toJson = file =>
Json.Encode.(
object_([
("lastModified", file##lastModified |> int),
("lastModifiedDate", file##lastModifiedDate |> string),
("name", file##name |> string),
("size", file##size |> int),
("type", file##type_ |> string),
("webkitRelativePath", file##webkitRelativePath |> string),
])
);
};
A good first step to figuring this out might be, has anyone had much luck working with the File API with Reason in general?