git.iko.soy/typeable/http-api-data
on master help sign in
Introduce unsafeToEncodedUrlPiece and use it types that don't need escaping
d91475dNickolay Kudasov
src/Web/Internal/HttpApiData.hs+68−31
@@ -73,7 +73,9 @@ class ToHttpApiData a where
73 toUrlPiece :: a -> Text
73 toUrlPiece :: a -> Text
74 toUrlPiece = toQueryParam
74 toUrlPiece = toQueryParam
75
75
76− -- | Convert to a URL path piece, making sure to encode any special chars
76+ -- | Convert to a URL path piece, making sure to encode any special chars.
77+ -- The default definition uses 'H.encodePathSegmentsRelative',
78+ -- but this may be overriden with a more efficient version.
77 toEncodedUrlPiece :: a -> BS.Builder
79 toEncodedUrlPiece :: a -> BS.Builder
78 toEncodedUrlPiece = H.encodePathSegmentsRelative . (:[]) . toUrlPiece
80 toEncodedUrlPiece = H.encodePathSegmentsRelative . (:[]) . toUrlPiece
79
81
@@ -394,46 +396,58 @@ parseBounded reader input = do
394 l = toInteger (minBound :: a)
396 l = toInteger (minBound :: a)
395 h = toInteger (maxBound :: a)
397 h = toInteger (maxBound :: a)
396
398
399+-- | Convert to a URL-encoded path piece using 'toUrlPiece'.
400+-- /Note/: this function does not check if the result contains unescaped characters!
401+-- This function can be used to override 'toEncodedUrlPiece' as a more efficient implementation
402+-- when the resulting URL piece /never/ has to be escaped.
403+unsafeToEncodedUrlPiece :: ToHttpApiData a => a -> BS.Builder
404+unsafeToEncodedUrlPiece = BS.byteString . encodeUtf8 . toUrlPiece
405+
397-- |
406-- |
398-- >>> toUrlPiece ()
407-- >>> toUrlPiece ()
399-- "_"
408-- "_"
400instance ToHttpApiData () where
409instance ToHttpApiData () where
401 toUrlPiece () = "_"
410 toUrlPiece () = "_"
411+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
402
412
403−instance ToHttpApiData Char where toUrlPiece = T.singleton
413+instance ToHttpApiData Char where
414+ toUrlPiece = T.singleton
404
415
405-- |
416-- |
406-- >>> toUrlPiece (Version [1, 2, 3] [])
417-- >>> toUrlPiece (Version [1, 2, 3] [])
407-- "1.2.3"
418-- "1.2.3"
408instance ToHttpApiData Version where
419instance ToHttpApiData Version where
409 toUrlPiece = T.pack . showVersion
420 toUrlPiece = T.pack . showVersion
421+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
410
422
411#if MIN_VERSION_base(4,8,0)
423#if MIN_VERSION_base(4,8,0)
412instance ToHttpApiData Void where toUrlPiece = absurd
424instance ToHttpApiData Void where toUrlPiece = absurd
413−instance ToHttpApiData Natural where toUrlPiece = showt
425+instance ToHttpApiData Natural where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
414#endif
426#endif
415
427
416−instance ToHttpApiData Bool where toUrlPiece = showTextData
428+instance ToHttpApiData Bool where toUrlPiece = showTextData; toEncodedUrlPiece = unsafeToEncodedUrlPiece
417−instance ToHttpApiData Ordering where toUrlPiece = showTextData
429+instance ToHttpApiData Ordering where toUrlPiece = showTextData; toEncodedUrlPiece = unsafeToEncodedUrlPiece
418−
430+
419−instance ToHttpApiData Double where toUrlPiece = showt
431+instance ToHttpApiData Double where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
420−instance ToHttpApiData Float where toUrlPiece = showt
432+instance ToHttpApiData Float where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
421−instance ToHttpApiData Int where toUrlPiece = showt
433+instance ToHttpApiData Int where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
422−instance ToHttpApiData Int8 where toUrlPiece = showt
434+instance ToHttpApiData Int8 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
423−instance ToHttpApiData Int16 where toUrlPiece = showt
435+instance ToHttpApiData Int16 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
424−instance ToHttpApiData Int32 where toUrlPiece = showt
436+instance ToHttpApiData Int32 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
425−instance ToHttpApiData Int64 where toUrlPiece = showt
437+instance ToHttpApiData Int64 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
426−instance ToHttpApiData Integer where toUrlPiece = showt
438+instance ToHttpApiData Integer where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
427−instance ToHttpApiData Word where toUrlPiece = showt
439+instance ToHttpApiData Word where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
428−instance ToHttpApiData Word8 where toUrlPiece = showt
440+instance ToHttpApiData Word8 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
429−instance ToHttpApiData Word16 where toUrlPiece = showt
441+instance ToHttpApiData Word16 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
430−instance ToHttpApiData Word32 where toUrlPiece = showt
442+instance ToHttpApiData Word32 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
431−instance ToHttpApiData Word64 where toUrlPiece = showt
443+instance ToHttpApiData Word64 where toUrlPiece = showt; toEncodedUrlPiece = unsafeToEncodedUrlPiece
432
444
433-- |
445-- |
434-- >>> toUrlPiece (fromGregorian 2015 10 03)
446-- >>> toUrlPiece (fromGregorian 2015 10 03)
435-- "2015-10-03"
447-- "2015-10-03"
436−instance ToHttpApiData Day where toUrlPiece = T.pack . show
448+instance ToHttpApiData Day where
449+ toUrlPiece = T.pack . show
450+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
437
451
438timeToUrlPiece :: FormatTime t => String -> t -> Text
452timeToUrlPiece :: FormatTime t => String -> t -> Text
439timeToUrlPiece fmt = T.pack . formatTime defaultTimeLocale (iso8601DateFormat (Just fmt))
453timeToUrlPiece fmt = T.pack . formatTime defaultTimeLocale (iso8601DateFormat (Just fmt))
@@ -441,32 +455,54 @@ timeToUrlPiece fmt = T.pack . formatTime defaultTimeLocale (iso8601DateFormat (J
441-- |
455-- |
442-- >>> toUrlPiece $ LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 01)
456-- >>> toUrlPiece $ LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 01)
443-- "2015-10-03T14:55:01"
457-- "2015-10-03T14:55:01"
444−instance ToHttpApiData LocalTime where toUrlPiece = timeToUrlPiece "%H:%M:%S"
458+instance ToHttpApiData LocalTime where
459+ toUrlPiece = timeToUrlPiece "%H:%M:%S"
460+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
445
461
446-- |
462-- |
447-- >>> toUrlPiece $ ZonedTime (LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 01)) utc
463-- >>> toUrlPiece $ ZonedTime (LocalTime (fromGregorian 2015 10 03) (TimeOfDay 14 55 01)) utc
448-- "2015-10-03T14:55:01+0000"
464-- "2015-10-03T14:55:01+0000"
449−instance ToHttpApiData ZonedTime where toUrlPiece = timeToUrlPiece "%H:%M:%S%z"
465+instance ToHttpApiData ZonedTime where
466+ toUrlPiece = timeToUrlPiece "%H:%M:%S%z"
467+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
450
468
451-- |
469-- |
452-- >>> toUrlPiece $ UTCTime (fromGregorian 2015 10 03) 864
470-- >>> toUrlPiece $ UTCTime (fromGregorian 2015 10 03) 864
453-- "2015-10-03T00:14:24Z"
471-- "2015-10-03T00:14:24Z"
454−instance ToHttpApiData UTCTime where toUrlPiece = timeToUrlPiece "%H:%M:%SZ"
472+instance ToHttpApiData UTCTime where
473+ toUrlPiece = timeToUrlPiece "%H:%M:%SZ"
474+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
455
475
476+instance ToHttpApiData NominalDiffTime where
456−instance ToHttpApiData NominalDiffTime where toUrlPiece = toUrlPiece . (floor :: NominalDiffTime -> Integer)
477+ toUrlPiece = toUrlPiece . (floor :: NominalDiffTime -> Integer)
478+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
457
479
458instance ToHttpApiData String where toUrlPiece = T.pack
480instance ToHttpApiData String where toUrlPiece = T.pack
459instance ToHttpApiData Text where toUrlPiece = id
481instance ToHttpApiData Text where toUrlPiece = id
460instance ToHttpApiData L.Text where toUrlPiece = L.toStrict
482instance ToHttpApiData L.Text where toUrlPiece = L.toStrict
461
483
462−instance ToHttpApiData All where toUrlPiece = toUrlPiece . getAll
484+instance ToHttpApiData All where toUrlPiece = toUrlPiece . getAll; toEncodedUrlPiece = toEncodedUrlPiece . getAll
463−instance ToHttpApiData Any where toUrlPiece = toUrlPiece . getAny
485+instance ToHttpApiData Any where toUrlPiece = toUrlPiece . getAny; toEncodedUrlPiece = toEncodedUrlPiece . getAny
486+
487+instance ToHttpApiData a => ToHttpApiData (Dual a) where
488+ toUrlPiece = toUrlPiece . getDual
489+ toEncodedUrlPiece = toEncodedUrlPiece . getDual
490+
491+instance ToHttpApiData a => ToHttpApiData (Sum a) where
492+ toUrlPiece = toUrlPiece . getSum
493+ toEncodedUrlPiece = toEncodedUrlPiece . getSum
494+
495+instance ToHttpApiData a => ToHttpApiData (Product a) where
496+ toUrlPiece = toUrlPiece . getProduct
497+ toEncodedUrlPiece = toEncodedUrlPiece . getProduct
498+
499+instance ToHttpApiData a => ToHttpApiData (First a) where
500+ toUrlPiece = toUrlPiece . getFirst
501+ toEncodedUrlPiece = toEncodedUrlPiece . getFirst
464
502
465−instance ToHttpApiData a => ToHttpApiData (Dual a) where toUrlPiece = toUrlPiece . getDual
503+instance ToHttpApiData a => ToHttpApiData (Last a) where
466−instance ToHttpApiData a => ToHttpApiData (Sum a) where toUrlPiece = toUrlPiece . getSum
504+ toUrlPiece = toUrlPiece . getLast
467−instance ToHttpApiData a => ToHttpApiData (Product a) where toUrlPiece = toUrlPiece . getProduct
505+ toEncodedUrlPiece = toEncodedUrlPiece . getLast
468−instance ToHttpApiData a => ToHttpApiData (First a) where toUrlPiece = toUrlPiece . getFirst
469−instance ToHttpApiData a => ToHttpApiData (Last a) where toUrlPiece = toUrlPiece . getLast
470
506
471-- |
507-- |
472-- >>> toUrlPiece (Just "Hello")
508-- >>> toUrlPiece (Just "Hello")
@@ -597,6 +633,7 @@ instance (FromHttpApiData a, FromHttpApiData b) => FromHttpApiData (Either a b)
597instance ToHttpApiData UUID.UUID where
633instance ToHttpApiData UUID.UUID where
598 toUrlPiece = UUID.toText
634 toUrlPiece = UUID.toText
599 toHeader = UUID.toASCIIBytes
635 toHeader = UUID.toASCIIBytes
636+ toEncodedUrlPiece = unsafeToEncodedUrlPiece
600
637
601instance FromHttpApiData UUID.UUID where
638instance FromHttpApiData UUID.UUID where
602 parseUrlPiece = maybe (Left "invalid UUID") Right . UUID.fromText
639 parseUrlPiece = maybe (Left "invalid UUID") Right . UUID.fromText