fix(ssr): résoudre une base absolue pour les fetch API côté serveur (page édition)
This commit is contained in:
1 parent
8ff530bf99
commit
0ca2846f2b
3 files changed
+58
-1
No files matched your search
@@ -1,6 +1,9 @@
|
||||
# Variables exposées au client (préfixées NEXT_PUBLIC_)
|
||||
# NEXT_PUBLIC_API_URL=http://localhost:3000
|
||||
|
||||
# Base interne pour les fetch SSR (port interne du serveur Next.js, défaut 3000)
|
||||
# API_BASE_URL=http://localhost:3000
|
||||
|
||||
# Implémentation repository active : mysql | mongo
|
||||
DB_IMPL=mysql
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// @vitest-environment node
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const fetchMock = vi.fn()
|
||||
|
||||
async function loadModule(env?: Record<string, string>) {
|
||||
vi.resetModules()
|
||||
delete process.env.API_BASE_URL
|
||||
if (env) Object.assign(process.env, env)
|
||||
return (await import('./api-client')) as typeof import('./api-client')
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
global.fetch = fetchMock as unknown as typeof fetch
|
||||
fetchMock.mockReset()
|
||||
})
|
||||
|
||||
describe('cardsApi (SSR / Node)', () => {
|
||||
it("résout une URL absolue sur localhost:3000 en l'absence de window", async () => {
|
||||
const { cardsApi: api } = await loadModule()
|
||||
fetchMock.mockResolvedValue(
|
||||
new Response(JSON.stringify([]), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
)
|
||||
await api.list()
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'http://localhost:3000/api/cards',
|
||||
expect.objectContaining({ method: 'GET' }),
|
||||
)
|
||||
})
|
||||
|
||||
it('respecte API_BASE_URL si elle est définie', async () => {
|
||||
const { cardsApi: api } = await loadModule({ API_BASE_URL: 'http://api:9999' })
|
||||
fetchMock.mockResolvedValue(
|
||||
new Response(JSON.stringify([]), {
|
||||
status: 200,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
}),
|
||||
)
|
||||
await api.list()
|
||||
expect(fetchMock).toHaveBeenCalledWith(
|
||||
'http://api:9999/api/cards',
|
||||
expect.objectContaining({ method: 'GET' }),
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -14,10 +14,16 @@ interface ApiErrorPayload {
|
||||
message?: string
|
||||
}
|
||||
|
||||
// Côté serveur (SSR/standalone), une URL relative n'est pas résolvable :
|
||||
// on cible la propre API de l'application (port interne 3000). Côté client,
|
||||
// l'URL relative est résolue par le navigateur.
|
||||
const API_BASE_URL =
|
||||
typeof window === 'undefined' ? (process.env.API_BASE_URL ?? 'http://localhost:3000') : ''
|
||||
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
let res: Response
|
||||
try {
|
||||
res = await fetch(path, {
|
||||
res = await fetch(`${API_BASE_URL}${path}`, {
|
||||
method: init?.method ?? 'GET',
|
||||
...init,
|
||||
headers: { 'Content-Type': 'application/json', ...init?.headers },
|
||||
|
||||
Reference in new issue
Block a user