Skip to content

[management] Add reverse proxy services REST client#5454

Merged
lixmal merged 1 commit intomainfrom
reverse-proxy-rest-client
Feb 28, 2026
Merged

[management] Add reverse proxy services REST client#5454
lixmal merged 1 commit intomainfrom
reverse-proxy-rest-client

Conversation

@lixmal
Copy link
Copy Markdown
Collaborator

@lixmal lixmal commented Feb 26, 2026

Describe your changes

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • New Features

    • Full Reverse Proxy Services management: list, get, create, update, delete.
    • Reverse Proxy Clusters: list cluster inventory.
    • Reverse Proxy Domains: list, create, delete, validate.
    • REST client now exposes these Reverse Proxy management endpoints.
  • Bug Fixes / Improvements

    • Improved API error handling and added a helper to detect "not found" responses.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

Added APIError and improved error handling in the management REST client; introduced and wired three new reverse-proxy REST API wrappers on Client: ReverseProxyServicesAPI (CRUD), ReverseProxyClustersAPI (List), and ReverseProxyDomainsAPI (List/Create/Delete/Validate).

Changes

Cohort / File(s) Summary
Client integration & errors
shared/management/client/rest/client.go
Added APIError type and IsNotFound helper; changed NewRequest to return APIError for non-2xx responses; added and initialized ReverseProxyServices, ReverseProxyClusters, ReverseProxyDomains fields on Client.
Reverse Proxy Services API
shared/management/client/rest/reverse_proxy_services.go
New ReverseProxyServicesAPI with methods: List(ctx), Get(ctx, id), Create(ctx, req), Update(ctx, id, req), Delete(ctx, id) targeting /api/reverse-proxies/services.
Reverse Proxy Clusters API
shared/management/client/rest/reverse_proxy_clusters.go
New ReverseProxyClustersAPI with List(ctx) calling /api/reverse-proxies/clusters.
Reverse Proxy Domains API
shared/management/client/rest/reverse_proxy_domains.go
New ReverseProxyDomainsAPI with List(ctx), Create(ctx, req), Delete(ctx, id), Validate(ctx, id) calling /api/reverse-proxies/domains endpoints.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Caller
participant Client
participant API as ReverseProxyServicesAPI
participant HTTP as HTTP Client
participant Server
participant Parser as parseResponse
Caller->>Client: call ReverseProxyServicesAPI.List/Get/Create/Update/Delete
Client->>API: delegate call
API->>HTTP: build & send HTTP request (/api/reverse-proxies/...)
HTTP->>Server: request
Server-->>HTTP: response (status, body)
HTTP->>Parser: parseResponse / unmarshal JSON
Parser-->>API: domain model or error
API-->>Client: return result or error
Client-->>Caller: propagate result or APIError

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I nibbled bugs and stitched new routes,

Services, clusters, domains—no doubts,
Client wired, errors neatly bound,
I hop, I cheer, the endpoints sound,
A rabbit’s codebound victory dance.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description follows the template structure and marks the change as a feature enhancement, but critically lacks details: no change description is provided, no issue ticket is referenced, and no explanation for why documentation is not needed. Add a detailed description of the changes, include the related issue ticket number and link, and explain why documentation is not needed despite this being a public API addition.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding a reverse proxy services REST client, which aligns with the primary feature in the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch reverse-proxy-rest-client

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
shared/management/client/rest/reverse_proxy_services.go (1)

17-87: Add focused unit tests for CRUD request construction and error paths.

