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
File extensions #283
File extensions #283
Conversation
Why not a composition using (:>) operator ? this would allow the use of this extension with other stuff than Capture ? (I have no example in mind right now) |
This can also be used in query parameters and headers through the use of the |
Also |
@axman6 why not just make your own combinator for this? data Ex (fileName :: Symbol) (extension :: Symbol)
instance (KnownSymbol fileName, KnownSymbol extension, HasServer api) =>
HasServer (Ex fileName ext :> api) where
.... |
The file name is the part were trying to capture, so it can't be a static part of the type. The helper allows you to handle requests for any file with a given extension instead of having to leave the extension off the URL. |
This implementation gets a lot of benefits for free, it can be used in several places in the URL and request without having to implement HasServer or anything else. |
@axman6 Ah I see, of course the filename has to be dynamic =) I guess then you could in theory do something like this: data Ex (extension :: Symbol)
instance (KnownSymbol extension, HasServer api) => HasServer (Ex fileName ext :> api) where
... capture filename in path, ensure it matches extension, if no extension, then still try stuff .... |
Sure, but this already does that when used with Capture, ensures the extension is present and strips it (but it's recoverable because the type is known) |
@axman6 I only read your description quckly, now I reviewed your commit and I understand better what you call an extension. I though you added a 'parameter' to Capture only, I like your implementation. sorry for the noise |
I see the point. It's a little annoying that content-types are not sufficient in all cases, but I guess we have to come to terms with that. @axman6 do you have a reference for when browsers misbehave w.r.t. content-types (but not extensions)? (Also, you'll have to add a CPP'd import of |
import Data.Maybe (catMaybes) | ||
import Control.Monad ((>=>)) | ||
|
||
-- | A wrapper around a time type which can be parsed/rendered to with `format', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Time
? This seems like it's from the other PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoops, yes, they we're developed at the tame time and I guess the two branches weren't kept as sterile as they should have been =)
Thanks for the fixes. General questions I should have asked earlier:
|
From what I can see, this functionality doesn't need to leave in cc @alpmestan, I guess this one could be used as an example of writing your own combinators. FWIW, it might make sense to setup |
Yes, servant-contrib/extras sounds like something we have to put somewhere on the roadmap now. Maybe |
Yes, it's hard to draw a line. I'd keep multipart as a separate one. But -- | A type for quick'n'dirty capture / query param matching.
--
-- @n@ stands for capture groups to extract
--
-- ==== Example
--
-- @
-- type API = "folder" :> Capture "filename" (RE "(.*)\\.json") :> Get '[JSON] MyType
-- @
newtype RE n = RE { matchGroups :: Vec n Text } EDIT: if it's in a separate package, than it can depend on e.g. |
I need something like this however for my use case I would prefer that newtype Ext (ext :: Symbol) a = Ext {getBase :: a} instance (KnownSymbol ext, ToHttpApiData a) => ToHttpApiData (Ext ext a) where ... So that I can define the following for example: type MyApi = "file" :> Capture "filename" (Ext "jpg" UTCTime) :> Raw Does that make sense? EDIT: newtype (:.) a (ext :: Symbol) = Ext (getBase :: a) so that I can define my example as: type MyApi = "file" :> Capture "filename" (UTCTime :. "jpg") :> Raw |
@basvandijk have you seen: https://github.com/haskell-servant/servant-contrib/blob/master/servant-contrib/src/Servant/Contrib/RegexHttpApiData.hs Consensus here is, that we are unlikely to add this combinator to |
@phadej thanks for the heads up. I'll copy&paste&adapt the code then. |
FWIW: it's not even |
Closing; the regex code is in |
Just as a reference for anyone else ending up here: another option is to use |
As discussed in this issue. haskell-servant/servant#283 TODO use basvandijk's idea haskell-servant/servant#283 (comment)
Adds the ability to capture
Text
file names with an extension specified in the type.We serve several server generated CSV and PNG files which currently have URLs which do not contain the file extension, which confuses some browsers, despite the correct content type.
I tried using something more generic than Text for the file name, but it proved to be not very useful - supporting a generic
From/ToHttpApiData
type only makes sense sometimes.