Skip to content
This repository has been archived by the owner on Jan 25, 2019. It is now read-only.

TBrookRouter and regex support #52

Closed
silvioprog opened this issue Aug 10, 2013 · 17 comments
Closed

TBrookRouter and regex support #52

silvioprog opened this issue Aug 10, 2013 · 17 comments

Comments

@silvioprog
Copy link
Owner

Hello,

We planning to implement regex support in Brook router too. Please see here.

See other feature that will be implemented here.

@silvioprog
Copy link
Owner Author

@uaply, regex support seems a good idea? :)

@uaply
Copy link
Collaborator

uaply commented Aug 15, 2013

Yeah, regexps are frequently used for routing, for example in Django under Python. They are powerful, and sometimes too much powerful :)

The only problem is how to implement it. We should find good RegExp library under Pascal. The one which present in FPC seems doesn't support named groups. Without named groups it will be very hard to use, harder than with current syntax.

@leledumbo
Copy link
Collaborator

http://www.regular-expressions.info/download/TPerlRegEx.zip is a wrapper over PCRE and is licensed under MPL. Maybe only requires some cleanup to make it platform independent. I prefer a pure Pascal solution so I guess it's the time somebody needs to extend Sorokin's TRegExpr to support named group. The code is quite neat so I guess it won't be too difficult to support.

@silvioprog
Copy link
Owner Author

We can use Sorokin's solution (it was moved to FPC after this looong thread: http://lists.lazarus.freepascal.org/pipermail/lazarus/2011-December/069381.html), and with an advantage: it's a code that comes with the Free Pascal.

I think something like:

  protected
    function DoMatchDirectly: Boolean; virtual;
    function DoMatchRegEx: Boolean; virtual;

With DoMatchDirectly using the current implementation and DoMatchRegEx using new implementation with regex. So if someone wants to use a different solution of Sorokin, overrides DoMatchRegEx.

What do you think?

I'll test all uaply changes and merge it to the master branch, so we'll be ready for this new implementation.

@uaply
Copy link
Collaborator

uaply commented Aug 18, 2013

How would be router path look like with this regexpr library? Also we need to pass variables to action. Now they are passed as JSON dictionary and accessed by string names.
Library regexpr.pas has only subexpr indexed by integers. Another library regex.pp not allow getting sub-groups at all.

@silvioprog
Copy link
Owner Author

You can see how to Slim implement it:

http://www.slimframework.com

Brook router is based on Slim framework.

@uaply
Copy link
Collaborator

uaply commented Aug 18, 2013

PHP has full-fledged support of regexp, so routes in Slim implementation internally are converted in such way:
/user/:name/post/:id → /user/(?P<name>[^/]+)/post/(?P<id>.+)

But we don't have named group functionality now in pascal, the best we can do is
/user/([^/]+)/post/(.+)
And loose variable names, because groups addressed by index only. Values[1] and Values[2] instead of Values['name'] and Values['id'] is not very pleasing.

@silvioprog
Copy link
Owner Author

Hm... We can test if the chars "(" and ")" (the sintax will be: /path/(<regex>)) are present, so:

/user/:name/post/:id([0-9])

Two variables will created (name, user) and the second variable will tested with a regex, so:

/user/foo/post/1 OK!

/user/foo/post/a Error!

Seems a good idea? :/

@silvioprog
Copy link
Owner Author

...Or, we can send a patch to improve regex lib of Free Pascal.

@uaply
Copy link
Collaborator

uaply commented Aug 18, 2013

I was also thinking about how we can pre-process initial route path to memorize names of variables. But things are complicated by the fact groups could be nested: '(?(?[^/]+?).?(?[^/]*))'. The better solution is to modify regexp lib, but not to do patches over top of it.

As you see RegExp are much more cryptic :) It is obvious drawback, so we should leave old syntax too.

@silvioprog
Copy link
Owner Author

I was also thinking about how we can pre-process initial route path to memorize names of variables. But things are > complicated by the fact groups could be nested: '(?(?[^/]+?).?(?[^/]*))'. The better > solution is to modify regexp lib, but not to do patches over top of it.

Hm.. we can implement a basic regex support.

I thought of another possibility, something like:

TAction.Register('/user/:name/:id', ['^[a-z]$', '^[0-9]$'], ['Invalid name: %s.', 'Invalid ID: %d.']);

Usage:

http://host/script/user/1/1 - 404 - Msg: Invalid name: 1.

http://host/script/user/a/a - 404 - Msg: Invalid ID: a.

http://host/script/user/1/a - 404 - Msg: Invalid name: 1.

http://host/script/user/a/1 - OK

So regex will be used to validate paths in URL.

Other demo:

TAction.Register('/home/*path/download', ['^[a-z]$']); - It validates *path variable.

TAction.Register('/download/*path/:fileid', ['', '^[0-9]$']); - It validates :fileid variable.

What do you think?

As you see RegExp are much more cryptic :) It is obvious drawback, so we should leave old syntax too.

Hehehe... we keep the old code, and the new feature using current implementation of RegExpr available on Free Pascal. :)

@silvioprog
Copy link
Owner Author

Oops, I forgot ...

I'm planning show a new idea about middleware class support. I'll create a new issue talking about ...

Imagine it:

TUserAction.Register('/user/:id', TMyMiddlewareClass);

...

procedure TMyMiddlewareClass.Execute;
var
  Vid: Integer;
begin
  Vid := Action.Fields['id'].AsInteger;
  if not VId in [0..9] then
    Error('Invalid ID: %d', [VId]);
end;

And reuse TMyMiddlewareClass in other class:

TDownloadAction.Register('/download/:id', TMyMiddlewareClass);

@silvioprog
Copy link
Owner Author

... Or:

initialization
  TDownloadAction.Register('/download/:id');
  TDownloadAction.RegisterMiddleware(TMyMiddlewareClass);

@silvioprog
Copy link
Owner Author

I'm planning show a new idea about middleware class support. I'll create a new issue talking about ...

Done. (#54)

@uaply
Copy link
Collaborator

uaply commented Aug 20, 2013

TAction.Register('/user/:name/:id', ['^[a-z]$', '^[0-9]$'], ['Invalid name: %s.', 'Invalid ID: %d.']);

Good idea – and it has very clear meaning. We validate values with regexp before matching. Error messages probably will not be needed (maybe only for debug).

@silvioprog
Copy link
Owner Author

Hello @uaply, you want to implement this feature?

@silvioprog
Copy link
Owner Author

Done, you can use middleware + constraints to do it! :)

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

3 participants