-
Notifications
You must be signed in to change notification settings - Fork 42
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
Add To/FromFormMultiPart classes #24
Comments
Related workServer-side:
Client-side:
EDIT: added |
data FileInfo = FileInfo
{ fileName :: !Text
, fileContentType :: !Text
, fileSourceRaw :: !(ConduitT () ByteString (ResourceT IO) ())
, fileMove :: !(FilePath -> IO ())
} They also seem to have 3 options for handling file uploads (on the server): data FileUpload
= FileUploadMemory !(NWP.BackEnd L.ByteString)
| FileUploadDisk !(InternalState -> NWP.BackEnd FilePath)
| FileUploadSource !(NWP.BackEnd (ConduitT () ByteString (ResourceT IO) ())) Note the last option which is not available with |
It isn't, but iirc can be added in an app: implement MultipartBackend
…Sent from my iPhone
On 21 Feb 2018, at 17.05, Nickolay Kudasov ***@***.***> wrote:
yesod-form also has support for file upload (see Cookbook file upload saving files to server).
File upload field is created using fileAFormReq. File info is represented with FileInfo:
data FileInfo = FileInfo
{ fileName :: !Text
, fileContentType :: !Text
, fileSourceRaw :: !(ConduitT () ByteString (ResourceT IO) ())
, fileMove :: !(FilePath -> IO ())
}
They also seem to have 3 options for handling file uploads (on the server):
data FileUpload
= FileUploadMemory !(NWP.BackEnd L.ByteString)
| FileUploadDisk !(InternalState -> NWP.BackEnd FilePath)
| FileUploadSource !(NWP.BackEnd (ConduitT () ByteString (ResourceT IO) ()))
Note the last option which is not available with servant-multipart AFAICT.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
The more I think about it the more it seems like we should just provide common data types and not use type classes 🙃 For instance we could just provide something like this: data MultiPartFormData file = MultiPartFormData
{ mpfdInputs :: Form
, mpfdFiles :: [FileData file]
}
data FileData file = FileData
{ fdInputName :: Text -- input field name
, fdFileName :: Text -- user's file name
, fdFileHeaders :: [Header] -- additional file headers
, fdContentType :: Text
, fdFileContents :: file
}
-- | Locally saved file.
newtype LocalFilePath = LocalFilePath FilePath
-- | File contents loaded into memory.
newtype FileContents = FileContents ByteString
-- | Some file that can be read directly or moved (saved) somewhere.
-- Particularly useful for server-side handlers to ignore how server handles uploads.
data SomeFile = SomeFile
{ someFileSorceRaw :: ConduitT () ByteString (ResourceT IO) () -- I don't really know how to convert this into a simpler type
, someFileMove :: FilePath -> IO ()
} Now we could provide classes like class ToMultiPartFormData file a where
toMultiPartFormData :: a -> MultiPartFormData file
class FromMultiPartFormData file a where
parseMultiPartFormData :: MultiPartFormData file -> Either Text a However those are multi parameter and without functional dependencies so are likely to only cause confusion. Alternatively we could limit class ToMultiPartFormData a where
toMultiPartFormData :: a -> MultiPartFormData (IO ByteString)
class FromMultiPartFormData file a where
parseMultiPartFormData :: MultiPartFormData SomeFile -> Either Text a However those look pretty weird to me, especially with IO actions in So for now I think it would be sufficient to just have common datatypes and functions and not introduce type classes for now. @alpmestan @phadej do you have any thoughts on this? |
Surely you'll reconsider this once your head is not upside down anymore. =) More seriously: I do think typeclasses are useful here, as with captures, query params and what not. The handlers are then allowed to only care about the user's "business types" (e.g class ToMultiPartFormData a where
toMultiPartFormData :: forall backend. KnownBackend backend => a -> MultiPartFormData backend
class FromMultiPartFormData a where
parseMultiPartFormData :: forall backend. KnownBackend backend => MultiPartFormData backend -> Either Text a where |
@alpmestan I think the problem with data User = User
{ name :: String
, profilePic :: FilePath
}
instance FromMultiPartFormData User where
parseMultiPartFormData :: KnownBackend backend =>
MultiPartFormData backend -> Either Text User
parseMultiPartFormData = ... -- what goes here? At least I can't figure out how to do that with class MultipartBackend tag where
type MultipartResult tag :: *
type MultipartBackendOptions tag :: *
backend :: Proxy tag
-> MultipartBackendOptions tag
-> InternalState
-> ignored1
-> ignored2
-> IO SBS.ByteString
-> IO (MultipartResult tag)
defaultBackendOptions :: Proxy tag -> MultipartBackendOptions tag If I understand it correctly, |
Hmm, correct, nevermind my suggestion then! |
Maybe something like this:
The text was updated successfully, but these errors were encountered: