servant-elm 0.3.0.1 → 0.4.0.0
raw patch · 12 files changed
+108/−31 lines, 12 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Servant.Elm: Dynamic :: UrlPrefix
+ Servant.Elm: Static :: Text -> UrlPrefix
+ Servant.Elm: data UrlPrefix
+ Servant.Elm.Internal.Generate: Dynamic :: UrlPrefix
+ Servant.Elm.Internal.Generate: Static :: Text -> UrlPrefix
+ Servant.Elm.Internal.Generate: data UrlPrefix
- Servant.Elm: ElmOptions :: Text -> Options -> [ElmDatatype] -> [ElmDatatype] -> ElmOptions
+ Servant.Elm: ElmOptions :: UrlPrefix -> Options -> [ElmDatatype] -> [ElmDatatype] -> ElmOptions
- Servant.Elm: [urlPrefix] :: ElmOptions -> Text
+ Servant.Elm: [urlPrefix] :: ElmOptions -> UrlPrefix
- Servant.Elm.Internal.Generate: ElmOptions :: Text -> Options -> [ElmDatatype] -> [ElmDatatype] -> ElmOptions
+ Servant.Elm.Internal.Generate: ElmOptions :: UrlPrefix -> Options -> [ElmDatatype] -> [ElmDatatype] -> ElmOptions
- Servant.Elm.Internal.Generate: [urlPrefix] :: ElmOptions -> Text
+ Servant.Elm.Internal.Generate: [urlPrefix] :: ElmOptions -> UrlPrefix
- Servant.Elm.Internal.Generate: mkArgs :: Req ElmDatatype -> Doc
+ Servant.Elm.Internal.Generate: mkArgs :: ElmOptions -> Req ElmDatatype -> Doc
Files
- CHANGELOG.md +6/−0
- README.md +3/−4
- examples/books/generate.hs +2/−2
- examples/e2e-tests/generate.hs +2/−2
- examples/giphy/generate.hs +2/−2
- servant-elm.cabal +1/−1
- src/Servant/Elm.hs +3/−2
- src/Servant/Elm/Internal/Generate.hs +37/−14
- test/Common.hs +2/−1
- test/GenerateSpec.hs +21/−1
- test/elm-sources/getBooksSource.elm +2/−2
- test/elm-sources/getOneWithDynamicUrlSource.elm +27/−0
CHANGELOG.md view
@@ -1,3 +1,9 @@+0.4.0.0+-------+* Allow passing the base URL dynamically in Elm. (#20)+* Don't use `toString` on `Text` parameters. (domenkozar) (#23, #24)+* Fix query parameter generation. (domenkozar) (#25)+ 0.3.0.1 ------- * Prefix generated function arguments to ensure valid Elm identifiers (#21)
README.md view
@@ -84,18 +84,17 @@ |> required "name" string getBooksByBookId : Int -> Http.Request (Book)-getBooksByBookId bookId =+getBooksByBookId capture_bookId = Http.request { method = "GET" , headers =- [ Http.header "Content-Type" "application/json"- ]+ [] , url = String.join "/" [ "" , "books"- , bookId |> toString |> Http.encodeUri+ , capture_bookId |> toString |> Http.encodeUri ] , body = Http.emptyBody
examples/books/generate.hs view
@@ -8,7 +8,7 @@ import GHC.Generics (Generic) import Servant.API ((:<|>), (:>), Capture, Get, JSON, Post, ReqBody) import Servant.Elm (ElmOptions (..), ElmType, Proxy (Proxy),- defElmImports, defElmOptions,+ UrlPrefix (Static), defElmImports, defElmOptions, generateElmForAPIWith) data Book = Book@@ -22,7 +22,7 @@ :<|> "books" :> Capture "bookId" Int :> Get '[JSON] Book myElmOpts :: ElmOptions-myElmOpts = defElmOptions { urlPrefix = "http://localhost:8000" }+myElmOpts = defElmOptions { urlPrefix = Static "http://localhost:8000" } spec :: Spec spec = Spec ["Generated", "BooksApi"]
examples/e2e-tests/generate.hs view
@@ -10,12 +10,12 @@ import Servant.API ((:<|>), (:>), Capture, Get, GetNoContent, JSON, NoContent, Post, QueryParam, ReqBody) import Servant.Elm (ElmOptions (..), ElmType, Proxy (Proxy),- defElmImports, defElmOptions,+ UrlPrefix (Static), defElmImports, defElmOptions, generateElmForAPIWith) myElmOpts :: ElmOptions-myElmOpts = defElmOptions { urlPrefix = "https://httpbin.org" }+myElmOpts = defElmOptions { urlPrefix = Static "https://httpbin.org" } data MessageBody = MessageBody
examples/giphy/generate.hs view
@@ -9,7 +9,7 @@ toElmDecoderSourceWith, toElmTypeSourceWith) import GHC.Generics (Generic) import Servant.API ((:>), Get, JSON, QueryParam)-import Servant.Elm (ElmOptions (..), ElmType, Proxy (Proxy),+import Servant.Elm (ElmOptions (..), ElmType, Proxy (Proxy), UrlPrefix(Static), defElmImports, defElmOptions, generateElmForAPIWith) @@ -40,7 +40,7 @@ myElmOpts = defElmOptions { urlPrefix =- "http://api.giphy.com/v1/gifs"+ Static "http://api.giphy.com/v1/gifs" , elmExportOptions = options }
servant-elm.cabal view
@@ -1,5 +1,5 @@ name: servant-elm-version: 0.3.0.1+version: 0.4.0.0 synopsis: Automatically derive Elm functions to query servant webservices. description: Please see README.md homepage: http://github.com/mattjbray/servant-elm#readme
src/Servant/Elm.hs view
@@ -15,6 +15,7 @@ ( generateElmForAPI , generateElmForAPIWith , ElmOptions(..)+ , UrlPrefix(..) , defElmOptions , defElmImports -- * Convenience re-exports from the "Elm" module@@ -25,8 +26,8 @@ , Proxy(Proxy) ) where -import Servant.Elm.Internal.Generate (ElmOptions (..), defElmImports,- defElmOptions,+import Servant.Elm.Internal.Generate (ElmOptions (..), UrlPrefix (..),+ defElmImports, defElmOptions, generateElmForAPI, generateElmForAPIWith)
src/Servant/Elm/Internal/Generate.hs view
@@ -28,9 +28,12 @@ { {- | The protocol, host and any path prefix to be used as the base for all requests. - Example: @"https://mydomain.com/api/v1"@+ Example: @Static "https://mydomain.com/api/v1"@++ When @Dynamic@, the generated Elm functions take the base URL as the first+ argument. -}- urlPrefix :: T.Text+ urlPrefix :: UrlPrefix , elmExportOptions :: Elm.Options -- ^ Options to pass to elm-export , emptyResponseElmTypes :: [ElmDatatype]@@ -40,13 +43,18 @@ } +data UrlPrefix+ = Static T.Text+ | Dynamic++ {-| Default options for generating Elm code. The default options are: > { urlPrefix =-> ""+> Static "" > , elmExportOptions = > Elm.defaultOptions > , emptyResponseElmTypes =@@ -57,7 +65,7 @@ -} defElmOptions :: ElmOptions defElmOptions = ElmOptions- { urlPrefix = ""+ { urlPrefix = Static "" , elmExportOptions = Elm.defaultOptions , emptyResponseElmTypes = [ Elm.toElmType NoContent@@ -65,6 +73,7 @@ ] , stringElmTypes = [ Elm.toElmType ("" :: String)+ , Elm.toElmType ("" :: T.Text) ] } @@ -156,7 +165,7 @@ mkTypeSignature opts request args =- mkArgs request+ mkArgs opts request letParams = mkLetParams opts request@@ -168,12 +177,19 @@ mkTypeSignature :: ElmOptions -> F.Req ElmDatatype -> Doc mkTypeSignature opts request = (hsep . punctuate " ->" . concat)- [ headerTypes+ [ catMaybes [urlPrefixType]+ , headerTypes , urlCaptureTypes , queryTypes , catMaybes [bodyType, returnType] ] where+ urlPrefixType :: Maybe Doc+ urlPrefixType =+ case (urlPrefix opts) of+ Dynamic -> Just "String"+ Static _ -> Nothing+ elmTypeRef :: ElmDatatype -> Doc elmTypeRef eType = stext (Elm.toElmTypeRefWith (elmExportOptions opts) eType)@@ -238,11 +254,16 @@ mkArgs- :: F.Req ElmDatatype+ :: ElmOptions+ -> F.Req ElmDatatype -> Doc-mkArgs request =+mkArgs opts request = (hsep . concat) $- [ -- Headers+ [ -- Dynamic url prefix+ case urlPrefix opts of+ Dynamic -> ["urlBase"]+ Static _ -> []+ , -- Headers [ elmHeaderArg header | header <- request ^. F.reqHeaders ]@@ -286,7 +307,7 @@ "toString >> " in name <$>- indent 4 ("|> Maybe.map" <+> parens (toStringSrc <> "Http.encodeUri >> (++)" <+> dquotes (name <> equals)) <$>+ indent 4 ("|> Maybe.map" <+> parens (toStringSrc <> "Http.encodeUri >> (++)" <+> dquotes (elmName <> equals)) <$> "|> Maybe.withDefault" <+> dquotes empty) F.Flag ->@@ -300,8 +321,8 @@ indent 4 ("|> List.map" <+> parens (backslash <> "val ->" <+> dquotes (name <> "[]=") <+> "++ (val |> toString |> Http.encodeUri)") <$> "|> String.join" <+> dquotes "&") where- name =- elmQueryArg qarg+ name = elmQueryArg qarg+ elmName= qarg ^. F.queryArgName . F.argName . to (stext . F.unPathSegment) mkRequest :: ElmOptions -> F.Req ElmDatatype -> Doc@@ -382,8 +403,10 @@ mkUrl opts segments = "String.join" <+> dquotes "/" <$> (indent i . elmList)- ( dquotes (stext (urlPrefix opts))- : map segmentToDoc segments)+ ( case urlPrefix opts of+ Dynamic -> "urlBase"+ Static url -> dquotes (stext url)+ : map segmentToDoc segments) where segmentToDoc :: F.Segment ElmDatatype -> Doc
test/Common.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE TypeOperators #-} module Common where +import Data.Text (Text) import Data.Aeson (ToJSON) import Data.Proxy (Proxy(Proxy)) import Elm (ElmType)@@ -28,7 +29,7 @@ :> Capture "id" Int :> Get '[JSON] Book :<|> "books"- :> Capture "title" String+ :> Capture "title" Text :> Get '[JSON] Book :<|> "books" :> QueryFlag "published"
test/GenerateSpec.hs view
@@ -12,11 +12,12 @@ import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T+import Servant.API ((:>), Get, JSON) import Servant.Elm import Test.Hspec (Spec, describe, hspec, it) import Test.HUnit (Assertion, assertBool) -import Common (testApi)+import Common (testApi) main :: IO ()@@ -64,6 +65,25 @@ "import Http\n" <> "import Json.Decode exposing (..)\n\n\n")] let generated = map (<> "\n") (generateElmForAPI testApi)+ generated `itemsShouldBe` expected+ it "with dynamic URLs" $+ do expected <-+ mapM+ (\(fpath,header) -> do+ source <- T.readFile fpath+ return (fpath, header, source))+ [ ( "test/elm-sources/getOneWithDynamicUrlSource.elm"+ , "module GetOneWithDynamicUrlSource exposing (..)\n\n" <>+ "import Http\n" <>+ "import Json.Decode exposing (..)\n\n\n")]+ let generated =+ map+ (<> "\n")+ (generateElmForAPIWith+ (defElmOptions+ { urlPrefix = Dynamic+ })+ (Proxy :: Proxy ("one" :> Get '[JSON] Int))) generated `itemsShouldBe` expected itemsShouldBe :: [Text] -> [(String, Text, Text)] -> IO ()
test/elm-sources/getBooksSource.elm view
@@ -14,10 +14,10 @@ else "" , query_sort- |> Maybe.map (Http.encodeUri >> (++) "query_sort=")+ |> Maybe.map (Http.encodeUri >> (++) "sort=") |> Maybe.withDefault "" , query_year- |> Maybe.map (toString >> Http.encodeUri >> (++) "query_year=")+ |> Maybe.map (toString >> Http.encodeUri >> (++) "year=") |> Maybe.withDefault "" , query_filters |> List.map (\val -> "query_filters[]=" ++ (val |> toString |> Http.encodeUri))
+ test/elm-sources/getOneWithDynamicUrlSource.elm view
@@ -0,0 +1,27 @@+module GetOneWithDynamicUrlSource exposing (..)++import Http+import Json.Decode exposing (..)+++getOne : String -> Http.Request (Int)+getOne urlBase =+ Http.request+ { method =+ "GET"+ , headers =+ []+ , url =+ String.join "/"+ [ urlBase+ , "one"+ ]+ , body =+ Http.emptyBody+ , expect =+ Http.expectJson int+ , timeout =+ Nothing+ , withCredentials =+ False+ }