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
Support verb suffix for HTTP endpoint #5613
Support verb suffix for HTTP endpoint #5613
Conversation
/cc @hyangtack |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice follow-up work, @sato9818! Left some minor comments 🙇
core/src/main/java/com/linecorp/armeria/server/RouteBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/RoutingTrieBuilder.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/VerbSuffixPathMapping.java
Outdated
Show resolved
Hide resolved
// Q: Should this be allowed? | ||
route = Route.builder().path("/foo/{bar:biz}").build(); | ||
assertThat(route.pathType()).isSameAs(RoutePathType.PARAMETERIZED); | ||
assertThat(route.paths()).containsExactly("/foo/:", "/foo/:"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great question! I think we should not allow it or treat it as {bar}
because we will introduce some option expressions in the future, e.g. {bar:type=int,range=[0,10]}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost there 😄
core/src/main/java/com/linecorp/armeria/server/ParameterizedPathMapping.java
Show resolved
Hide resolved
@@ -418,4 +427,63 @@ Node<V> build() { | |||
return new Node<>(type, path, children, parameterChild, catchAllChild, values); | |||
} | |||
} | |||
|
|||
private static class PathReader { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice abstraction
core/src/main/java/com/linecorp/armeria/server/VerbSuffixPathMapping.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
core/src/main/java/com/linecorp/armeria/server/RoutingTrie.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks very nice. 😃
core/src/main/java/com/linecorp/armeria/server/VerbSuffixPathMapping.java
Outdated
Show resolved
Hide resolved
return node; | ||
} else { | ||
final Node<V> verb = node.children.get(':'); | ||
final String pathVerbPart = path.substring(lastColon); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Micro optimization) What do you think of implementing a method such as findVerb
to find a verb part from path
? findVerb
will scan path
from the last character up to begin
to find :
.
String verbPart = findVerb(path, begin);
if (verbPart == null) {
return node;
} else {
final Node<V> verb = node.children.get(':');
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use the fineVerb
method defined in VerbSuffixPathMapping
because the verb found by the method has to be last segment of a path 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The regular expression may consume more CPU cycles which is inefficient in finding an exact character.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your advice! Implemented the findVerb
function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Left minor suggestions. 👍
core/src/main/java/com/linecorp/armeria/server/VerbSuffixPathMapping.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/VerbSuffixPathMapping.java
Outdated
Show resolved
Hide resolved
core/src/main/java/com/linecorp/armeria/server/RoutingTrieBuilder.java
Outdated
Show resolved
Hide resolved
return withLeadingSlash ? '/' + path : path; | ||
} | ||
|
||
private static String toPathString(List<PathSegment> segments, PathMappingType type) { | ||
final PathSegment lastSegment = segments.get(segments.size() - 1); | ||
if (lastSegment instanceof VerbPathSegment) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: Shouldn't we do some validation here such as checking if the body "*"
when POST is used? 🤔
armeria/grpc/src/main/java/com/linecorp/armeria/server/grpc/HttpJsonTranscodingPathParser.java
Line 67 in 17b64b9
// We don't check 'Verb' part because we don't use it when generating a corresponding path pattern. |
https://cloud.google.com/apis/design/custom_methods#http_mapping
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your suggestion! As you said, I think we need to validate the verb part so I used a regex to make sure the verb part is in valid.
In my opinion, we don't need to validate if the body is "*"
when POST is used because some poeple might want to use a body other than *
according to this stackoverflow. What do you think of this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After rereading the spec, I realize that it uses the term 'shall' at the top.
The following guidelines shall be applied when choosing the HTTP mapping:
...
- If the HTTP verb used for the custom method allows an HTTP request body (this applies to POST, PUT, PATCH, or a custom HTTP verb), the HTTP configuration of that custom method must use the body: "*" clause and all remaining request message fields shall map to the HTTP request body.
Because they use must
in the sentence, I thought we should prohibit the value except "*" but I was wrong. 😓
Let's just remove this line though:
armeria/grpc/src/main/java/com/linecorp/armeria/server/grpc/HttpJsonTranscodingPathParser.java
Line 67 in 17b64b9
// We don't check 'Verb' part because we don't use it when generating a corresponding path pattern. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fantastic. Thanks, @sato9818! 👍 👍 👍
return withLeadingSlash ? '/' + path : path; | ||
} | ||
|
||
private static String toPathString(List<PathSegment> segments, PathMappingType type) { | ||
final PathSegment lastSegment = segments.get(segments.size() - 1); | ||
if (lastSegment instanceof VerbPathSegment) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After rereading the spec, I realize that it uses the term 'shall' at the top.
The following guidelines shall be applied when choosing the HTTP mapping:
...
- If the HTTP verb used for the custom method allows an HTTP request body (this applies to POST, PUT, PATCH, or a custom HTTP verb), the HTTP configuration of that custom method must use the body: "*" clause and all remaining request message fields shall map to the HTTP request body.
Because they use must
in the sentence, I thought we should prohibit the value except "*" but I was wrong. 😓
Let's just remove this line though:
armeria/grpc/src/main/java/com/linecorp/armeria/server/grpc/HttpJsonTranscodingPathParser.java
Line 67 in 17b64b9
// We don't check 'Verb' part because we don't use it when generating a corresponding path pattern. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fantastic. Thanks, @sato9818! 👍 👍 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fantastic. Thanks, @sato9818! 👍 👍 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome work! 🚀💯
@jrhee17 is currently looking for ways to improve this PR, so please bear with us 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's get this merged! Thanks @sato9818 ! 🙇 👍 🙇
Motivation:
We didn't implement supporting "verb" part from #3786, for example,
customVerb
fromhttps://service.name/v1/some/resource/name:customVerb
.:
is a control character of a parameter variable inRoutingTrie
,so there's no way to specify a plain
:
character on a service path.This changeset if a follow-up of #4064, originally written by @hyangtack.
Modifications:
VerbSuffixPathMapping
which checks whether the request path has a verb or not.HttpJsonTranscodingPathParser.Stringifier
to produce a verb with a leading:
character.RoutingTrie
handle a escape character\
.Result:
Co-authored-by: Hyangtack Lee [email protected]