Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Extend *.eskip format with basic abstraction facilities #182

Open
grassator opened this issue Jul 26, 2016 · 8 comments
Open

RFC: Extend *.eskip format with basic abstraction facilities #182

grassator opened this issue Jul 26, 2016 · 8 comments

Comments

@grassator
Copy link
Contributor

grassator commented Jul 26, 2016

The following proposal is to implement several abstraction facilities to *.eskip format. The focus is to have minimal changes to the syntax of the files and introduce bare minimum extra grammar.

Example

commonFilterChain():
    filterOne()
    -> filterTwo()
    -> localeResolver();

AllHosts():
    Host(/my[.]host[.]name|my[.]other[.]host[.]name/)

$commonPathPrefix: "/prefix";
replacePath($path):
    modPath(".*", $path);

foo:
    AllHosts() && Path('/foo/(\w)+')
    -> commonFilterChain()
    -> pathWithPrefix("/bar")
    -> "http://mosaic9.org";

Specification

User-defined constants

A constant MUST be able to represent the following base types:

  • Number
  • String
  • Regular Expression

Each constant identifier MUST be prefixed with $. A constant definition MUST consist of an identifier and it's value separated by : and terminated by ; located at the top level in an eskip file:

$someNum: 42;
$someStr: "foobar";
$someRegex: /foo|bar/; 

Constants are global and MUST have a globally unique name. A conflict in names MUST be reported by the eskip check command.

User-defined filter chains

A user-defined filter chain has the same syntax as the route, but MUST have a parameter list enclosed in round braces following the identifier. Parameter list MUST contain zero or more parameters. Each parameter MUST be a locally-bound constant.

The body of the filter chain MUST consist of one or more filter "calls", separated by ->:

commonFilterChain():
    filterOne()
    -> filterTwo()
    -> localeResolver();

Any violations of on of the following conditions MUST be reported by the eskip check command:

  • User-defined filter chains are global and MUST have a globally unique name.
  • User-defined filter chains MUST be defined before their usage.
  • Self or mutual recursion is not allowed.
  • An identifier for a user-defined filter chain MUST start with a lowercase latin character.

User-defined predicates

User-defined predicates have the same syntax as the route, but MUST have a parameter list enclosed in round braces following the identifier. Parameter list MUST contain zero or more parameters. Each parameter MUST be a locally-bound constant.

The body of the predicate MUST consist of one or more predicate "calls", separated by &&:

PathOnDefaultHost($path):
    Host("mosaic9.org") && Path($path)

Any violations of on of the following conditions MUST be reported by the eskip check command:

  • User-defined predicates are global and MUST have a globally unique name.
  • User-defined predicates MUST be defined before their usage.
  • Self or mutual recursion is not allowed.
  • An identifier for a user-defined predicate MUST start with an uppercase latin character.
@aryszka
Copy link
Contributor

aryszka commented Jul 26, 2016

this is awesome!

i am only not sure about these two:

"An identifier for a user-defined filter chain MUST start with a lowercase latin character."
"An identifier for a user-defined predicate MUST start with an uppercase latin character."

while it's very Goish, not sure that users would expect it. Need to consider this. Any suggestions, opinions, wishes?

@Raffo
Copy link
Contributor

Raffo commented Jul 26, 2016

I agree with @aryszka that this looks like Go and it is something the could be counter intuitive in something that is not directly Go.

@grassator
Copy link
Contributor Author

I'm happy to drop this requirement, but my idea here was that it would help to statically verify the routes. Otherwise it will either be a "dumb" macro or we will have to carry types through expansion, which is a bit complicated. However it also might be that I'm totally missing something :)

@aryszka
Copy link
Contributor

aryszka commented Jul 27, 2016

can they be verified like this?
to do a complete check, the checking code needs to know about the deployed predicates and filters. If it knows, then it can check if in the final routes, there are only predicates in predicate positions and only filters in the filter positions. did you think about something more?

@grassator
Copy link
Contributor Author

@aryszka That is true, however eskip can know about all the built-in filters, which will cover a lot of cases. For people that do need custom filters we could add some sort of "external" spec later which could probably even be auto-generated from filter go code.

For now, eskip could just warn about "unknown" filters and predicates with an option to set it to quiet (or other way around), or maybe you could provide a list of names (and signatures?) of custom filters / predicates as command line arguments.

I always want to catch as many errors as I can before going into production.

@aryszka
Copy link
Contributor

aryszka commented Jul 28, 2016

still considering this. I would like it if it was possible to differentiate between a predicate definition and a filter definition. I just don't have a syntax solution on my mind that I would like as a user. Sofar.

@LappleApple
Copy link
Contributor

@aryszka We could ask for community input here. I proposed on a different issue a "feedback wanted" label.

@evangelion1204
Copy link
Member

@aryszka
I completely read through the definition and regarding #215. I simply have one question regarding constants in general. For me they sound more something like a precompiler, something that is being replaced when parsing the routes.
On the other hand those constants could also be injected into the FilterContext and then be used in a dynamic replacement like the params of #215.

Which could result in something like this:

$host: "www.zalando.de";
$targetPath: "/product-details-page""

route: Host($host) && Path("/products/:productid") => setPath("/product-details-page/sku/${productid}") => https://domain.tld;

using_constant_within_string: Host($host) => setPath("${targetPath}/${productid}") => https://domain.tld;

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

No branches or pull requests

5 participants