BeaconCMS/beacon

How to handle "not found" with Beacon.DataSource.Behaviour?

kwando opened this issue · 5 comments

kwando commented

How do we handle when data is not found in my BeaconDataSource? For instance in the demo app, what if I navigate to a blog post that does not exist?

Is there someway of signal back to beacon?
Maybe some async features here as well if the data is slow to get?

what if I navigate to a blog post that does not exist?

It depends how you structure your site and pages, for eg on dockyard.com each blog post is a page so visiting a broken url will render a 404 page, eg: https://dockyard.com/blog/2023/11/01/nothing-here
Such pages can be created and styled in the Admin interface since we merged support for error pages. It provides a default implementation too.

How do we handle when data is not found in my BeaconDataSource?

At this moment it's up to you to make sure the data source is correct and you're calling an existing key. This process will be easier after we get to merge BeaconCMS/beacon_live_admin#84 which will let you manage the data source in the admin interface at runtime. Besides that, I've been discussing this problem with @APB9785 and exploring ways to warn users about incorrect data source, the issue to track is #369

async features here as well if the data is slow to get?
Async and caching is not yet planned but I can see it'll be necessary eventually. It's too early to define the architecture for both but they would probably be implemented after LV async and Nextjs Data Caching, respectively. Just created two issues to keep track of it: #371 and #370

I hope that answer your questions so I'm closing the issue, but feel free to post more comments. Thanks!

kwando commented

Maybe I'm just confused with how the Datasource-thingy should work..

def live_data(:blog, ["posts", post_slug], _params) do
   case BlogPosts.fetch_blog_post_by_slug(post_slug) do
       {:ok, post} -> post
       :error -> 
         nil    # <==== what to return here to render a 404? nil? raise error?
   end
end

For this situation, you can define your own custom exception which is treated as 404 by Phoenix:

defmodule YourApp.PageNotFoundError do
  defexception plug_status: 404, message: nil, path: nil

  def exception(opts) do
    path = Keyword.fetch!(opts, :path)

    %__MODULE__{message: "Page not found for path: #{Enum.join(path, "/")}", path: path}
  end
end

and then in your live_data handler:

def live_data(:blog, ["posts", post_slug] = path, _params) do
  case BlogPosts.fetch_blog_post_by_slug(post_slug) do
    {:ok, post} -> %{post: post}
    :error -> raise YourApp.PageNotFoundError, path: path
  end
end

Note the successful case creates a map of live_data assigns, which will be used in your template.

kwando commented

Oh, didn't consider that option 😅

Not a fan of raising exceptions for non exceptional cases, but at least there is something.