Turn a Result into a Request. Useful with andThen. Turns Err into a skipped request handler (non-matching request),
and Ok values into a succeed (matching request).
This is a Request.Parser that will never match an HTTP request. Similar to Json.Decode.fail.
Why would you want it to always fail? It's helpful for building custom Server.Request.Parser. For example, let's say
you wanted to define a custom Server.Request.Parser to use an XML Decoding package on the request body.
You could define a custom function like this
import Server.Request as Request
expectXmlBody : XmlDecoder value -> Request.Parser value
expectXmlBody xmlDecoder =
Request.expectBody
|> Request.andThen
(\bodyAsString ->
case runXmlDecoder xmlDecoder bodyAsString of
Ok decodedXml ->
Request.succeed decodedXml
Err error ->
Request.skip ("XML could not be decoded " ++ xmlErrorToString error)
)
Note that when we said Request.skip, remaining Request Parsers will run (for example if you use Server.Request.oneOf).
You could build this with different semantics if you wanted to handle any valid XML body. This Request Parser will not
handle any valid XML body. It will only handle requests that can match the XmlDecoder that is passed in.
So when you define your Server.Request.Parsers, think carefully about whether you want to handle invalid cases and give an
error, or fall through to other Parsers. There's no universal right answer, it's just something to decide for your use case.
expectXmlBody : Request.Parser value
expectXmlBody =
Request.map2
acceptContentTypes
Request.expectBody
|> Request.andThen
(\bodyAsString ->
case runXmlDecoder xmlDecoder bodyAsString of
Ok decodedXml ->
Request.succeed decodedXml
Err error ->
Request.skip ("XML could not be decoded " ++ xmlErrorToString error)
)
Decode an argument and provide it to a function in a decoder.
decoder : Decoder String
decoder =
succeed (String.repeat)
|> andMap (field "count" int)
|> andMap (field "val" string)
""" { "val": "hi", "count": 3 } """
|> decodeString decoder
--> Success "hihihi"
Same as rawBody, but will only match when a body is present in the HTTP request.
Gets the HTTP Method as a String, like 'GET', 'PUT', etc.
TODO internal only
TODO internal only
A
Server.Request.Parserlets you send aServer.Response.Responsebased on an incoming HTTP request. For example, using aServer.Request.Parser, you could check a session cookie to decide whether to respond by rendering a page for the logged-in user, or else respond with an HTTP redirect response (see theServer.Responsedocs).You can access the incoming HTTP request's:
methodrequestTime(as aTime.Posix)Note that this data is not available for pre-rendered pages or pre-rendered API Routes, only for server-rendered pages. This is because when a page is pre-rendered, there is no incoming HTTP request to respond to, it is rendered before a user requests the page and then the pre-rendered page is served as a plain file (without running your Route Module).
That's why
RouteBuilder.preRenderhasdata : RouteParams -> BackendTask Data:import BackendTask exposing (BackendTask) import RouteBuilder exposing (StatelessRoute) type alias Data = {} data : RouteParams -> BackendTask Data data routeParams = BackendTask.succeed Data route : StatelessRoute RouteParams Data ActionData route = RouteBuilder.preRender { data = data , head = head , pages = pages } |> RouteBuilder.buildNoState { view = view }A server-rendered Route Module does have access to a user's incoming HTTP request because it runs every time the page is loaded. That's why
datais aRequest.Parserin server-rendered Route Modules. Since you have an incoming HTTP request for server-rendered routes,RouteBuilder.serverRenderhasdata : RouteParams -> Request.Parser (BackendTask (Response Data)). That means that you can use the incoming HTTP request data to choose how to respond. For example, you could check for a dark-mode preference cookie and render a light- or dark-themed page and render a different page.That's a mouthful, so let's unpack what it means.
Request.Parsermeans you can pull outdata from the request payload using a Server Request Parser.
import BackendTask exposing (BackendTask) import RouteBuilder exposing (StatelessRoute) import Server.Request as Request exposing (Request) import Server.Response as Response exposing (Response) type alias Data = {} data : RouteParams -> Request.Parser (BackendTask (Response Data)) data routeParams = {} |> Server.Response.render |> BackendTask.succeed |> Request.succeed route : StatelessRoute RouteParams Data ActionData route = RouteBuilder.serverRender { head = head , data = data } |> RouteBuilder.buildNoState { view = view }