Please add tests that validate HTTP method/path, payload serialization, and parse/error behavior (nil, err contract for Get/Create/Update on failures). This new client surface is otherwise regression-prone.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shared/management/client/rest/reverse_proxy_services.go` around lines 17 -
87, Add focused unit tests for ReverseProxyServicesAPI methods (List, Get,
Create, Update, Delete) that assert the HTTP method and URL passed to the
underlying client (a.c.NewRequest), validate request body serialization for
Create and Update (matching api.PostApiReverseProxiesServicesJSONRequestBody and
api.PutApiReverseProxiesServicesServiceIdJSONRequestBody), and cover error paths
where NewRequest or parseResponse returns an error to ensure callers receive
(nil, err) for Get/Create/Update and error for Delete; use a fake/mock
implementation of the client (the c field) to capture method, path, headers, and
body, and stub parseResponse or http response bodies to exercise both successful
parsing and failure cases. Ensure tests reference the API methods by name
(ReverseProxyServicesAPI.List/Get/Create/Update/Delete) and verify resp.Body is
closed when non-nil if applicable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shared/management/client/rest/reverse_proxy_services.go`:
- Around line 38-39: The three methods Get, Create, and Update currently return
a non-nil *api.Service together with an error because they unconditionally do
"ret, err := parseResponse[api.Service](resp); return &ret, err"; change each to
check the parse error and return nil on failure: call "ret, err :=
parseResponse[api.Service](resp)" then "if err != nil { return nil, err }" and
finally "return &ret, nil" so callers receive a nil pointer whenever an error is
returned.
- Line 31: The REST client concatenates path parameters directly (e.g., in
reverse_proxy_services.go where a.c.NewRequest is called with
"/api/reverse-proxies/services/"+serviceID); fix by applying url.PathEscape to
all path parameters before building paths (serviceID, userID, tokenID, peerID,
zoneID, etc.) or centralize into a helper like buildPath(segment, id) that calls
url.PathEscape, and update all occurrences across the client methods to use the
escaped values to prevent reserved-character injection.

---

Nitpick comments:
In `@shared/management/client/rest/reverse_proxy_services.go`:
- Around line 17-87: Add focused unit tests for ReverseProxyServicesAPI methods
(List, Get, Create, Update, Delete) that assert the HTTP method and URL passed
to the underlying client (a.c.NewRequest), validate request body serialization
for Create and Update (matching api.PostApiReverseProxiesServicesJSONRequestBody
and api.PutApiReverseProxiesServicesServiceIdJSONRequestBody), and cover error
paths where NewRequest or parseResponse returns an error to ensure callers
receive (nil, err) for Get/Create/Update and error for Delete; use a fake/mock
implementation of the client (the c field) to capture method, path, headers, and
body, and stub parseResponse or http response bodies to exercise both successful
parsing and failure cases. Ensure tests reference the API methods by name
(ReverseProxyServicesAPI.List/Get/Create/Update/Delete) and verify resp.Body is
closed when non-nil if applicable.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a6a72e and 5523148.

📒 Files selected for processing (2)
  • shared/management/client/rest/client.go
  • shared/management/client/rest/reverse_proxy_services.go

Comment thread shared/management/client/rest/reverse_proxy_services.go Outdated
Comment thread shared/management/client/rest/reverse_proxy_services.go Outdated
@lixmal lixmal force-pushed the reverse-proxy-rest-client branch from 5523148 to 6f4964a Compare February 26, 2026 09:26
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
shared/management/client/rest/reverse_proxy_services.go (1)

55-56: ⚠️ Potential issue | 🟡 Minor

Return nil, err on parse failure instead of &ret, err in Create and Update.

Same issue as flagged for Get: returning a non-nil pointer together with an error violates Go conventions. Apply the same fix pattern to both methods.

🔧 Proposed fix for Create (lines 55-56)
 	ret, err := parseResponse[api.Service](resp)
-	return &ret, err
+	if err != nil {
+		return nil, err
+	}
+	return &ret, nil
🔧 Proposed fix for Update (lines 72-73)
 	ret, err := parseResponse[api.Service](resp)
-	return &ret, err
+	if err != nil {
+		return nil, err
+	}
+	return &ret, nil

