DataSource rename to BackendTasks, and Exception Handling #355
Replies: 2 comments 4 replies
-
The idea of passing off the handling of an exception to the runtime sounds really nice! It immediately reminded me of my recent use of As far as naming, I definitely like the move away from I do wonder, and may try to see, if I can use elm-pages as a cli for running my toy language instead of elm-posix. The idea of it possibly caching sounds intriguing for a cli tool, especially since I want to load data from both the file system and uris. Also sounds nice as I've been doing Advent of Code and I'm always nervous to do what some people do and hit the website directly to get the input instead of manually copy/pasting it. |
Beta Was this translation helpful? Give feedback.
-
Just a thought about the name BackendTask: wouldn't it be better named BuildTask? Backend is something I usually associate with a server running after build/deployment. |
Beta Was this translation helpful? Give feedback.
-
Background
With the new features in the elm-pages v3 beta, I've taken a step back to think about the core abstraction of elm-pages. For example, with server-rendered routes, and
action
s, DataSource's have expanded to do more than just pulling in static data. Now it is used for:elm-pages run
commandThis means it is likely you will want to do more sophisticated things like recovering from HTTP errors (if an HTTP API request fails with validations, for example). And the abstraction isn't only about pulling in data - when the only goal is to fire and forget an effectful API request, the term DataSource doesn't fit so well.
Changes: Rename to BackendTask and Exceptions
To better reflect this, I'm making 3 changes around DataSources:
DataSource
->BackendTask
DataSource value
->BackendTask error value
BackendTask
can cause an error or not by its error type variable - for example,BackendTask.succeed "Hello"
gives youBackendTask error String
. You don't need to usethrow
when there are no possible errors like inBackendTask.succeed
Here's what that looks like in practice. A few things to notice in this example:
Exception
type is useful for taking aBackendTask
's error values in one of two paths: throwing to ignore the error and pass it up to the framework if something goes wrong, or catch to unwrap the nicely typed error data so you can handle itBackendTask.throw : BackendTask (Catchable error) data -> BackendTask Throwable data
- this is in contrast toBackendTask.catch : BackendTask (Catchable error) value -> BackendTask error value
BackendTask.File
,BackendTask.Glob
,BackendTask.Http
have nicely typed error data and return their own error types wrapped withCatchable
. But users can createCatchable error
types to enable this same flow, or they can directly create aThrowable
which can lets the framework handle the unexpected errorhttps://github.com/dillonkearns/elm-pages-v3-beta/blob/backend-tasks/examples/docs/app/Route/Docs/Section__.elm#L133-L164
elm-pages Exceptions compared to traditional exception handling
I'm not a fan of exceptions in other languages because of the way they introduce a new control flow mechanism, and because you can't tell which code could have a possible exception lurking, or whether the code above it is handling exceptions or not. There is also a strange back-and-forth where you could throw and catch exceptions at different levels and pass an error multiple directions.
With this abstraction, I think of this as "Managed Exceptions", just as many languages have side-effects while Elm has "Managed Effects." Similar to Managed Effects in Elm, Exceptions in elm-pages don't do anything in themselves, rather they need to be passed to the framework. Elm Managed Effects need to be passed to
init
orupdate
, and elm-pages Exceptions need to be the final result of theerror
type variable inBackendTask Throwable value
(whereThrowable
is just an alias toException ()
).The goal here is to give you explicitness of errors that come in vanilla Elm
Tasks
, but whereas regular Task's give you aMsg
with aResult
in it that you always need to explicitly handle,elm-pages
BackendTask
s give you a way to not handle certain error cases yourself but pass them to the framework to give an error status in the CLI or a server error code response for errors that you don't want to explicitly handle. So you have all the explicitness of error handling that we're familiar with in Elm and Task's, but the added convenience that we can let the framework give us nice error messages for cases that we don't expect and don't want to catch.Performing all BackendTask's
Previously, DataSource's would cache all previous results in the chain of DataSource running, so if you hit an API it would never make that exact same API request twice but instead would just use the previous result.
This abstraction doesn't work for new effectful uses, such as
elm-pages run
scripts, or hitting effectful APIs from anaction
, where you want to be sure those effects are performed each time they're called.It may take some iteration to figure out a nice way to allow for caching when the user wants it, for example to only make a given API request once and cache it any other time it's hit.
Feedback
I'd love to hear from you if you have thoughts on these APIs. Thanks for reading!
Beta Was this translation helpful? Give feedback.
All reactions