Add serverless ApiRoute builder and some examples in pokedex app.

This commit is contained in:
Dillon Kearns 2021-12-21 07:47:47 -08:00
parent 5aed656279
commit 7f2d47c6de
4 changed files with 70 additions and 71 deletions

View File

@ -20,12 +20,11 @@ routes :
-> (Html Never -> String)
-> List (ApiRoute.ApiRoute ApiRoute.Response)
routes getStaticRoutes htmlToString =
[ -- route1
--, route2
nonHybridRoute
[ nonHybridRoute
, noArgs
, redirectRoute
, serverRequestInfo
, repoStars
]
@ -39,7 +38,7 @@ serverRequestInfo =
|> ApiRoute.literal "api"
|> ApiRoute.slash
|> ApiRoute.literal "request"
|> ApiRoute.singleServerless
|> ApiRoute.serverless
redirectRoute : ApiRoute ApiRoute.Response
@ -51,7 +50,7 @@ redirectRoute =
|> ApiRoute.literal "api"
|> ApiRoute.slash
|> ApiRoute.literal "redirect"
|> ApiRoute.singleServerless
|> ApiRoute.serverless
serverRequestDataSource =
@ -90,7 +89,7 @@ noArgs =
|> ApiRoute.literal "api"
|> ApiRoute.slash
|> ApiRoute.literal "stars"
|> ApiRoute.singleServerless
|> ApiRoute.serverless
nonHybridRoute =
@ -119,6 +118,31 @@ nonHybridRoute =
)
repoStars : ApiRoute ApiRoute.Response
repoStars =
ApiRoute.succeed
(\repoName ->
DataSource.Http.get
(Secrets.succeed ("https://api.github.com/repos/dillonkearns/" ++ repoName))
(Decode.field "stargazers_count" Decode.int)
|> DataSource.map
(\stars ->
Json.Encode.object
[ ( "repo", Json.Encode.string repoName )
, ( "stars", Json.Encode.int stars )
]
|> ServerResponse.json
)
)
|> ApiRoute.literal "api"
|> ApiRoute.slash
|> ApiRoute.literal "repo"
|> ApiRoute.slash
|> ApiRoute.capture
--|> ApiRoute.literal ".json"
|> ApiRoute.serverless
route1 =
ApiRoute.succeed
(\repoName ->
@ -138,30 +162,3 @@ route1 =
|> ApiRoute.slash
|> ApiRoute.capture
|> ApiRoute.literal ".json"
|> ApiRoute.buildTimeRoutes
(\route ->
DataSource.succeed
[ route "elm-graphql"
]
)
route2 : ApiRoute ApiRoute.Response
route2 =
ApiRoute.succeed
(DataSource.succeed route1Pattern)
|> ApiRoute.literal "api-patterns.json"
|> ApiRoute.single
route1Pattern : String
route1Pattern =
case route1 of
----Internal.ApiRoute.ApiRouteBuilder String (List String -> a) (List String -> String) (List String -> constructor)
--Internal.ApiRoute.ApiRouteBuilder pattern _ _ _ ->
-- pattern
--
Internal.ApiRoute.ApiRoute record ->
--record.regex
-- |> Debug.toString
record.pattern |> Debug.toString

View File

@ -79,7 +79,7 @@ async function outputString(
break;
}
case "api-response": {
const body = fromElm.body;
const body = fromElm.body.body;
console.log(`Generated ${pathname}`);
fs.writeFileSyncSafe(path.join("dist", pathname), body);
if (pathname === "/all-paths.json") {

View File

@ -1,6 +1,6 @@
module ApiRoute exposing
( ApiRoute, ApiRouteBuilder, Response, buildTimeRoutes, capture, int, literal, single, slash, succeed, getBuildTimeRoutes
, singleServerless, toJson
, serverless, toJson
)
{-| ApiRoute's are defined in `src/Api.elm` and are a way to generate files, like RSS feeds, sitemaps, or any text-based file that you output with an Elm function! You get access
@ -72,33 +72,27 @@ encodeServerResponse serverResponse =
]
{-| -}
singleServerless : ApiRouteBuilder (DataSource ServerResponse) (List String) -> ApiRoute Response
singleServerless ((ApiRouteBuilder patterns pattern _ toString constructor) as fullHandler) =
serverless : ApiRouteBuilder (DataSource ServerResponse) constructor -> ApiRoute Response
serverless ((ApiRouteBuilder patterns pattern _ toString constructor) as fullHandler) =
ApiRoute
{ regex = Regex.fromString ("^" ++ pattern ++ "$") |> Maybe.withDefault Regex.never
, matchesToResponse =
\path ->
let
routeFound : DataSource Bool
routeFound =
DataSource.succeed ((path |> normalizePath) == (pattern |> normalizePath))
in
routeFound
|> DataSource.andThen
(\found ->
if found then
Internal.ApiRoute.tryMatch path fullHandler
|> Maybe.map (DataSource.map (encodeServerResponse >> Just))
|> Maybe.withDefault (DataSource.succeed Nothing)
else
DataSource.succeed Nothing
)
Internal.ApiRoute.tryMatch path fullHandler
|> Maybe.map (DataSource.map (encodeServerResponse >> Just))
|> Maybe.withDefault
(DataSource.succeed Nothing)
, buildTimeRoutes = DataSource.succeed []
, handleRoute =
\path ->
DataSource.succeed (path == pattern)
DataSource.succeed
(case Internal.ApiRoute.tryMatch path fullHandler of
Just _ ->
True
Nothing ->
False
)
, pattern = patterns
, kind = "serverless"
}

View File

@ -5,6 +5,7 @@ import DataSource
import Expect
import Internal.ApiRoute exposing (tryMatch, withRoutes)
import Pattern exposing (Pattern(..))
import ServerResponse
import Test exposing (Test, describe, test)
@ -15,50 +16,50 @@ all =
\() ->
succeed
(\userId ->
{ body = "Data for user " ++ userId }
"Data for user " ++ userId
)
|> capture
|> tryMatch "123"
|> Expect.equal (Just { body = "Data for user 123" })
|> Expect.equal (Just "Data for user 123")
, test "file with extension" <|
\() ->
succeed
(\userId ->
{ body = "Data for user " ++ userId }
"Data for user " ++ userId
)
|> capture
|> literal ".json"
|> tryMatch "124.json"
|> Expect.equal (Just { body = "Data for user 124" })
|> Expect.equal (Just "Data for user 124")
, test "file path with multiple segments" <|
\() ->
succeed
(\userId ->
{ body = "Data for user " ++ userId }
"Data for user " ++ userId
)
|> literal "users"
|> slash
|> capture
|> literal ".json"
|> tryMatch "users/123.json"
|> Expect.equal (Just { body = "Data for user 123" })
|> Expect.equal (Just "Data for user 123")
, test "integer matcher" <|
\() ->
succeed
(\userId ->
{ body = "Data for user " ++ String.fromInt userId }
"Data for user " ++ String.fromInt userId
)
|> literal "users"
|> slash
|> int
|> literal ".json"
|> tryMatch "users/123.json"
|> Expect.equal (Just { body = "Data for user 123" })
|> Expect.equal (Just "Data for user 123")
, test "routes" <|
\() ->
succeed
(\userId ->
{ body = "Data for user " ++ userId }
"Data for user " ++ userId
)
|> literal "users"
|> slash
@ -78,18 +79,25 @@ all =
[ test "no dynamic segments" <|
\() ->
succeed
(DataSource.succeed { body = "" })
(""
|> ServerResponse.stringBody
|> DataSource.succeed
)
|> literal "no-dynamic-segments.json"
|> ApiRoute.singleServerless
|> ApiRoute.serverless
|> Internal.ApiRoute.toPattern
|> Expect.equal (Pattern [ Pattern.Literal "no-dynamic-segments.json" ] Pattern.NoPendingSlash)
, test "two literal segments" <|
\() ->
ApiRoute.succeed (DataSource.succeed { body = "" })
ApiRoute.succeed
(""
|> ServerResponse.stringBody
|> DataSource.succeed
)
|> ApiRoute.literal "api"
|> ApiRoute.slash
|> ApiRoute.literal "stars"
|> ApiRoute.singleServerless
|> ApiRoute.serverless
|> Internal.ApiRoute.toPattern
|> Expect.equal
(Pattern
@ -102,7 +110,7 @@ all =
\() ->
succeed
(\userId ->
DataSource.succeed { body = "Data for user " ++ userId }
DataSource.succeed ("Data for user " ++ userId)
)
|> literal "users"
|> slash
@ -133,7 +141,7 @@ all =
\() ->
succeed
(\_ _ ->
{ body = "Data for user" }
"Data for user"
)
|> literal "repos"
|> slash
@ -155,7 +163,7 @@ all =
\() ->
succeed
(\username repo branch ->
{ body = [ username, repo, branch ] |> String.join " - " }
[ username, repo, branch ] |> String.join " - "
)
|> literal "repos"
|> slash