Url.Parser.Query
In the URI spec, Tim Berners-Lee says a URL looks like this:
https://example.com:8042/over/there?name=ferret#nose
\___/ \______________/\_________/ \_________/ \__/
| | | | |
scheme authority path query fragment
This module is for parsing the query part.
In this library, a valid query looks like ?search=hats&page=2 where each
query parameter has the format key=value and is separated from the next
parameter by the & character.
Parse Query Parameters
Parse a query like ?search=hat&page=2 into nice Gren data.
Handle String parameters.
search : Parser (Maybe String)
search =
string "search"
-- ?search=cats == Just "cats"
-- ?search=42 == Just "42"
-- ?branch=left == Nothing
-- ?search=cats&search=dogs == Nothing
Check out custom if you need to handle multiple search
parameters for some reason.
Handle Int parameters. Maybe you want to show paginated search results:
page : Parser (Maybe Int)
page =
int "page"
-- ?page=2 == Just 2
-- ?page=17 == Just 17
-- ?page=two == Nothing
-- ?sort=date == Nothing
-- ?page=2&page=3 == Nothing
Check out custom if you need to handle multiple page parameters
or something like that.
Handle enumerated parameters. Maybe you want a true-or-false parameter:
import Dict
debug : Parser (Maybe Bool)
debug =
enum "debug" (Dict.fromArray [ ("true", True), ("false", False) ])
-- ?debug=true == Just True
-- ?debug=false == Just False
-- ?debug=1 == Nothing
-- ?debug=0 == Nothing
-- ?true=true == Nothing
-- ?debug=true&debug=true == Nothing
You could add 0 and 1 to the dictionary if you want to handle those as
well. You can also use map to say map (Maybe.withDefault False) debug
to get a parser of type Parser Bool that swallows any errors and defaults to
False.
Note: Parameters like ?debug with no = are not supported by this library.
Create a custom query parser. The string, int, and
enum parsers are defined using this function. It can help you handle
anything though!
Say you are unlucky enough to need to handle ?post=2&post=7 to show a couple
posts on screen at once. You could say:
posts : Parser (Array Int)
posts =
custom "post" (Array.filterMap String.toInt)
-- ?post=2 == [2]
-- ?post=2&post=7 == [2, 7]
-- ?post=2&post=x == [2]
-- ?hats=2 == []
Mapping
Transform a parser in some way. Maybe you want your page query parser to
default to 1 if there is any problem?
page : Parser Int
page =
map (Maybe.withDefault 1) (int "page")
Combine two parsers. A query like ?search=hats&page=2 could be parsed
with something like this:
type alias Query =
{ search : Maybe String
, page : Maybe Int
}
query : Parser Query
query =
map2 Query (string "search") (int "page")
Combine three parsers. A query like ?search=hats&page=2&sort=ascending
could be parsed with something like this:
import Dict
type alias Query =
{ search : Maybe String
, page : Maybe Int
, sort : Maybe Order
}
type Order = Ascending | Descending
query : Parser Query
query =
map3 Query (string "search") (int "page") (enum "sort" order)
order : Dict.Dict String Order
order =
Dict.fromArray
[ ( "ascending", Ascending )
, ( "descending", Descending )
]
If you need higher than eight, you can define a function like this:
apply : Parser a -> Parser (a -> b) -> Parser b
apply argParser funcParser =
map2 (<|) funcParser argParser
And then you can chain it to do as many of these as you would like:
map func (string "search")
|> apply (int "page")
|> apply (int "per-page")