Serverless elm-pages #169
Replies: 1 comment 2 replies
-
StaticHttp in an On-Demand ContextOne of the really interesting things about StaticHttp is that you don't have an When running a Handling HTTP Errors as data in StaticHttp requestsMy current thinking for this is that the missing piece is a function like this: StaticHttp.requestResult :
Pages.Secrets.Value RequestDetails
-> OptimizedDecoder.Decoder a
-> StaticHttp.Request (Result Http.Error a) For example, if you make an HTTP request that gives a 403 Unauthorized status code if a user doesn't have access to a resource, you may want to use that status code "as data" in your StaticHttp request. You could then check for that, and proceed to turn it into whatever data you want. You can also respond in server-side rendered So the idea is that you have access to those errors as data, and then you can turn it into whatever resulting response that you want to. StaticHttp errorsWhat if the user makes a StaticHttp.Request and assumes it will succeed, so they use something like I have a few ideas on the different directions this could go:
I'm leaning towards (1), but I'd be curious to hear thoughts on this. |
Beta Was this translation helpful? Give feedback.
-
Right now
elm-pages
builds a set of compiled Elm, pre-rendered HTML, JSON files, files from fileGenerators, and copied assets fromimages/
andstatic/
during the build step. So right now the lifecycle is:Browser.application
Elm app is hydrated and takes over the initial pre-rendered HTML page)I'm working on a prototype for supporting a new part of the lifecycle: On Server/Serverless Request.
There are a lot of design decisions involved in this architecture, so I'm laying out my current thoughts and goals here.
You can see a rough prototype live here:
Main Areas
The main feature areas here are:
The current mental model I have in mind for Pages Routes is that they are either server-rendered at request time, or pre-rendered at build time.
Page Routes
Use Cases
Some uses for server-rendered pages would be:
Design Ideas
There are a few important design decisions to solidify here. I'll just list the decisions that I'm leaning towards now
Shared
Template Modules StaticHttp request. The reason is that this could be confusing because this data is built up at build time (and if it was re-fetched, it could cause it to be out of sync with some data). For example, if you get the current GitHub Stars in the Shared staticData, then server rendered pages could have a different number in the header star count than static pages on subsequent client-side navigationsprepare
step which builds upContext
for the request. The StaticHttp requests inprepare
don't result in any data being bundled into the server-rendered payload. You provide aCodec
to explicitly pick the context that you want to have in the bundle. Then you can make follow-up StaticHttp requests that will be included from there in the final payload.API Routes
For API Routes, my current thinking is that the existing
withFileGenerator
hook will remain the same. This allows you to generate arbitrary static files during the build.API Routes are similar to file generators, except they have access to the request payload. Another important distinction is that file generators are all executed during the build step. But with API Routes, we need to be able to execute a single specific one. So the current internals for
generateFiles
wouldn't work well because you need to resolve aStaticHttp.Request
in order to find out its file path:A file generator is generating a specific set of files during the build. API Routes could potentially register to handle arbitrary dynamic routes. So conceptually the route matcher is more of a "give me the request, and I'll decide whether I can handle it."
It might look something like this:
A few things to note here:
Just
first when given the incoming RequestPayloadJson.Encode.Value
because the response could be different types depending on which service you're hosting with under the hood (Netlify, Vercel, etc). See the section on Hosting Adapters. The encoded JSON response may include cache hints to give to the provider, the raw body, status code, etc.Typed Elm API Handlers (possible idea for a future iteration)
The API Routing I described above is a pretty general purpose way of using StaticHttp functionality to respond on-demand to API requests. You could use that as the low-level building block for some higher-level functionality that makes some assumptions.
Some assumptions we could make:
Api.ShopSession
would give you an API route //ShopSession.jsonWith those assumptions, we could add a higher-level feature for making API endpoints that users could use in addition to the low-level API Routing functionality. Here's what it might look like to define one of these Elm JSON API endpoints:
So then from some Elm code, you could consume it in a more type-safe way like this by leverage the Codec you defined.
An example use case where you could use this:
You have an
elm-pages
route that you want to statically generate for performance reasons. But once the page is hydrated into an Elm app, you want to make an HTTP request oninit
to get some fresh data about things like inventory, etc.Hosting Adapters
I've been following some of the designs that SvelteKit has been coming up with. Their Adapter layer for different hosting providers is the basis of my thinking for this design. For example, here's their current Netlify adapter. It's a Node script that writes out some configuration files and copies some compiled assets to the appropriate places for that hosting provider.
For the first iteration of this functionality,
elm-pages
might just run a specific file, like sayhosting-adapter.js
, if that file exists in the root folder. It would run it when it's doing runningelm-pages build
.Beta Was this translation helpful? Give feedback.
All reactions