Wire through custom headers and status codes for RenderPage server responses.

This commit is contained in:
Dillon Kearns 2022-01-17 16:56:40 -08:00
parent c27377c8f7
commit 03dd16a86f
19 changed files with 80 additions and 33 deletions

View File

@ -144,7 +144,7 @@ async function render(event, context) {
);
console.log("@@@renderResult", JSON.stringify(renderResult, null, 2));
const statusCode = renderResult.is404 ? 404 : 200;
const statusCode = renderResult.is404 ? 404 : renderResult.statusCode;
if (renderResult.kind === "json") {
return {
@ -152,6 +152,7 @@ async function render(event, context) {
headers: {
"Content-Type": "application/json",
"x-powered-by": "elm-pages",
...renderResult.headers,
},
statusCode,
};
@ -169,6 +170,7 @@ async function render(event, context) {
headers: {
"Content-Type": "text/html",
"x-powered-by": "elm-pages",
...renderResult.headers,
},
statusCode,
};

View File

@ -24,7 +24,7 @@ data _ =
DataSource.Http.get (Secrets.succeed "https://elm-pages-pokedex.netlify.app/.netlify/functions/time")
Decode.string
|> DataSource.map Data
|> DataSource.map PageServerResponse.RenderPage
|> DataSource.map PageServerResponse.render
head : (routeParams -> String) -> StaticPayload Data routeParams -> List Head.Tag

View File

@ -48,10 +48,10 @@ data routeParams =
)
|> Request.map
(\file ->
DataSource.succeed (PageServerResponse.RenderPage (Just file))
DataSource.succeed (PageServerResponse.render (Just file))
)
, Request.succeed
(DataSource.succeed (PageServerResponse.RenderPage Nothing))
(DataSource.succeed (PageServerResponse.render Nothing))
]

View File

@ -215,7 +215,7 @@ data routeParams =
, { user = Nothing
, errors = Form.init (form defaultUser)
}
|> PageServerResponse.RenderPage
|> PageServerResponse.render
|> DataSource.succeed
|> Request.succeed
]

View File

@ -49,6 +49,11 @@ data routeParams =
(\requestData ->
requestData
|> PageServerResponse.RenderPage
{ statusCode = 200
, headers =
[ ( "x-greeting", "hello there " ++ requestData.username ++ "!" )
]
}
|> DataSource.succeed
)
, Request.map2 Data
@ -58,6 +63,11 @@ data routeParams =
(\requestData ->
requestData
|> PageServerResponse.RenderPage
{ statusCode = 200
, headers =
[ ( "x-greeting", "hello " ++ requestData.username ++ "!" )
]
}
|> DataSource.succeed
)
, Request.succeed

View File

@ -67,7 +67,7 @@ data routeParams =
(\name ->
name
|> Data
|> PageServerResponse.RenderPage
|> PageServerResponse.render
|> DataSource.succeed
)
]

View File

@ -68,7 +68,7 @@ data { pokedexNumber } =
(Decode.field "types" (Decode.list (Decode.field "type" (Decode.field "name" Decode.string))))
)
)
|> DataSource.map PageServerResponse.RenderPage
|> DataSource.map PageServerResponse.render
notFoundResponse : String -> DataSource (PageServerResponse Data)

View File

@ -60,12 +60,12 @@ data routeParams =
|> DataSource.succeed
|> DataSource.andMap (DataSource.File.rawFile "examples/pokedex/content/secret-note.txt")
|> DataSource.map LoggedIn
|> DataSource.map PageServerResponse.RenderPage
|> DataSource.map PageServerResponse.render
)
, Request.succeed
(NotLoggedIn
|> DataSource.succeed
|> DataSource.map PageServerResponse.RenderPage
|> DataSource.map PageServerResponse.render
--"/login"
-- |> ServerResponse.temporaryRedirect
-- --|> ServerResponse.withStatusCode 404

View File

@ -619,7 +619,7 @@ data routeParams =
, { user = Nothing
, initialForm = Form.init (form defaultUser)
}
|> PageServerResponse.RenderPage
|> PageServerResponse.render
|> DataSource.succeed
|> Request.succeed
]

View File

