Skip to content

[APIView] Extract shared ICopilotHttpService for apiview-copilot calls#15619

Open
helen229 wants to merge 2 commits into
mainfrom
refactor/copilot-http-service
Open

[APIView] Extract shared ICopilotHttpService for apiview-copilot calls#15619
helen229 wants to merge 2 commits into
mainfrom
refactor/copilot-http-service

Conversation

@helen229
Copy link
Copy Markdown
Member

Summary

Extracts a single ICopilotHttpService that owns endpoint resolution, bearer-token injection, HttpClient lifecycle, and JSON (de)serialization for talking to the apiview-copilot service. Removes the duplicated plumbing from 8 call sites across 5 files.

Motivated by review feedback on #15347 — the new AgentController would have been the 6th place duplicating this same dance.

Changes

New

  • src/dotnet/APIView/APIViewWeb/Services/Interfaces/ICopilotHttpService.cs — interface with GetAsync<T>, PostAsync<T>, PostAsync, and a raw SendAsync escape-hatch.
  • src/dotnet/APIView/APIViewWeb/Services/CopilotHttpService.cs — implementation. Reads CopilotServiceEndpoint, attaches bearer from ICopilotAuthenticationService, uses IHttpClientFactory.CreateClient().

DI

  • Startup.cs — registers ICopilotHttpService as a singleton next to ICopilotAuthenticationService.

Migrated call sites (8 across 5 files)

File Sites Endpoint
Managers/ReviewManager.cs 3 POST api-review/start ×2, GET api-review/{jobId}
Managers/CommentsManager.cs 2 POST api-review/mention ×2
HostedServices/CopilotJobProcessor.cs 1 GET api-review/{jobId} (poll loop)
LeanControllers/APIRevisionsController.cs 1 GET api-review/{jobId} (drop-detection)
Managers/ReviewSearch.cs 1 POST api-review/resolve-package

For each class, dropped the ctor params that are now only used through the new service: IConfiguration, IHttpClientFactory, ICopilotAuthenticationService. Verified by grep that those deps weren't used for anything else in those classes (CommentsManager keeps System.Net.Http.Headers — it's used by an unrelated GitHub call).

Tests

9 test files updated. To minimize churn, each ctor call now constructs a real CopilotHttpService from the existing Configuration / HttpClientFactory / CopilotAuth mocks, so the existing HttpMessageHandler.Protected().Setup(SendAsync, ...) plumbing keeps working unchanged. No test logic was modified.

Verification

  • dotnet build APIViewWeb.csproj — clean.
  • dotnet test APIViewUnitTests.csproj — 790 passed.

Out of scope (intentional follow-ups)

  • AgentController.ReportIssueAsync (added by [APIView] Add "Report an Issue" dialog component #15347) will adopt this service in a follow-up commit on that branch — AgentController doesn't exist on main yet, so it's not migrated here.
  • CommentsManager.LoadTaggableUsers still does new HttpClient() for the GitHub public-members API. That's a different concern (not copilot) and would benefit from its own factory-based refactor.
  • CopilotJobProcessor still has a hand-rolled Poller; could be Polly. Not in scope.

helen229 added 2 commits May 13, 2026 14:53
…calls

Centralizes endpoint resolution, bearer-token injection, HttpClient
lifecycle, and JSON (de)serialization into a single service.

Migrates 8 call sites across 5 files:
- ReviewManager (StartCopilotReviewJobAsync x2, GetCopilotReviewJobAsync)
- CommentsManager (agent mention x2)
- CopilotJobProcessor (polling)
- APIRevisionsController (drop-detection poll)
- ReviewSearch (resolve-package)

Drops IConfiguration / IHttpClientFactory / ICopilotAuthenticationService
from constructors of these classes (only used for the duplicated copilot
plumbing). Updates unit tests to construct CopilotHttpService from existing
mocks so HttpMessageHandler-level test plumbing keeps working unchanged.

A follow-up will migrate the AgentController.ReportIssueAsync call site
once #15347 (the PR introducing AgentController) merges.
Copilot AI review requested due to automatic review settings May 13, 2026 23:07
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Extracts a shared ICopilotHttpService that centralizes endpoint resolution, bearer-token injection, HttpClient lifecycle, and JSON (de)serialization for apiview-copilot calls, removing duplicated plumbing from 8 call sites across 5 files.

Changes:

  • Adds ICopilotHttpService / CopilotHttpService (with GetAsync<T>, PostAsync[<T>], and a raw SendAsync escape-hatch) and registers it as a singleton in Startup.
  • Migrates ReviewManager, CommentsManager, CopilotJobProcessor, APIRevisionsController, and ReviewSearch to the new service, dropping the now-unused IConfiguration/IHttpClientFactory/ICopilotAuthenticationService ctor params.
  • Updates 9 unit-test files to construct a real CopilotHttpService from the existing mocks, preserving the existing HttpMessageHandler setup with no test-logic changes.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Services/Interfaces/ICopilotHttpService.cs New interface for centralized copilot HTTP calls
Services/CopilotHttpService.cs Implementation owning endpoint + auth + JSON plumbing
Startup.cs DI registration of ICopilotHttpService as singleton
Managers/ReviewManager.cs Replaces 3 hand-rolled copilot HTTP calls with the new service
Managers/CommentsManager.cs Replaces 2 mention-endpoint calls; drops unused deps
HostedServices/CopilotJobProcessor.cs Polling loop now uses GetAsync<T>
LeanControllers/APIRevisionsController.cs Drop-detection poll uses GetAsync<T>
Managers/ReviewSearch.cs resolve-package POST routed through SendAsync
APIViewUnitTests/*.cs (9 files) Test ctors updated to wrap mocks in a real CopilotHttpService

_mockCopilotAuthService.Object,
_mockHttpClientFactory.Object,
_mockConfiguration.Object,
new CopilotHttpService(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why are not you doing a mock of ICopilotHttpService instead of creating a new CopilotHttpService(?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

  • Minimal-diff refactor. These tests already had full HTTP-layer wiring (HttpMessageHandler mock + HttpClient + IHttpClientFactory + ICopilotAuthenticationService). Wrapping that existing setup in new CopilotHttpService(...) was a one-line change per ctor site. Switching to Mock would have required rewriting every arrange block

  • Exercises the real seam. The real instance runs actual JSON serialization, URL composition (BuildUrl), and bearer-token header injection. The mock at HttpMessageHandler is the most realistic interception point — closer to the wire — so regressions in CopilotHttpService itself get caught by these tests.

  • No behavior change risk. Using the real type guarantees the test outcomes are identical to pre-refactor behavior.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

but you are not exercising the http-layer on any of that test, on top of that we are removing the idea of those tests being unit isolated tests, if you break something meaningful on that layer, is every test going to break?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants