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

Azure HTTP functions do not work if you define a contextPath #30

Open
mbjarland opened this issue Jul 20, 2020 · 0 comments · May be fixed by #493
Open

Azure HTTP functions do not work if you define a contextPath #30

mbjarland opened this issue Jul 20, 2020 · 0 comments · May be fixed by #493

Comments

@mbjarland
Copy link

mbjarland commented Jul 20, 2020

Sample Repository

https://bitbucket.org/mbjarland/azure-function-context-path-issue/src/master/

Steps to Reproduce

When it works:
─➤ mn 
> create-app azure-function-context-path-issue --lang groovy --build gradle --java-version 8 --test spock --features azure-function --features 
> exit
─➤ cd azure-function-context-path-issue
<edit build.gradle and add dependency implementation("io.micronaut.servlet:micronaut-servlet-core")>
<otherwise the build is broken as described by #28> 
─➤ ./gradlew azureFunctionsRun 
... 
Http Functions:

        ExampleTrigger: [GET,POST] http://localhost:7071/api/{*route}
Hosting environment: Production
Content root path: /home/mbjarland/projects/azure-function-context-path-issue/build/azure-functions/azure-function-context-path-issue
Now listening on: http://0.0.0.0:7071
Application started. Press Ctrl+C to shut down.

in a separate terminal:

─➤ curl http://localhost:7071/api/hello
Example Response%
─➤
When it breaks:

Edit src/main/resources/application.yml and add:

micronaut:
  server:
    context-path: /foo

and run again:

─➤ ./gradlew azureFunctionsRun 
... 
Http Functions:

        ExampleTrigger: [GET,POST] http://localhost:7071/api/{*route}
Hosting environment: Production
Content root path: /home/mbjarland/projects/azure-function-context-path-issue/build/azure-functions/azure-function-context-path-issue
Now listening on: http://0.0.0.0:7071
Application started. Press Ctrl+C to shut down.

in a separate terminal:

─➤ curl -v http://localhost:7071/foo/hello
*   Trying 127.0.0.1:7071...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 7071 (#0)
> GET /foo/hello HTTP/1.1
> Host: localhost:7071
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 404 Not Found
< Date: Mon, 20 Jul 2020 14:45:23 GMT
< Server: Kestrel
< Content-Length: 0
< 
* Connection #0 to host localhost left intact

i.e. we get a http 404 not found response. The same result with:

http://localhost:7071/foo/hello
http://localhost:7071/api/foo/hello
http://localhost:7071/api/foo/foo/hello
http://localhost:7071/foo/foo/hello

and every other combination of prefixes I have been able to come up with. Further, adding some logging in the generated class Function extends AzureHttpFunction class, we can see that only requests with context path /api are actually hitting the method in the Function class (which I in this report call the "router function"), even after we have defined a different context path.

This this makes it impossible to actually hit the controller function in the generated HelloController since:

  • you will only get routed if you hit /api/...
  • you will only match any existing route if your uri matches /foo (it's actually even worse, you need to match /foo/foo/hello, more on this below)

Further, adding a breakpoint in the class io.micronaut.web.router.DefaultRouter, method find:

    private <T, R> List<UriRouteMatch<T, R>> find(String httpMethodName, CharSequence uri) {
        List<UriRoute> routes = routesByMethod.getOrDefault(httpMethodName, Collections.emptyList());
        if (CollectionUtils.isNotEmpty(routes)) { // <-------- BREAKPOINT HERE
            final String uriStr = uri.toString();

we can see that with the above setup, i.e. with:

  • newly generated azure function project with a Function and a HelloController with @Controller('/hello') and @Get(uri="/")
  • a application.yml change setting the context path to /foo
  • running the function locally using the azure core tools and gradle task azureFunctionsRun

, the routes variable gets one route:

GET /foo/foo/hello -> HelloController#io.micronaut.context.DefaultBeanContext$4@7615e40f (application/json )

so to sum things up:

  • we have to hit /api as otherwise our request doesn't get routed at all
  • this is true even if we have manually changed the context path
  • changing the context path to anything, creates two problems:
    1. we can never hit the url as it no longer starts with /api
    2. the context path is duplicated in the micronaut-internal registered route. I.e. it doesn't say /foo/hello it says /foo/foo/hello

Expected Behaviour

Being able to change the root context path and still have functions work.

Actual Behaviour

Changing the context path breaks azure http functions.

Environment Information

─➤ mn --version                                                                                                  130 ↵
Micronaut Version: 2.0.0
JVM Version: 1.8.0_252

─➤ ./gradlew --version                                                                                                            130 ↵

------------------------------------------------------------
Gradle 6.5
------------------------------------------------------------

Build time:   2020-06-02 20:46:21 UTC
Revision:     a27f41e4ae5e8a41ab9b19f8dd6d86d7b384dad4

Kotlin:       1.3.72
Groovy:       2.5.11
Ant:          Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM:          1.8.0_252 (Amazon.com Inc. 25.252-b09)
OS:           Linux 5.4.0-39-generic amd64

A Note on Documentation

at:

https://micronaut-projects.github.io/micronaut-azure/1.0.x/guide/

we state the following:

With this in place you can write regular Micronaut controllers as documented in the user guide for the HTTP server and incoming function requests will be routed to the controllers and executed.

nowhere do we mention the /api prefix, the fact that it doesn't seem like it can be changed, etc. It would be helpful to have a few examples of how to curl things and actually hit the controller so as not to make users have to experiment to figure out where the controller route actually lives.

Happy to make a pr for the docs once this issue has been resolved.

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