-
Notifications
You must be signed in to change notification settings - Fork 923
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 nested context paths. #5846
base: main
Are you sure you want to change the base?
Conversation
I would like to receive feedback on whether this PR is heading in the right direction, as it is currently a draft. After fix direction, I will write unit tests and Java docs based on the BaseContextPathsTest code. When you have time, please take a look 🙇♂️ |
I didn't see that a fluent style is good for nested context paths in terms of API design. Users may find it difficult to know the current depth and parent trees and children trees. How about taking a lambda expression as a second parameter to leverage Kotlin trailing lamdas? I imagined the following style API. We used Server
.builder()
.contextPath("/rest") {
contextPath("/catalog") {
service("/product", new GetProductService())
service("/products", new ProductsHandler())
}
}
.contextPath("/cart") {
contextPath("/foo") {
contextPath("/bar") {
service("/checkout", new CheckoutService())
}
}
}
.contextPath("/gql") {
service("/catalog", new GraphQLService())
} Related work: https://ktor.io/docs/server-routing.html#nested_routes |
@ikhoon nim, Thanks for your guidelines. |
@ikhoon nim, i change code style from fluent style to nested lambda expression. // Without virtual host
sb.baseContextPath("/api")
.contextPath("/context-path/a1", "/context-path/a2")
.nestedContext()
.contextPaths(Set.of("/b1", "/b2"), ctx1 -> ctx1 // ctx1 scope start (lambda function)
.annotatedService(new Object() { ... })
.service("/my-service", new HttpService() { ... })
.contextPaths(Set.of("/c1", "/c2"), ctx2 -> ctx2 // ctx2 scope start (lambda function)
.service("/my-service1", new HttpService() { ... })
.contextPaths(Set.of(...), ctx3 -> ctx3 // ctx3 scope start (lambda function)
.service("/...", new HttpService() { ... })
) // ctx3 scope end.
) // ctx2 scope end.
) // ctx1 scope end.
.contextPaths(Set.of("/b3", "/b4"), ctx11 -> ctx11
.service("/my-service", new HttpService() { ... });
// With virtual host.
sb.virtualHost("foo.com")
.contextPath("/virtual-foo")
.nestedContext()
.contextPaths(Set.of("/a1", "/a2"), ctx -> ctx
.service("/my-service1", new HttpService() { ... })); To get detail code, you can refer to this java code.
It may not be exactly the same as the API you imagined, but since we can represent the scope within a lambda function, I believe it will be more user-friendly than my initial commit. also, java cannot perfectly match to When you have time, please take another look. 🙇♂️ |
Motivation:
armeria
supports only1-depth
context paths. Sometimes, user want deeper context paths than 1-depth when they usecontextPaths()
.Modifications:
ContextPathServiceBuilder
tree to support nested context paths.before()
is for going back previous node.contextPath()
is for adding context paths and making childContextPathServiceBuilder
parent()
: To give ChildcontextPathServiceBuilder
parent object. because of this, child can return parent object whenand()
is called.virtualHostbuilder()
: to relay their context viaContextPathServiceBuilder
tree.mergeContextPaths()
: to merge previous context paths and current context paths.Example
Result:
/rest/catalog/product
=>getProductService
/rest/catalog/products
=>productsHandler
/rest/cart/foo/bar/checkout
=>checkoutService
/gql/catalog
=>GraphQLService