Wire through headers, statusCode, and body from ServerResponse. Add redirect example.

This commit is contained in:
Dillon Kearns 2021-12-20 14:45:18 -08:00
parent 84096ec8dc
commit 843ca0bacd
8 changed files with 119 additions and 51 deletions

View File

@ -146,13 +146,11 @@ async function render(event, context) {
statusCode,
};
} else if (renderResult.kind === "api-response") {
const serverResponse = renderResult.body;
return {
body: renderResult.body,
headers: {
"Content-Type": "application/json",
"x-powered-by": "elm-pages",
},
statusCode,
body: serverResponse.body,
headers: serverResponse.headers,
statusCode: serverResponse.statusCode,
};
} else {
return {

View File

@ -10,6 +10,7 @@ import OptimizedDecoder as Decode
import Regex
import Route exposing (Route)
import Secrets
import ServerResponse
routes :
@ -21,9 +22,22 @@ routes getStaticRoutes htmlToString =
--, route2
nonHybridRoute
, noArgs
, redirectRoute
]
redirectRoute : ApiRoute ApiRoute.Response
redirectRoute =
ApiRoute.succeed
(DataSource.succeed
(ServerResponse.permanentRedirect "/")
)
|> ApiRoute.literal "api"
|> ApiRoute.slash
|> ApiRoute.literal "redirect"
|> ApiRoute.singleServerless
noArgs : ApiRoute ApiRoute.Response
noArgs =
ApiRoute.succeed
@ -32,13 +46,11 @@ noArgs =
(Decode.field "stargazers_count" Decode.int)
|> DataSource.map
(\stars ->
{ body =
Json.Encode.object
[ ( "repo", Json.Encode.string "elm-pages" )
, ( "stars", Json.Encode.int stars )
]
|> Json.Encode.encode 2
}
Json.Encode.object
[ ( "repo", Json.Encode.string "elm-pages" )
, ( "stars", Json.Encode.int stars )
]
|> ServerResponse.json
)
)
|> ApiRoute.literal "api"
@ -55,13 +67,11 @@ nonHybridRoute =
(Decode.field "stargazers_count" Decode.int)
|> DataSource.map
(\stars ->
{ body =
Json.Encode.object
[ ( "repo", Json.Encode.string repoName )
, ( "stars", Json.Encode.int stars )
]
|> Json.Encode.encode 2
}
Json.Encode.object
[ ( "repo", Json.Encode.string repoName )
, ( "stars", Json.Encode.int stars )
]
|> Json.Encode.encode 2
)
)
|> ApiRoute.literal "repo"
@ -83,13 +93,11 @@ route1 =
(Decode.field "stargazers_count" Decode.int)
|> DataSource.map
(\stars ->
{ body =
Json.Encode.object
[ ( "repo", Json.Encode.string repoName )
, ( "stars", Json.Encode.int stars )
]
|> Json.Encode.encode 2
}
Json.Encode.object
[ ( "repo", Json.Encode.string repoName )
, ( "stars", Json.Encode.int stars )
]
|> Json.Encode.encode 2
)
)
|> ApiRoute.literal "repo"
@ -107,7 +115,7 @@ route1 =
route2 : ApiRoute ApiRoute.Response
route2 =
ApiRoute.succeed
(DataSource.succeed { body = route1Pattern })
(DataSource.succeed route1Pattern)
|> ApiRoute.literal "api-patterns.json"
|> ApiRoute.single

View File

