lydell/elm-app-url

URLs for applications


Keywords
elm
License
MIT
Install
elm-package install lydell/elm-app-url 1.0.0

Documentation

elm-app-url

AppUrl is an attempt at making URL handling simpler than elm/url!

It’s based around this AppUrl type:

type alias AppUrl =
    { path : List String
    , queryParameters : QueryParameters
    , fragment : Maybe String
    }


type alias QueryParameters =
    Dict String (List String)

Which works really nicely with pattern matching!

import AppUrl exposing (AppUrl)
import Dict


parse : AppUrl -> Maybe Page
parse url =
    case url.path of
        [] ->
            Just Home

        [ "product", productId ] ->
            String.toInt productId |> Maybe.map (Product << ProductId)

        [ "products" ] ->
            Just
                (ListProducts
                    { color = Dict.get "color" url.queryParameters |> Maybe.andThen List.head
                    , size = Dict.get "size" url.queryParameters |> Maybe.andThen List.head
                    }
                )

        _ ->
            Nothing


type Page
    = Home
    | Product ProductId
    | ListProducts Filters


type ProductId
    = ProductId Int


type alias Filters =
    { color : Maybe String
    , size : Maybe String
    }

Creating URL strings is pretty smooth too:

import Maybe.Extra


toAppUrl : Page -> AppUrl
toAppUrl page =
    case page of
        Home ->
            AppUrl.fromPath []

        Product (ProductId productId) ->
            AppUrl.fromPath [ "product", String.fromInt productId ]

        ListProducts { color, size } ->
            { path = [ "products" ]
            , queryParameters =
                Dict.fromList
                    [ ( "color", Maybe.Extra.toList color )
                    , ( "size", Maybe.Extra.toList size )
                    ]
            , fragment = Nothing
            }


toString : Page -> String
toString =
    toAppUrl >> AppUrl.toString

👉 Full examples

Design principles

  • Parse: Avoid the complex types Url.Parser has, and use simple list pattern matching instead. Decode away all percentage escapes so you never need to think about them.
  • Stringify: No separate API like Url.Builder. Escape the minimum needed with percentage escapes.
  • Specification: Follow the WHATWG URL Standard.
  • Keep it simple: URLs shouldn’t be that complicated. List pattern matching, Dict and Maybe is the bread and butter of AppUrl, rather than parsers, tricky type annotations and the </> and <?> operators.

Tip

It’s completely fine to have something like this:

parse : AppUrl -> Maybe Page
parse url =
    case url.path of
        [ "blog" ] -> x
        [ "blog", postId ] -> x
        [ "blog", postId, "edit" ] -> x
        [ "blog", postId, "comment", commentId ] -> x
        [ "blog", postId, "comment", commentId, "edit" ] -> x
        _ -> Nothing

It might feel wrong to repeat the URL segment blog so many times, for example. My advice is: Don’t try to be clever here for the sake of following the “Don’t Repeat Yourself (DRY)” principle! The above is very simple and easy to read, and gives a nice overview of what all your URLs look like. It’s easy to change too, since all the repetitions of blog are in the same place.

Do however avoid duplication in each branch by calling helper functions. But the pattern matching is better left “duplicated”.