@ -266,7 +266,7 @@ single :
-> Builder {} data
single { data, head } =
WithData
{ data = \_ -> data |> DataSource.map PageServerResponse.RenderPage
{ data = \_ -> data |> DataSource.map PageServerResponse.render
, staticRoutes = DataSource.succeed [ {} ]
, head = head
, serverless = False
@ -284,7 +284,7 @@ preRender :
-> Builder routeParams data
preRender { data, head, pages } =
WithData
{ data = data >> DataSource.map PageServerResponse.RenderPage
{ data = data >> DataSource.map PageServerResponse.render
, staticRoutes = pages
, head = head
, serverless = False

View File

@ -192,7 +192,7 @@ init config flags url key =
case Result.map2 Tuple.pair sharedDataResult pageDataResult of
Ok ( sharedData, pageData_ ) ->
case pageData_ of
PageServerResponse.RenderPage pageData ->
PageServerResponse.RenderPage responseInfo pageData ->
let
userFlags : Pages.Flags.Flags
userFlags =
@ -477,7 +477,7 @@ update config appMsg model =
|> Result.andThen
(\pageResponse ->
case pageResponse of
PageServerResponse.RenderPage renderPagePageData ->
PageServerResponse.RenderPage responseInfo renderPagePageData ->
Ok renderPagePageData
PageServerResponse.ServerResponse _ ->
@ -575,7 +575,7 @@ update config appMsg model =
case Result.map2 Tuple.pair sharedDataResult pageDataResult of
Ok ( sharedData, pageData_ ) ->
case pageData_ of
PageServerResponse.RenderPage pageData ->
PageServerResponse.RenderPage responseInfo pageData ->
let
updateResult : Maybe ( userModel, Cmd userMsg )
updateResult =

View File

@ -726,7 +726,7 @@ nextStepToEffect site contentCache config model ( updatedStaticResponsesModel, n
case includeHtml of
RenderRequest.OnlyJson ->
Ok
(PageServerResponse.RenderPage
(PageServerResponse.render
{ head = []
, view = "This page was not rendered because it is a JSON-only request."
, title = "This page was not rendered because it is a JSON-only request."
@ -738,7 +738,7 @@ nextStepToEffect site contentCache config model ( updatedStaticResponsesModel, n
|> Result.map
(\( pageData_, sharedData ) ->
case pageData_ of
PageServerResponse.RenderPage pageData ->
PageServerResponse.RenderPage responseInfo pageData ->
let
pageModel : userModel
pageModel =
@ -763,7 +763,7 @@ nextStepToEffect site contentCache config model ( updatedStaticResponsesModel, n
viewValue =
(config.view currentPage Nothing sharedData pageData |> .view) pageModel
in
PageServerResponse.RenderPage
PageServerResponse.RenderPage responseInfo
{ head = config.view currentPage Nothing sharedData pageData |> .head
, view = viewValue.body |> HtmlPrinter.htmlToString
, title = viewValue.title
@ -808,7 +808,7 @@ nextStepToEffect site contentCache config model ( updatedStaticResponsesModel, n
case Result.map3 (\a b c -> ( a, b, c )) pageFoundResult renderedResult siteDataResult of
Ok ( pageFound, renderedOrApiResponse, siteData ) ->
case renderedOrApiResponse of
PageServerResponse.RenderPage rendered ->
PageServerResponse.RenderPage responseInfo rendered ->
{ route = payload.path |> Path.toRelative
, contentJson =
--toJsPayload.pages
@ -821,6 +821,8 @@ nextStepToEffect site contentCache config model ( updatedStaticResponsesModel, n
, title = rendered.title
, staticHttpCache = model.allRawResponses |> Dict.Extra.filterMap (\_ v -> v)
, is404 = False
, statusCode = responseInfo.statusCode
, headers = responseInfo.headers
}
|> ToJsPayload.PageProgress
|> Effect.SendSinglePage False
@ -896,7 +898,7 @@ sendSinglePageProgress site contentJson config model =
case includeHtml of
RenderRequest.OnlyJson ->
Ok
(PageServerResponse.RenderPage
(PageServerResponse.render
{ head = []
, view = "This page was not rendered because it is a JSON-only request."
, title = "This page was not rendered because it is a JSON-only request."
@ -908,7 +910,7 @@ sendSinglePageProgress site contentJson config model =
|> Result.map
(\( pageData_, sharedData ) ->
case pageData_ of
PageServerResponse.RenderPage pageData ->
PageServerResponse.RenderPage responseInfo pageData ->
let
pageModel : userModel
pageModel =
@ -933,7 +935,7 @@ sendSinglePageProgress site contentJson config model =
viewValue =
(config.view currentPage Nothing sharedData pageData |> .view) pageModel
in
PageServerResponse.RenderPage
PageServerResponse.RenderPage responseInfo
{ head = config.view currentPage Nothing sharedData pageData |> .head
, view = viewValue.body |> HtmlPrinter.htmlToString
, title = viewValue.title
@ -983,7 +985,7 @@ sendSinglePageProgress site contentJson config model =
case maybeNotFoundReason of
Nothing ->
case renderedOrApiResponse of
PageServerResponse.RenderPage rendered ->
PageServerResponse.RenderPage responseInfo rendered ->
{ route = page |> Path.toRelative
, contentJson = contentJson
, html = rendered.view
@ -992,6 +994,8 @@ sendSinglePageProgress site contentJson config model =
, title = rendered.title
, staticHttpCache = model.allRawResponses |> Dict.Extra.filterMap (\_ v -> v)
, is404 = False
, statusCode = responseInfo.statusCode
, headers = responseInfo.headers
}
|> ToJsPayload.PageProgress
|> Effect.SendSinglePage True
@ -1049,6 +1053,8 @@ render404Page config model path notFoundReason =
, title = notFoundDocument.title
, staticHttpCache = model.allRawResponses |> Dict.Extra.filterMap (\_ v -> v)
, is404 = True
, statusCode = 404
, headers = []
}
|> ToJsPayload.PageProgress
|> Effect.SendSinglePage True

View File

@ -22,6 +22,8 @@ type alias ToJsSuccessPayloadNew =
, title : String
, staticHttpCache : Dict String String
, is404 : Bool
, statusCode : Int
, headers : List ( String, String )
}
@ -63,6 +65,10 @@ successCodecNew canonicalSiteUrl currentPagePath =
.staticHttpCache
(Codec.dict Codec.string)
|> Codec.field "is404" .is404 Codec.bool
|> Codec.field "statusCode" .statusCode Codec.int
|> Codec.field "headers"
.headers
(Codec.dict Codec.string |> Codec.map Dict.toList Dict.fromList)
|> Codec.buildObject

View File

@ -198,13 +198,13 @@ data =`
? `Request.succeed ()
|> Request.thenRespond
(\\() ->
DataSource.succeed (PageServerResponse.RenderPage {})
DataSource.succeed (PageServerResponse.render {})
)
`
: withFallback
? ` Data
|> DataSource.succeed
|> DataSource.map PageServerResponse.RenderPage
|> DataSource.map PageServerResponse.render
`
: `DataSource.succeed {}`
}

View File

@ -367,15 +367,17 @@ async function start(options) {
const is404 = renderResult.is404;
switch (renderResult.kind) {
case "json": {
res.writeHead(is404 ? 404 : 200, {
res.writeHead(is404 ? 404 : renderResult.statusCode, {
"Content-Type": "application/json",
...renderResult.headers,
});
res.end(renderResult.contentJson);
break;
}
case "html": {
res.writeHead(is404 ? 404 : 200, {
res.writeHead(is404 ? 404 : renderResult.statusCode, {
"Content-Type": "text/html",
...renderResult.headers,
});
res.end(renderResult.htmlString);
break;

View File

@ -459,7 +459,7 @@ dataForRoute : Maybe Route -> DataSource (PageServerResponse PageData)
dataForRoute route =
case route of
Nothing ->
DataSource.succeed (PageServerResponse.RenderPage Data404NotFoundPage____)
DataSource.succeed (PageServerResponse.RenderPage { statusCode = 400, headers = [] } Data404NotFoundPage____)
${templates
.map(
(name) =>

View File

@ -138,6 +138,8 @@ function runElmApp(
staticData: args.contentJson,
is404: args.is404,
}),
statusCode: args.statusCode,
headers: args.headers,
});
} else {
resolve(outputString(basePath, fromElm, isDevServer));
@ -192,6 +194,8 @@ async function outputString(
contentJson["staticData"] = args.contentJson;
contentJson["is404"] = args.is404;
contentJson["path"] = args.route;
contentJson["statusCode"] = args.statusCode;
contentJson["headers"] = args.headers;
const normalizedRoute = args.route.replace(/index$/, "");
return {
@ -199,6 +203,8 @@ async function outputString(
route: normalizedRoute,
htmlString: preRenderHtml(basePath, args, contentJson, isDevServer),
contentJson: args.contentJson,
statusCode: args.statusCode,
headers: args.headers,
kind: "html",
};
}

View File

@ -2002,7 +2002,8 @@ submitHandlers myForm toDataSource =
Err model ->
Err () |> toDataSource model
)
|> DataSource.map PageServerResponse.RenderPage
-- TODO allow customizing headers or status code, or not?
|> DataSource.map PageServerResponse.render
)
]

View File

@ -1,4 +1,7 @@
module PageServerResponse exposing (map, PageServerResponse(..))
module PageServerResponse exposing
( map, PageServerResponse(..)
, render
)
{-|
@ -11,16 +14,27 @@ import Server.Response exposing (Response)
{-| -}
type PageServerResponse data
= RenderPage data
= RenderPage
{ statusCode : Int
, headers : List ( String, String )
}
data
| ServerResponse Response
render : data -> PageServerResponse data
render data =
RenderPage
{ statusCode = 200, headers = [] }
data
{-| -}
map : (data -> mappedData) -> PageServerResponse data -> PageServerResponse mappedData
map mapFn pageServerResponse =
case pageServerResponse of
RenderPage data ->
RenderPage (mapFn data)
RenderPage response data ->
RenderPage response (mapFn data)
ServerResponse serverResponse ->
ServerResponse serverResponse