Skip to content

Conversation

@NandanDevHub
Copy link

@NandanDevHub NandanDevHub commented Oct 16, 2025

Fixes #2248

This PR fixes an issue where aggregated routes failed to correctly resolve nested route parameters when the downstream route expected a placeholder (for example, user/{id}) derived from the first service response.

Previously, the aggregator was not correctly substituting the JsonPath parameter value into the downstream request, resulting in empty or incorrect downstream calls during multi-service aggregation.

Root Cause

  • The AggregatesCreator logic did not properly bind the JsonPath extracted value to the downstream route template.
  • The MultiplexingMiddleware was not maintaining consistent parameter mapping when multiple downstream responses were aggregated sequentially.

Proposed Changes

  • Updated AggregatesCreator to correctly propagate extracted route parameters (JsonPathParameter) into the downstream template.
  • Adjusted MultiplexingMiddleware to ensure each downstream request uses the resolved parameter before invocation.

Verified via

  • Verified locally using the provided test setup (comments and user mock services via Ocelot gateway - reproduced locally).
  • Gateway now correctly returns the aggregated response:
{
  "comments": [
    { "id": 1, "userId": 1 },
    { "id": 2, "userId": 2 }
  ],
  "user": [
    { "id": 1, "name": "Artem" },
    { "id": 2, "name": "Ivan" }
  ]
}
  • Also validated through Postman to confirm downstream aggregation works as expected.
  • All aggregate related acceptance tests passed except for a few port-collision test cases, which were environmental (macOS multiple test runners binding the same ports).

@raman-m raman-m added bug Identified as a potential bug Aggregation Ocelot feature: Aggregation, e.g., Request Aggregation, aka BFF labels Oct 17, 2025
@raman-m raman-m changed the title Bug Fix: To ensure correct mapping of RouteKeysConfig arrays in aggregates #2248 Ensure correct mapping of RouteKeysConfig arrays in aggregates Oct 17, 2025
@coveralls
Copy link
Collaborator

coveralls commented Oct 17, 2025

Coverage Status

coverage: 91.737% (-0.02%) from 91.759%
when pulling 4dc2d1f on NandanDevHub:fix/aggregate-routekeys-nandan
into e3ad51c on ThreeMammals:develop.

@raman-m raman-m requested review from ggnaegi and raman-m October 17, 2025 09:17
Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NandanDevHub Hi Nandan!
Thanks for your interest in Ocelot! 🐯
I noticed several fictitious changes stemming from the EOL Gotchas issue. I'll help you resolve them a bit later, as I know the best way to fix them. To be fair, reviewing the actual code is challenging with the fictitious changes, so I'll revisit the PR later as well.

The current CI build 268 is green, which means nothing was broken. However, since no tests were attached and there are only one or two tests related to complex aggregation, we definitely need more thorough tests. A must-have is writing bug #2248 repro acceptance tests to confirm that the fix resolves the original issue. While manual testing in Postman is a useful part of development, it's not enough for final delivery.

FYI, I won't mark this PR as draft because I believe it should be straightforward for you to handle the required testing given our development process. It's very likely this PR will be included in the next release for version 25.0, allowing this bug fix to be rolled out.

P.S. The current CI status is red due to a failed Coveralls check that says, "Please write more unit tests." 😉 Additionally, Coveralls provided this status update.

@raman-m
Copy link
Member

raman-m commented Oct 17, 2025

@ggnaegi Guil, would you mind taking the lead and pair-programming on this PR?
If you're okay with it, please assign yourself as an Assignee.
I'll take on the role of supervisor, so let me focus and complete the current hot release v24.1.

@NandanDevHub
Copy link
Author

Okay @raman-m Thenk you for the detailed feedback!
Got it about the EOL part, I’ll leave that as is for now, and will check locally again regarding EOL, and will soon add on the acceptance test for #2248.
I’ll commit the test shortly so it’s easier to review the actual fix.

@NandanDevHub
Copy link
Author

@raman-m I’ve added the acceptance test for #2248 covering the RouteKeys array case.
It builds fine on my local setup for both net8.0 and net9.0.
Please let me know if anything looks off or if I should adjust the test structure or assertions.

Copy link
Member

@raman-m raman-m left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid using AI tools to generate code❗

I noticed that the code in commit 19668d4 appears to have been generated by AI 😠
Code created this way will not be merged, and it won't help you understand the Ocelot codebase or successfully complete and deliver features or bug fixes. Moreover, the test is failing, dude 🙄

The test is currently failing❗

  • Check the failed build here

@raman-m
Copy link
Member

raman-m commented Oct 18, 2025

Something unusual is happening after I reverted the MultiplexingMiddleware code in commit bb83253. This is the exact copy of upstream develop branch.
This file still includes a few fictious changes 👇

image

If it's alright with you, I'll rebase the branch onto the upstream develop. This should help clean up any fictitious changes from the commit history... So, going to rebase...

