Janiczek / elm-url-codec / Url.SimpleParser

A simpler alternative to Url.Parser module from the elm/url package.

Note that if you want to build both URL parsers and builders at the same time, you should use the Url.Codec module instead. The API is very similar!

URL parsing


type Parser a

Parser knows how to parse an URL string into Elm data.

Create it with the combinators:

Use it to parse URLs with the functions parsePath and parseUrl.

Leading and trailing slashes don't matter.


type ParseError
    = SegmentMismatch ({ expected : String, available : String })
    | SegmentNotAvailable
    | WasNotInt String
    | DidNotConsumeEverything (List String)
    | NeededSingleQueryParameterValueGotMultiple ({ key : String, got : List String })
    | NotAllQueryParameterValuesWereInts ({ key : String, got : List String })
    | NoParsers

All the ways the parsing can fail.

parsePath : List (Parser a) -> String -> Result ParseError a

Parse the URL path string, trying out multiple parsers if necessary.

Will stop at the first success.

Will prefer to report error from the parser that had most success parsing.

allParsers =
    [ helloParser, homeParser ]

Url.SimpleParser.parse allParsers "hello/123"
--> Ok (HelloPage 123)

Url.SimpleParser.parse allParsers "/hello/123?comments=1"
--> Ok (HelloPage 123)

Url.SimpleParser.parse allParsers "hello/123whoops"
--> Err (WasNotInt "123whoops")

Url.SimpleParser.parse allParsers ""
--> Ok HomePage

Url.SimpleParser.parse [] ""
--> Err NoParsers

parseUrl : List (Parser parseResult) -> Url -> Result ParseError parseResult

A variant of parsePath that accepts an Url.

Combinators

succeed : a -> Parser a

A way to start your Parser definition.

unfinishedParser : Parser (String -> Route)
unfinishedParser =
    -- needs a string provided via a combinator like `Url.SimpleParser.string`
    Url.SimpleParser.succeed UserRoute

Can also work standalone for URLs without path segments:

parser : Parser Route
parser =
    Url.SimpleParser.succeed HomeRoute

Url.SimpleParser.parsePath [parser] ""
--> Ok HomeRoute

s : String -> Parser a -> Parser a

A hardcoded path segment.

parser : Parser Route
parser =
    Url.SimpleParser.succeed HomeRoute
        |> Url.SimpleParser.s "home"

Url.SimpleParser.parsePath [parser] "home"
--> Ok HomeRoute

int : Parser (Basics.Int -> a) -> Parser a

An integer path segment.

type Route
    = UserRoute Int
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed UserRoute
        |> Url.SimpleParser.s "user"
        |> Url.SimpleParser.int

Url.SimpleParser.parsePath [parser] "user/123"
--> Ok (UserRoute 123)

Url.SimpleParser.parsePath [parser] "user"
--> Err SegmentNotAvailable

string : Parser (String -> a) -> Parser a

A string path segment.

type Route
    = PostRoute String
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed PostRoute
        |> Url.SimpleParser.s "post"
        |> Url.SimpleParser.string

Url.SimpleParser.parsePath [parser] "post/hello"
--> Ok (PostRoute "hello")

Url.SimpleParser.parsePath [parser] "post"
--> Err SegmentNotAvailable

Query parameters

queryInt : String -> Parser (Maybe Basics.Int -> a) -> Parser a

An integer query parameter.

type Route
    = UserRoute (Maybe Int)
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed UserRoute
        |> Url.SimpleParser.s "user"
        |> Url.SimpleParser.queryInt "id"

Url.SimpleParser.parsePath [parser] "user?id=123"
--> Ok (UserRoute (Just 123))

Url.SimpleParser.parsePath [parser] "user"
--> Ok (UserRoute Nothing)

Will fail if there are multiple query parameters with the same key:

Url.SimpleParser.parsePath [parser] "user?id=1&id=2"
--> Err (NeededSingleQueryParameterValueGotMultiple { got = ["1","2"], key = "id" })

Will succeed with Nothing if the query parameter contains a non-integer string:

Url.SimpleParser.parsePath [parser] "user?id=martin"
--> Ok (UserRoute Nothing)

queryString : String -> Parser (Maybe String -> a) -> Parser a

A string query parameter.

