Skip to content

Commit 854b1e4

Browse files
committed
Improve Api handling
1 parent edbd145 commit 854b1e4

4 files changed

Lines changed: 23 additions & 26 deletions

File tree

src/main/frontend/app/components/directory-picker/directory-picker.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ export default function DirectoryPicker({
3636
setEntries(result.entries)
3737
setCurrentPath(result.resolvedPath)
3838
setParentPath(result.parentPath)
39-
} catch (error_) {
40-
if (error_ instanceof ApiError && error_.status === 403) {
39+
} catch (error) {
40+
if (error instanceof ApiError && error.httpCode === 403) {
4141
setError('Access denied')
4242
} else {
43-
setError(error_ instanceof Error ? error_.message : 'Failed to load directories')
43+
setError(error instanceof Error ? error.message : 'Failed to load directories')
4444
}
4545
} finally {
4646
setLoading(false)

src/main/frontend/app/components/toast.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ const toastStyles = {
1818
container: defaultStyle,
1919
card: `${toastBaseCard} bg-error`,
2020
icon: '',
21-
defaultDuration: 2000,
21+
defaultDuration: 5000,
2222
},
2323
WARNING: {
2424
container: defaultStyle,
2525
card: `${toastBaseCard} bg-warning`,
2626
icon: '⚠️',
27-
defaultDuration: 3000,
27+
defaultDuration: 5000,
2828
},
2929
INFO: {
3030
container: defaultStyle,
@@ -36,7 +36,7 @@ const toastStyles = {
3636
container: defaultStyle,
3737
card: `${toastBaseCard} bg-success`,
3838
icon: '✅',
39-
defaultDuration: 3000,
39+
defaultDuration: 2000,
4040
},
4141
} as const
4242

src/main/frontend/app/routes/projectlanding/project-landing.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import FfIcon from '/icons/custom/ff!-icon.svg?react'
44
import ArchiveIcon from '/icons/solar/Archive.svg?react'
55
import { fetchInstanceConfigurations, type FFConfiguration } from '~/services/frank-framework-service'
66
import { useProjectStore } from '~/stores/project-store'
7+
import { ApiError } from '~/utils/api'
78

89
import ConfigurationRow from './configuration-row'
910
import Search from '~/components/search/search'
@@ -81,6 +82,10 @@ export default function ProjectLanding() {
8182
setFFInstanceName(ffInstance.name)
8283
setFFConfiguration(ffInstance.configurations)
8384
})
85+
.catch((error) => {
86+
if (error instanceof ApiError && error.httpCode === 404) return
87+
showErrorToast(error.message)
88+
})
8489
.finally(() => setIsDiscovering(false))
8590
}
8691

src/main/frontend/app/utils/api.ts

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,33 +19,29 @@ const getAuthToken = () => {
1919
}
2020

2121
interface BackendErrorResponse {
22-
httpStatus: number
23-
messages: string[]
24-
errorCode: string
22+
status: string
23+
error: string
2524
}
2625

2726
export class ApiError extends Error {
2827
constructor(
29-
public status: number,
30-
public messages?: string[],
31-
public errorCode?: string,
28+
public status: string,
29+
public error: string,
30+
public httpCode: number,
3231
) {
33-
super(messages ? messages.join(', ') : status.toString())
32+
super(error)
3433
this.name = 'ApiError'
3534
}
3635
}
3736

3837
export async function apiFetch<T>(path: string, options?: RequestInit): Promise<T> {
3938
const isFormData = options?.body instanceof FormData
4039

41-
const defaultHeaders: Record<string, string> =
42-
options?.body && !isFormData ? { 'Content-Type': 'application/json' } : {}
43-
4440
const headers: Record<string, string> = {
45-
...defaultHeaders,
46-
'X-Session-ID': getAnonymousSessionId(),
4741
...(options?.headers as Record<string, string>),
42+
'X-Session-ID': getAnonymousSessionId(),
4843
}
44+
if (options?.body && !isFormData) headers['Content-Type'] = 'application/json'
4945

5046
const token = getAuthToken()
5147
if (token) {
@@ -61,15 +57,11 @@ export async function apiFetch<T>(path: string, options?: RequestInit): Promise<
6157
const contentType = response.headers.get('content-type')
6258
if (contentType?.includes('application/json')) {
6359
const error: BackendErrorResponse = await response.json()
64-
throw new ApiError(error.httpStatus, error.messages, error.errorCode)
60+
throw new ApiError(error.status, error.error, response.status)
6561
}
66-
throw new ApiError(response.status, [response.statusText])
67-
}
68-
69-
const contentType = response.headers.get('content-type')
70-
if (contentType?.includes('application/json')) {
71-
return response.json()
62+
throw new ApiError('Server Error', `HTTP ${response.status} - ${response.statusText}`, response.status)
7263
}
7364

74-
return undefined as T
65+
// assume the response is in json as our API should always do, errors can be caught with <promise>.catch()
66+
return response.json()
7567
}

0 commit comments

Comments
 (0)