@raman-m raman-m force-pushed the fix/aggregate-routekeys-nandan branch from bb83253 to 48363bd Compare October 18, 2025 13:58
@raman-m raman-m force-pushed the fix/aggregate-routekeys-nandan branch from 48363bd to 3395986 Compare October 18, 2025 14:05
@raman-m
Copy link
Member

raman-m commented Oct 18, 2025

@NandanDevHub Now the changes look good. The test has been moved to the AggregateTests class.
I think we can begin the code review now.

@raman-m raman-m requested review from RaynaldM and raman-m October 18, 2025 14:32
@raman-m
Copy link
Member

raman-m commented Oct 18, 2025

Ready for Code Review

@NandanDevHub After you complete the test and demonstrate that it effectively covers the bug's scenario, I will review this PR again.

@NandanDevHub
Copy link
Author

NandanDevHub commented Oct 18, 2025

@raman-m sorry man for the trouble, especially fixing the EOL issues, cleaning up the branch, and rebasing everything. thanks man appreciate the effort you put in to make it right,

and will add the test in same tests for test to cover the bug scenario.

@NandanDevHub
Copy link
Author

@raman-m The new test Should_expand_jsonpath_array_into_multiple_parameterized_calls checks that when a downstream service returns an array for example [{"userId":1},{"userId":2}], so that ocelot expands those values into multiple parameterized calls to /users/{userId} and aggregates the responses as expected.

I ran the test locally twice once all and again with the two 2248 related tests do passes

{
var processing = new List<Task<HttpContext>>();
var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct();
var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct().ToList();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct().ToList();
var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct().ToArray();

Copy link
Member

@raman-m raman-m Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be fair, creating a list or another collection isn't necessary since the foreach operator already processes IEnumerable object 🤣 LoL →

var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct();
foreach (var value in values)

@NandanDevHub Please avoid using ToList() to create the list, as it consumes a small amount of heap and adds unnecessary pressure on the garbage collector!
FYI, Distinct() is essentially a wrapper algorithm applied to a collection generated by multiple Select() operations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My suggestion:

-        var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(s => s.ToString()).Distinct();
+        var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Select(ToString).Distinct();

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@raman-m I've kept the explicit lambda here since SelectTokens() returns JToken items, i felt this way each tokens value is safely converted to string.

Also in below cmmit i confirmed the EOL formatting is fine now.

Copy link
Member

@raman-m raman-m Oct 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, fair enough!
Could the code line be like this?
My suggestion:

var values = jObject.SelectTokens(matchAdvancedAgg.JsonPath).Distinct().Select(s => s.ToString());

The idea is to skip creating the collection and applying the Distinct algorithm afterward. Instead, it's more efficient to search for distinct objects directly and then perform the casting to strings.
I'm not sure about the correctness because Distinct might return all J-tokens.

@NandanDevHub NandanDevHub force-pushed the fix/aggregate-routekeys-nandan branch from 25d8ea8 to 378ce02 Compare October 25, 2025 05:23
@RaynaldM RaynaldM self-requested a review October 28, 2025 09:17
@raman-m
Copy link
Member

raman-m commented Oct 28, 2025

Lack of Unit Testing ❗

@NandanDevHub I can't approve this PR because there are no unit tests. This issue is highlighted by the failed Coveralls build, which shows no unit tests and a decrease in the coverage factor. Please focus on adding unit tests for MultiplexingMiddleware.
Unit tests should be added to MultiplexingMiddlewareTests class.

@raman-m
Copy link
Member

raman-m commented Oct 28, 2025

@RaynaldM approved these changes on Oct 28

Ray, thanks for your approval. I know your suggestions have been applied, but I think we need to wait for Gui's approval since he is the key reviewer and the master of Multiplexer.

@raman-m
Copy link
Member

raman-m commented Oct 28, 2025

@ggnaegi Are you planning to manage this PR and assist the contributor in delivering it for the current release?
I'm unable to do so because I'm busy, as you know what I'm currently working on. I would really appreciate it if you could handle this bug fix alongside the author.

@NandanDevHub NandanDevHub force-pushed the fix/aggregate-routekeys-nandan branch from 2f06dda to 46252ad Compare October 28, 2025 20:56
@NandanDevHub
Copy link
Author

@raman-m I have added a new unit test inside MultiplexingMiddlewareTests that exercises the ProcessRouteWithComplexAggregation path in MultiplexingMiddleware

@raman-m
Copy link
Member

raman-m commented Oct 31, 2025

Sorry, I’m tied up with a hot release and can’t assist right now. Please avoid mentioning me directly, as you already have an assigned mentor. Reach out to Guillaume for further help.

FYI

Thanks for adding the commit 4dc2d1f, but which lines did you actually cover?
The unit testing Coveralls build has failed, showing a 2% decrease in code coverage. You can find the details here → Coveralls Build:
image
So, I'm concluding that the unit test you added doesn't actually cover the new code!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Aggregation Ocelot feature: Aggregation, e.g., Request Aggregation, aka BFF bug Identified as a potential bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aggregates + RouteKeysConfig where the array of values does not work correctly

5 participants