Also applies to: 72-73

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shared/management/client/rest/reverse_proxy_services.go` around lines 55 -
56, In Create and Update in reverse_proxy_services.go you currently call
parseResponse[api.Service](resp) and always return &ret, err; change the return
so that when err != nil you return nil, err instead of &ret, err, and only
return &ret, nil when parseResponse succeeded—adjust the return logic around the
parseResponse call (look for the ret variable and the lines returning &ret, err)
to follow Go conventions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@shared/management/client/rest/reverse_proxy_domains.go`:
- Around line 42-43: The current return of "&ret, err" after calling
parseResponse[api.ReverseProxyDomain](resp) can return a non-nil pointer when an
error occurred; update the code so you check the err from parseResponse and
return "nil, err" on failure, and only return "&ret, nil" when err is nil (i.e.,
replace the single-line "ret, err :=
parseResponse[api.ReverseProxyDomain](resp); return &ret, err" with an explicit
if err != nil { return nil, err } return &ret, nil).

---

Duplicate comments:
In `@shared/management/client/rest/reverse_proxy_services.go`:
- Around line 55-56: In Create and Update in reverse_proxy_services.go you
currently call parseResponse[api.Service](resp) and always return &ret, err;
change the return so that when err != nil you return nil, err instead of &ret,
err, and only return &ret, nil when parseResponse succeeded—adjust the return
logic around the parseResponse call (look for the ret variable and the lines
returning &ret, err) to follow Go conventions.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5523148 and 6f4964a.

📒 Files selected for processing (4)
  • shared/management/client/rest/client.go
  • shared/management/client/rest/reverse_proxy_clusters.go
  • shared/management/client/rest/reverse_proxy_domains.go
  • shared/management/client/rest/reverse_proxy_services.go

Comment thread shared/management/client/rest/reverse_proxy_domains.go Outdated
@lixmal lixmal force-pushed the reverse-proxy-rest-client branch from 6f4964a to ede9115 Compare February 26, 2026 09:56
@lixmal lixmal force-pushed the reverse-proxy-rest-client branch from ede9115 to 4e16483 Compare February 26, 2026 09:58
@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
shared/management/client/rest/client.go (1)

20-23: Consider including status code in error message for better diagnostics.

The Error() method only returns the message, which may lose useful context when the error is logged or wrapped. Including the status code helps with debugging.

💡 Optional enhancement
 // Error implements the error interface.
 func (e *APIError) Error() string {
-	return e.Message
+	return fmt.Sprintf("%d: %s", e.StatusCode, e.Message)
 }

This would require adding "fmt" to imports.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shared/management/client/rest/client.go` around lines 20 - 23, The
APIError.Error() method currently returns only e.Message; update it to include
the HTTP/status code for better diagnostics by returning a formatted string like
"status: message" (e.g., using fmt.Sprintf) so logs and wrapped errors show both
code and message; add the "fmt" import and modify the Error() method in the
APIError type to include e.Status (or the correct status field name) in the
returned string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@shared/management/client/rest/client.go`:
- Around line 20-23: The APIError.Error() method currently returns only
e.Message; update it to include the HTTP/status code for better diagnostics by
returning a formatted string like "status: message" (e.g., using fmt.Sprintf) so
logs and wrapped errors show both code and message; add the "fmt" import and
modify the Error() method in the APIError type to include e.Status (or the
correct status field name) in the returned string.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f4964a and 4e16483.

📒 Files selected for processing (4)
  • shared/management/client/rest/client.go
  • shared/management/client/rest/reverse_proxy_clusters.go
  • shared/management/client/rest/reverse_proxy_domains.go
  • shared/management/client/rest/reverse_proxy_services.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • shared/management/client/rest/reverse_proxy_clusters.go

@lixmal lixmal merged commit 0ca5953 into main Feb 28, 2026
40 checks passed
@lixmal lixmal deleted the reverse-proxy-rest-client branch February 28, 2026 05:05
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.

2 participants