type Route
    = UserRoute (Maybe String)
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed UserRoute
        |> Url.SimpleParser.s "user"
        |> Url.SimpleParser.queryString "name"

Url.SimpleParser.parsePath [parser] "user?name=martin"
--> Ok (UserRoute (Just "martin"))

Will fail if there are multiple query parameters with the same key:

Url.SimpleParser.parsePath [parser] "user?name=a&name=b"
--> Err (NeededSingleQueryParameterValueGotMultiple { got = ["a","b"], key = "name" })

queryInts : String -> Parser (List Basics.Int -> a) -> Parser a

A repeated integer query parameter.

type Route
    = UserListingRoute (List Int)
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed UserListingRoute
        |> Url.SimpleParser.s "users"
        |> Url.SimpleParser.queryInts "id"

Url.SimpleParser.parsePath [parser] "users?id=1"
--> Ok (UserListingRoute [1])

Url.SimpleParser.parsePath [parser] "users?id=1&id=2&id=3"
--> Ok (UserListingRoute [1,2,3])

Url.SimpleParser.parsePath [parser] "users"
--> Ok (UserListingRoute [])

Will fail if given a query parameter with an empty value:

Url.SimpleParser.parsePath [parser] "users?id="
--> Err (NotAllQueryParameterValuesWereInts { got = [ "" ] , key = "id" })

Will fail if any of the query parameters has a non-integer value:

Url.SimpleParser.parsePath [parser] "users?id=1&id=hello"
--> Err (NotAllQueryParameterValuesWereInts { got = [ "1", "hello" ] , key = "id" })

queryStrings : String -> Parser (List String -> a) -> Parser a

A repeated string query parameter.

type Route
    = UserListingRoute (List String)
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed UserListingRoute
        |> Url.SimpleParser.s "users"
        |> Url.SimpleParser.queryInts "tags"

Url.SimpleParser.parsePath [parser] "users?tags=Foo"
--> Ok (UserListingRoute ["Foo"])

Url.SimpleParser.parsePath [parser] "users?tags=Foo&tags=Bar&tags=999"
--> Ok (UserListingRoute ["Foo", "Bar", "999"])

Url.SimpleParser.parsePath [parser] "users"
--> Ok (UserListingRoute [])

Will succeed with an empty string if given a query parameter with an empty value:

Url.SimpleParser.parsePath [parser] "users?tags="
--> Ok (UserListingRoute [""])

queryFlag : String -> Parser (Basics.Bool -> a) -> Parser a

A query flag (parameter without = and a value), like eg. /settings?admin.

type Route
    = SettingsRoute { admin : Bool }
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed (\admin -> SettingsRoute { admin = admin })
        |> Url.SimpleParser.s "settings"
        |> Url.SimpleParser.queryFlag "admin"

Url.SimpleParser.parsePath [parser] "settings?admin"
--> Ok (SettingsRoute { admin = True })

Url.SimpleParser.parsePath [parser] "settings"
--> Ok (SettingsRoute { admin = False })

allQueryFlags : Parser (List String -> a) -> Parser a

All query flags, like eg. /settings?admin&no-exports.

type Route
    = SettingsRoute (List String)
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed SettingsRoute
        |> Url.SimpleParser.s "settings"
        |> Url.SimpleParser.allQueryFlags

Url.SimpleParser.parsePath [parser] "settings?admin"
--> Ok (SettingsRoute ["admin"])

Url.SimpleParser.parsePath [parser] "settings"
--> Ok (SettingsRoute [])

Url.SimpleParser.parsePath [parser] "settings?admin&no-exports"
--> Ok (SettingsRoute ["admin", "no-exports"])

Fragment

fragment : Parser (Maybe String -> a) -> Parser a

Fragment part of the URL, eg. /settings#HelloThereWorld.

type Route
    = SettingsRoute (Maybe String)
    | ...

parser : Parser Route
parser =
    Url.SimpleParser.succeed SettingsRoute
        |> Url.SimpleParser.s "settings"
        |> Url.SimpleParser.fragment

Url.SimpleParser.parsePath [parser] "settings#abc"
--> Ok (SettingsRoute (Just "abc"))

Url.SimpleParser.parsePath [parser] "settings"
--> Ok (SettingsRoute Nothing)

Url.SimpleParser.parsePath [parser] "settings#"
--> Ok (SettingsRoute (Just ""))