route_tree 1.0.0-nullsafety.1 route_tree: ^1.0.0-nullsafety.1 copied to clipboard
RouteTree is a generic routing library that makes it easy to implement routing logic based on the path segments of a URI.
RouteTree #
A generic library for parsing URI paths.
RouteTree is a generic routing library that makes it easy to implement routing logic based on the path segments of a URI. This is done by nesting Segment nodes to build a tree not unlike the Widget trees you see in Flutter apps.
Quick example #
final router = Segment.root<String>(
create: (context) => "home",
createError: (context) => "Error!",
children: [
Segment.path(
name: "first_path",
create: (context) => "routed to first_path",
),
Segment.path(
name: "second_path",
create: (context) => "routed to second_path",
children: [
Segment.param(
parser: const UintParser("id"),
create: (context) => "routed to /second_path/${context["id"]}",
),
],
),
],
);
assert(router.route(Uri.parse("/second_path/12")) == "routed to second_path/12");
Note the template parameter that denotes what data type RootSegment.route will return. This makes route_tree so flexible.
How it works #
The basic building blocks of this library are Segments, SegmentParsers and the ParseContext.
Segments #
Segments are to route_tree
what Widgets are to Flutter. Each Segment represents a possible path segment that can be part of a route. Since it's templated it can be used in several ways, like routing in a Flutter app or choosing the correct function to handle incoming HTTP requests in a backend. The abstract class Segment contains several factory constructors to make finding the right one easier.
RootSegment or Segment.root
The root node of any route_tree.
Defines the "/"-route, the root error-handler as well as a list of SegmentVerifiers that can be used to assert certain properties of the route_tree.
By default RootSegments contain findConflictingParamKeys, which returns an error if your route_tree contains duplicate parameter keys like /users/{id}/edit/{id}
.
/// Matches "/"
final router = Segment.root<String>(
create: (context) => "home",
createError: (context) => "root error",
children: [
...
],
);
PathSegment or Segment.path
The Segment you're probably gonna use most often. It defines a simple literal path segment. Internally children of a Segment with a LiteralParser (which by default only applies to PathSegments) are contained in a Map<String, PathSegment> for constant time lookup of corresponding path segments.
Segment.root<String>(
...
children: [
/// Matches "/about"
Segment.path(
name: "about",
create: (context) => "about",
),
/// Matches "/settings/*", but not "/settings" itself, since [create] was
/// left null
Segment.path(
name: "settings",
children: [
/// Matches "/settings/privacy"
Segment.path(
name: "privacy",
create: (context) => "privacy",
),
],
),
],
);
RegExpPathSegment or Segment.regExpPath
Used to define one or (usually) more paths that should be matched by one Segment using a regular expression.
Segment.root<String>(
...
children: [
/// Matches any path segment consisting of letters
Segment.regExpPath(
regExp: RegExp(r"[a-zA-Z]+"),
create: (context) => "letter path",
),
],
);
ParamSegment or Segment.param
Used to define a path parameter. If the segment of a URI is matched, the matched value is added to the ParseContext, from which it can be queried using ParseContext.operator[]
Segment.root<String>(
create: (context) => "home",
createError: (context) => "error!",
children: [
/// Matches "/users/*", since [create] was left null
Segment.path(
name: "users",
children: [
/// Matches "/users/{id}", where {id} is any non-negative integer as defined
/// by [UintParser].
Segment.param(
parser: const UintParser("id"),
create: (context) => context["id"] as String,
),
],
),
],
);
RegExpParamSegment or Segment.regExpParam
Consider URLs used by Twitter where a URL like https://twitter.com/{name}
, where name
can be any word and a hypothetical Twitter client obviously couldn't hardcode all possible names. This is where this Segment comes into play. It can be used to define a path parameter that matches the provided regular expression and injects it into the ParseContext, from which it can be queried using ParseContext.operator[].
final router = Segment.root<String>(
create: (context) => "home",
createError: (context) => "error!",
children: [
/// Matches any path segment consisting of letters
Segment.regExpParam(
parser: RegExpParamParser.forward(
key: "name",
regExp: RegExp(r"\w+"),
),
create: (context) => context["name"] as String,
),
],
);
assert(router.route(Uri.parse("/flutterdev")) == "flutterdev");
SegmentParsers #
The actual parsing logic for looking up correct segments is delegated to instances of SegmentParser. The predefined parsers are:
- SegmentParser.withFunction, which takes a Parser function and can be used to quickly define custom SegmentParses
- LiteralParser, which is primarily used by PathSegment (& Segment.path) and matches a path segment literally
- RegExpParser, which matches a path segment against a regular expression
- ParamParser, subclass of SegmentParser and base class of parsers that inject matches into the ParseContext
- ParamParser.withFunction, which can be used to quickly define custom ParamParsers
- RegExpPararamParser, similar to RegExpParser, but also injects a successful match into the ParseContext
- IntParser & UintParser, which match integers and non-negative integers respectively. The latter is useful for for
id
path parameters.
ParseContext #
The ParseContext holds the initial URI as well as any path parameters in the current route. It is passed to the create
-function when they're called after a path has been matched.