mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
[FE-3035] fix(studio): show /rest/v1/ suffix on Data API overview URL (#45045)
The Data API overview page (`/integrations/data_api/overview`) was showing the project URL as `https://xxx.supabase.co`, but the documented Data API base URL is `https://xxx.supabase.co/rest/v1/`. This normalizes the URL so it matches the docs. **Changed:** - `getApiEndpoint` now appends `/rest/v1/` to the resolved endpoint (only used by the Data API overview card, so no other dashboard URLs are affected) ## To test - Visit `/dashboard/project/_/integrations/data_api/overview` and confirm the API URL field ends with `/rest/v1/` - Switch the database selector between primary, a read replica, and (if available) a load balancer — all should show a URL ending in `/rest/v1/` - With a custom domain active, the custom domain URL should also end with `/rest/v1/` Addresses [FE-3035](https://linear.app/supabase/issue/FE-3035/dashboard-data-api-page-shows-inconsistent-api-url) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Bug Fixes** * API endpoints are now properly normalized to ensure consistent path formatting with the `/rest/v1/` suffix across all endpoint sources. * Fixed URL handling for custom domain and load balancer endpoint selection. * Enhanced replica database URL handling to ensure correct trailing slash formatting. * **Tests** * Updated test expectations and added new test cases to verify proper endpoint normalization behavior. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
This commit is contained in:
1 parent
865ffb8e01
commit
d0d41e00d6
2 files changed
+34
-12
No files matched your search
@@ -13,7 +13,7 @@ const makeDatabase = (
|
||||
const makeLoadBalancer = (endpoint: string): Pick<LoadBalancer, 'endpoint'> => ({ endpoint })
|
||||
|
||||
describe('getApiEndpoint', () => {
|
||||
it('returns custom domain URL when custom domain is active and primary database is selected', () => {
|
||||
it('returns custom domain URL with /rest/v1/ when custom domain is active and primary database is selected', () => {
|
||||
expect(
|
||||
getApiEndpoint({
|
||||
selectedDatabaseId: 'project-ref',
|
||||
@@ -22,10 +22,10 @@ describe('getApiEndpoint', () => {
|
||||
loadBalancers: undefined,
|
||||
selectedDatabase: makeDatabase(
|
||||
'project-ref',
|
||||
'https://project-ref.supabase.co/rest/v1'
|
||||
'https://project-ref.supabase.co/rest/v1/'
|
||||
) as Database,
|
||||
})
|
||||
).toBe('https://api.example.com')
|
||||
).toBe('https://api.example.com/rest/v1/')
|
||||
})
|
||||
|
||||
it('returns database restUrl when custom domain is active but a replica is selected', () => {
|
||||
@@ -35,15 +35,30 @@ describe('getApiEndpoint', () => {
|
||||
projectRef: 'project-ref',
|
||||
resolvedEndpoint: 'https://api.example.com',
|
||||
loadBalancers: undefined,
|
||||
selectedDatabase: makeDatabase(
|
||||
'replica-1',
|
||||
'https://replica-1.supabase.co/rest/v1/'
|
||||
) as Database,
|
||||
})
|
||||
).toBe('https://replica-1.supabase.co/rest/v1/')
|
||||
})
|
||||
|
||||
it('normalizes a replica restUrl without a trailing slash', () => {
|
||||
expect(
|
||||
getApiEndpoint({
|
||||
selectedDatabaseId: 'replica-1',
|
||||
projectRef: 'project-ref',
|
||||
resolvedEndpoint: undefined,
|
||||
loadBalancers: undefined,
|
||||
selectedDatabase: makeDatabase(
|
||||
'replica-1',
|
||||
'https://replica-1.supabase.co/rest/v1'
|
||||
) as Database,
|
||||
})
|
||||
).toBe('https://replica-1.supabase.co/rest/v1')
|
||||
).toBe('https://replica-1.supabase.co/rest/v1/')
|
||||
})
|
||||
|
||||
it('returns load balancer endpoint when load balancer is selected', () => {
|
||||
it('returns load balancer endpoint with /rest/v1/ when load balancer is selected', () => {
|
||||
expect(
|
||||
getApiEndpoint({
|
||||
selectedDatabaseId: 'load-balancer',
|
||||
@@ -52,7 +67,7 @@ describe('getApiEndpoint', () => {
|
||||
loadBalancers: [makeLoadBalancer('https://lb.supabase.co') as LoadBalancer],
|
||||
selectedDatabase: undefined,
|
||||
})
|
||||
).toBe('https://lb.supabase.co')
|
||||
).toBe('https://lb.supabase.co/rest/v1/')
|
||||
})
|
||||
|
||||
it('returns empty string when load balancer is selected but none exist', () => {
|
||||
@@ -76,10 +91,10 @@ describe('getApiEndpoint', () => {
|
||||
loadBalancers: undefined,
|
||||
selectedDatabase: makeDatabase(
|
||||
'replica-2',
|
||||
'https://replica-2.supabase.co/rest/v1'
|
||||
'https://replica-2.supabase.co/rest/v1/'
|
||||
) as Database,
|
||||
})
|
||||
).toBe('https://replica-2.supabase.co/rest/v1')
|
||||
).toBe('https://replica-2.supabase.co/rest/v1/')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@ import { snakeToCamel } from '@/lib/helpers'
|
||||
|
||||
/**
|
||||
* Resolves the API endpoint URL based on the selected database, custom domain
|
||||
* status, and load balancer configuration.
|
||||
* status, and load balancer configuration. The returned URL is normalized to
|
||||
* end with `/rest/v1/` to match the Data API base path documented elsewhere.
|
||||
*/
|
||||
export function getApiEndpoint({
|
||||
selectedDatabaseId,
|
||||
@@ -23,14 +24,20 @@ export function getApiEndpoint({
|
||||
const loadBalancerSelected = selectedDatabaseId === 'load-balancer'
|
||||
|
||||
if (selectedDatabaseId === projectRef && !!resolvedEndpoint) {
|
||||
return resolvedEndpoint
|
||||
return withDataApiPath(resolvedEndpoint)
|
||||
}
|
||||
|
||||
if (loadBalancerSelected) {
|
||||
return loadBalancers?.[0]?.endpoint ?? ''
|
||||
return withDataApiPath(loadBalancers?.[0]?.endpoint)
|
||||
}
|
||||
|
||||
return selectedDatabase?.restUrl ?? ''
|
||||
return withDataApiPath(selectedDatabase?.restUrl)
|
||||
}
|
||||
|
||||
function withDataApiPath(url: string | undefined): string {
|
||||
if (!url) return ''
|
||||
const trimmed = url.replace(/\/+$/, '')
|
||||
return /\/rest\/v1$/.test(trimmed) ? `${trimmed}/` : `${trimmed}/rest/v1/`
|
||||
}
|
||||
|
||||
export type EnrichedEntity = { id: string; displayName: string; camelCase: string }
|
||||
|
||||
Reference in new issue
Block a user