NGINX setup for REST API returning default configuration

Solution 1:

I'm assuming you just stubbed out the proxy-related machinations to be handled at a later time in your warehouse API file, but that actually won't work, as you found out.

# Warehouse API
#
location /warehouse/api/ {
    # Policy configuration here (authentication, rate limiting, logging, more...)
    #
    access_log /var/log/nginx/warehouse_api.log main;
    auth_request /_validate_apikey;

    # URI routing
    #
    proxy_pass http://warehouse;

    return 404; # Catch-all
}

Compare that one line in charge of URI routing against the version in the example you linked.

# Warehouse API
#
location /api/warehouse/ {
    # Policy configuration here (authentication, rate limiting, logging, more...)
    #
    access_log /var/log/nginx/warehouse_api.log main;
    auth_request /_validate_apikey;

    # URI routing
    #
    location /api/warehouse/inventory {
        proxy_pass http://warehouse_inventory;
    }

    location /api/warehouse/pricing {
        proxy_pass http://warehouse_pricing;
    }

    return 404; # Catch-all
}

The reason for why the example works but yours doesn't has to do with the "precedence" ("immediacy" might be a better term) of the return directive.

As per the documentation, the return directive immediately causes Nginx to stop processing the current request and return right away1. This means your proxy_pass directive isn't even getting the chance to even try to execute.

However, in the example, there are two nested, prefix-based locations within the block, which means that Nginx will opt for the longest match. This is why the example request succeeded; the requested URI, https://api.example.com/api/warehouse/pricing/item001, matched the second of the two nested location blocks, and thus the request was proxied as expected.

In conclusion, you need to add a nested location block for the proxy_pass directive to execute within, if you want to replicate the example. Otherwise, it looks like you should be able to simply remove the return directive and your configured upstream backend will be free to try to do its thing.