StaticBlog.Micropub (StaticBlog v0.2.0)

Copy Markdown View Source

Business logic for the Micropub endpoint.

Handles the three directions the protocol needs to flow:

  • properties_from_params/1 — parse an incoming create request into a normalized map of post properties.
  • create/1 — turn normalized properties into a markdown file on disk.
  • update/3 and delete/1 — mutate an existing post addressed by its URL.
  • source/2 — serialise a post back into MF2 JSON for editing clients.

Summary

Functions

Create a new post from a normalized properties/0 map.

Delete the post at the given canonical URL.

Normalize an incoming create request into a properties/0 map.

Serialize post attributes and body back to the %{...}---body file format.

Extract the blog post slug from a canonical post URL.

Convert a title into a URL-safe slug.

Return the MF2 JSON representation of a post for a Micropub source query.

Update an existing post, identified by its canonical URL.

Build the canonical URL for a post slug using the configured base URL.

Types

properties()

@type properties() :: %{
  optional(:title) => String.t(),
  optional(:content) => String.t(),
  optional(:tags) => [String.t()],
  optional(:date) => Date.t(),
  optional(:slug) => String.t(),
  optional(:author) => String.t(),
  optional(:description) => String.t(),
  optional(:status) => StaticBlog.Post.status()
}

Functions

create(properties)

@spec create(properties()) :: {:ok, String.t()} | {:error, atom()}

Create a new post from a normalized properties/0 map.

Arguments

Returns

  • {:ok, url} where url is the canonical URL on the configured site.

  • {:error, reason} if required fields are missing.

delete(url)

@spec delete(String.t()) :: :ok | {:error, :not_found | :invalid_url}

Delete the post at the given canonical URL.

Arguments

  • url is the canonical URL of the post to remove.

Returns

  • :ok on success.

  • {:error, :not_found} if no post exists at that URL.

properties_from_params(json)

@spec properties_from_params(map()) :: properties()

Normalize an incoming create request into a properties/0 map.

Handles both JSON-encoded Micropub payloads (where properties live under a "properties" key and values are arrays) and form-encoded payloads (where values are scalars or repeated keys).

Arguments

  • params is the decoded request body as a map.

Returns

serialize(attrs, body)

@spec serialize(map(), String.t()) :: String.t()

Serialize post attributes and body back to the %{...}---body file format.

Arguments

  • attrs is a map with :title, :author, :tags, and :description.

  • body is the markdown body string.

Returns

  • A binary ready to be written to disk.

slug_from_url(url)

@spec slug_from_url(String.t()) :: {:ok, String.t()} | {:error, :invalid_url}

Extract the blog post slug from a canonical post URL.

Arguments

  • url is a URL of the form <base>/posts/<slug>/ (trailing slash optional).

Returns

  • {:ok, slug} if the URL matches the expected shape.

  • {:error, :invalid_url} otherwise.

slugify(title)

@spec slugify(String.t()) :: String.t()

Convert a title into a URL-safe slug.

Arguments

  • title is the post title.

Returns

  • A lowercase, dash-separated slug string.

source(url, requested_properties \\ [])

@spec source(String.t(), [String.t()]) :: {:ok, map()} | {:error, atom()}

Return the MF2 JSON representation of a post for a Micropub source query.

Arguments

  • url is the canonical URL of the post to fetch.

  • requested_properties is an optional list of property names to include.

Returns

  • {:ok, mf2} on success where mf2 is a map ready to be encoded as JSON.

  • {:error, :not_found} if no post exists at that URL.

update(url, replace \\ %{}, add \\ %{}, delete_properties \\ %{})

@spec update(String.t(), map(), map(), list() | map()) ::
  {:ok, String.t()} | {:error, atom()}

Update an existing post, identified by its canonical URL.

Arguments

  • url is the canonical URL of the post to edit.

  • replace is a map of property -> replacement values.

  • add is a map of property -> values to append to the existing list.

  • delete_properties is either a list of property names to clear entirely, or a map of property -> values to remove from the existing list.

Returns

  • {:ok, url} on success.

  • {:error, :not_found} if no post exists at that URL.

url_for(slug)

@spec url_for(String.t()) :: String.t()

Build the canonical URL for a post slug using the configured base URL.

Arguments

  • slug is the post slug.

Returns

  • The absolute URL string.