@ -670,7 +670,7 @@ nextStepToEffect site contentCache config model ( updatedStaticResponsesModel, n
|> (\response ->
case response of
Ok (Just okResponse) ->
{ body = okResponse.body
{ body = okResponse
, staticHttpCache = model.allRawResponses |> Dict.Extra.filterMap (\_ v -> v)
, statusCode = 200
}
@ -678,7 +678,7 @@ nextStepToEffect site contentCache config model ( updatedStaticResponsesModel, n
|> Effect.SendSinglePage True
Ok Nothing ->
{ body = "Hello1!"
{ body = Json.Encode.string "Hello1!"
, staticHttpCache = model.allRawResponses |> Dict.Extra.filterMap (\_ v -> v)
, statusCode = 404
}

View File

@ -9,6 +9,7 @@ import Dict.Extra
import Html exposing (Html)
import HtmlPrinter exposing (htmlToString)
import Internal.ApiRoute exposing (ApiRoute(..))
import Json.Encode
import Pages.Internal.ApplicationType as ApplicationType
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
import Pages.SiteConfig exposing (SiteConfig)
@ -62,7 +63,7 @@ buildTimeFilesRequest config =
Err ""
Just response ->
Ok { path = path |> String.split "/", content = response.body }
Ok { path = path |> String.split "/", content = response |> Json.Encode.encode 0 }
)
)
|> DataSource.combine

View File

@ -74,7 +74,7 @@ headCodec canonicalSiteUrl currentPagePath =
type ToJsSuccessPayloadNewCombined
= PageProgress ToJsSuccessPayloadNew
| SendApiResponse { body : String, staticHttpCache : Dict String String, statusCode : Int }
| SendApiResponse { body : Json.Encode.Value, staticHttpCache : Dict String String, statusCode : Int }
| ReadFile String
| Glob String
| DoHttp { masked : Pages.StaticHttp.Request.Request, unmasked : Pages.StaticHttp.Request.Request }
@ -127,7 +127,7 @@ successCodecNew2 canonicalSiteUrl currentPagePath =
|> Codec.variant1 "ApiResponse"
SendApiResponse
(Codec.object (\body staticHttpCache statusCode -> { body = body, staticHttpCache = staticHttpCache, statusCode = statusCode })
|> Codec.field "body" .body Codec.string
|> Codec.field "body" .body Codec.value
|> Codec.field "staticHttpCache"
.staticHttpCache
(Codec.dict Codec.string)

View File

@ -570,7 +570,7 @@ routePatterns =
.join("\n , ")}
]
|> (\\json -> DataSource.succeed { body = Json.Encode.encode 0 json })
|> (\\json -> DataSource.succeed ( Json.Encode.encode 0 json ))
)
|> ApiRoute.literal "route-patterns.json"
|> ApiRoute.single
@ -585,7 +585,7 @@ apiPatterns =
in
ApiRoute.succeed
(Json.Encode.list identity apiPatternsString
|> (\\json -> DataSource.succeed { body = Json.Encode.encode 0 json })
|> (\\json -> DataSource.succeed ( Json.Encode.encode 0 json ))
)
|> ApiRoute.literal "api-patterns.json"
|> ApiRoute.single
@ -633,11 +633,9 @@ pathsToGenerateHandler =
ApiRoute.succeed
(DataSource.map2
(\\pageRoutes apiRoutes ->
{ body =
(pageRoutes ++ (apiRoutes |> List.map (\\api -> "/" ++ api)))
|> Json.Encode.list Json.Encode.string
|> Json.Encode.encode 0
}
(pageRoutes ++ (apiRoutes |> List.map (\\api -> "/" ++ api)))
|> Json.Encode.list Json.Encode.string
|> Json.Encode.encode 0
)
(DataSource.map
(List.map
@ -674,14 +672,11 @@ manifestHandler =
|> ApiRoute.single
manifestToFile : String -> Manifest.Config -> { body : String }
manifestToFile : String -> Manifest.Config -> String
manifestToFile resolvedCanonicalUrl manifestConfig =
manifestConfig
|> Manifest.toJson resolvedCanonicalUrl
|> (\\manifestJsonValue ->
{ body = Json.Encode.encode 0 manifestJsonValue
}
)
|> (\\manifestJsonValue -> Json.Encode.encode 0 manifestJsonValue)
port toJsPort : Json.Encode.Value -> Cmd msg

View File

@ -27,7 +27,7 @@ type alias ApiRoute response =
{-| -}
single : ApiRouteBuilder (DataSource Response) (List String) -> ApiRoute Response
single : ApiRouteBuilder (DataSource String) (List String) -> ApiRoute Response
single handler =
handler
|> buildTimeRoutes (\constructor -> DataSource.succeed [ constructor ])
@ -58,8 +58,21 @@ stripTrailingSlash path =
path
encodeServerResponse : ServerResponse -> Response
encodeServerResponse serverResponse =
Json.Encode.object
[ ( "body", serverResponse.body |> Maybe.map Json.Encode.string |> Maybe.withDefault Json.Encode.null )
, ( "statusCode", serverResponse.statusCode |> Json.Encode.int )
, ( "headers"
, serverResponse.headers
|> List.map (Tuple.mapSecond Json.Encode.string)
|> Json.Encode.object
)
]
{-| -}
singleServerless : ApiRouteBuilder (DataSource Response) (List String) -> ApiRoute Response
singleServerless : ApiRouteBuilder (DataSource ServerResponse) (List String) -> ApiRoute Response
singleServerless ((ApiRouteBuilder patterns pattern _ toString constructor) as fullHandler) =
ApiRoute
{ regex = Regex.fromString ("^" ++ pattern ++ "$") |> Maybe.withDefault Regex.never
@ -75,7 +88,7 @@ singleServerless ((ApiRouteBuilder patterns pattern _ toString constructor) as f
(\found ->
if found then
Internal.ApiRoute.tryMatch path fullHandler
|> Maybe.map (DataSource.map Just)
|> Maybe.map (DataSource.map (encodeServerResponse >> Just))
|> Maybe.withDefault (DataSource.succeed Nothing)
else
@ -90,8 +103,13 @@ singleServerless ((ApiRouteBuilder patterns pattern _ toString constructor) as f
}
encodeStaticFileBody : String -> Response
encodeStaticFileBody fileBody =
fileBody |> Json.Encode.string
{-| -}
buildTimeRoutes : (constructor -> DataSource (List (List String))) -> ApiRouteBuilder (DataSource Response) constructor -> ApiRoute Response
buildTimeRoutes : (constructor -> DataSource (List (List String))) -> ApiRouteBuilder (DataSource String) constructor -> ApiRoute Response
buildTimeRoutes buildUrls ((ApiRouteBuilder patterns pattern _ toString constructor) as fullHandler) =
let
buildTimeRoutes__ : DataSource (List String)
@ -122,7 +140,7 @@ buildTimeRoutes buildUrls ((ApiRouteBuilder patterns pattern _ toString construc
(\found ->
if found then
Internal.ApiRoute.tryMatch path fullHandler
|> Maybe.map (DataSource.map Just)
|> Maybe.map (DataSource.map (encodeStaticFileBody >> Just))
|> Maybe.withDefault (DataSource.succeed Nothing)
else
@ -150,7 +168,14 @@ type alias ApiRouteBuilder a constructor =
{-| -}
type alias Response =
{ body : String }
Json.Encode.Value
type alias ServerResponse =
{ statusCode : Int
, headers : List ( String, String )
, body : Maybe String
}
{-| -}

41
src/ServerResponse.elm Normal file
View File

@ -0,0 +1,41 @@
module ServerResponse exposing (ServerResponse, json, permanentRedirect, success)
import Json.Encode
type alias ServerResponse =
{ statusCode : Int
, headers : List ( String, String )
, body : Maybe String
}
success : ServerResponse
success =
{ statusCode = 200
, headers = []
, body = Nothing
}
json : Json.Encode.Value -> ServerResponse
json jsonValue =
{ statusCode = 200
, headers =
[ ( "Content-Type", "application/json" )
]
, body =
jsonValue
|> Json.Encode.encode 0
|> Just
}
permanentRedirect : String -> ServerResponse
permanentRedirect url =
{ body = Nothing
, statusCode = 308
, headers =
[ ( "Location", url )
]
}