Skip to content

Commit

Permalink
RA extracts error messages from AxiosError (#519)
Browse files Browse the repository at this point in the history
* RA extracts error messages from AxiosError

* refactor and unify with `mutations.onError` handling in _app.tsx

---------

Co-authored-by: rtrembecky <[email protected]>
  • Loading branch information
vgeffer and rtrembecky authored Dec 14, 2024
1 parent b78317b commit bfa065a
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 41 deletions.
127 changes: 89 additions & 38 deletions src/components/Admin/dataProvider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import axios from 'axios'
import axios, {isAxiosError} from 'axios'
import {stringify} from 'querystring'
import {DataProvider, FilterPayload, /* PaginationPayload, */ RaRecord, SortPayload} from 'react-admin'
import {DataProvider, FilterPayload, /* PaginationPayload, */ SortPayload} from 'react-admin'

const getFilterQuery = ({q, ...otherSearchParams}: FilterPayload) => ({
...otherSearchParams,
Expand All @@ -13,6 +13,27 @@ const getOrderingQuery = ({order, field}: SortPayload) => ({ordering: `${order =
// limit: perPage,
// })

/* field errors by mali byt zachytene uz FE validaciou, dumpujem do 'Nastala neznáma chyba' */
const parseError = (error: unknown) => {
// povacsine matchuje `mutations.onError` v `_app.tsx`
if (isAxiosError(error)) {
const data = error.response?.data as unknown
if (typeof data === 'object' && data) {
const detail = 'detail' in data && data.detail
if (typeof detail === 'string') return detail

const nonFieldErrors = 'non_field_errors' in data && data.non_field_errors
const nonFieldErrorsUnknown = Array.isArray(nonFieldErrors) ? (nonFieldErrors as unknown[]) : []
const nonFieldErrorsJoined = nonFieldErrorsUnknown.every((e) => typeof e === 'string')
? nonFieldErrorsUnknown.join('\n')
: ''
if (nonFieldErrorsJoined) return nonFieldErrorsJoined
}
}

return 'Nastala neznáma chyba'
}

const apiUrl = '/api'

// skopirovane a dost upravene z https://github.com/bmihelac/ra-data-django-rest-framework/blob/master/src/index.ts
Expand All @@ -25,40 +46,55 @@ export const dataProvider: DataProvider = {
// ...getPaginationQuery(pagination),
}
const stringifiedQuery = stringify(query)
const {data} = await axios.get<any[]>(`${apiUrl}/${resource}${stringifiedQuery ? `/?${stringifiedQuery}` : ''}`)

// client-side pagination
let pagedData = data
if (pagination) {
const {page, perPage} = pagination
pagedData = data.slice((page - 1) * perPage, page * perPage)
}

return {
data: pagedData,
total: data.length,
try {
const {data} = await axios.get<any[]>(`${apiUrl}/${resource}${stringifiedQuery ? `/?${stringifiedQuery}` : ''}`)

Check warning on line 51 in src/components/Admin/dataProvider.ts

View workflow job for this annotation

GitHub Actions / branch-test

Unexpected any. Specify a different type

// client-side pagination
let pagedData = data
if (pagination) {
const {page, perPage} = pagination
pagedData = data.slice((page - 1) * perPage, page * perPage)
}

return {
data: pagedData,
total: data.length,
}
} catch (e) {
throw new Error(parseError(e))
}
},
getOne: async (resource, params) => {
const {data} = await axios.get(`${apiUrl}/${resource}/${params.id}`)

return {data}
try {
const {data} = await axios.get(`${apiUrl}/${resource}/${params.id}`)
return {data}
} catch (e) {
throw new Error(parseError(e))
}
},
getMany: async (resource, params) => {
const data = await Promise.all(params.ids.map((id) => axios.get(`${apiUrl}/${resource}/${id}`)))

return {data: data.map(({data}) => data)}
try {
const data = await Promise.all(params.ids.map((id) => axios.get(`${apiUrl}/${resource}/${id}`)))
return {data: data.map(({data}) => data)}
} catch (e) {
throw new Error(parseError(e))
}
},
// TODO: ak budeme pouzivat tuto funkciu, upravime podla getList (pagination, sort, filter). uprimne este neviem, pri com sa pouziva
getManyReference: async (resource, params) => {
const query = {
[params.target]: params.id,
}
const {data} = await axios.get(`${apiUrl}/${resource}/?${stringify(query)}`)

return {
data: data,
total: data.length,
try {
const {data} = await axios.get(`${apiUrl}/${resource}/?${stringify(query)}`)
return {
data: data,
total: data.length,
}
} catch (e) {
throw new Error(parseError(e))
}
},
update: async (resource, params) => {
Expand All @@ -68,32 +104,47 @@ export const dataProvider: DataProvider = {
// ked existuju formData, ktore sme do recordu pridali v `transform` v `MyEdit`, pouzijeme tie
const body = formData ?? input

const {data} = await axios.patch(`${apiUrl}/${resource}/${id}`, body)

return {data}
try {
const {data} = await axios.patch(`${apiUrl}/${resource}/${id}`, body)
return {data}
} catch (e) {
throw new Error(parseError(e))
}
},
updateMany: async (resource, params) => {
const data = await Promise.all(params.ids.map((id) => axios.patch(`${apiUrl}/${resource}/${id}`, params.data)))

return {data: data.map(({data}) => data)}
try {
const data = await Promise.all(params.ids.map((id) => axios.patch(`${apiUrl}/${resource}/${id}`, params.data)))
return {data: data.map(({data}) => data)}
} catch (e) {
throw new Error(parseError(e))
}
},
create: async (resource, params) => {
const {formData, ...input} = params.data

const body = formData ?? input

const {data} = await axios.post(`${apiUrl}/${resource}`, body)

return {data}
try {
const {data} = await axios.post(`${apiUrl}/${resource}`, body)
return {data}
} catch (e) {
throw new Error(parseError(e))
}
},
delete: async (resource, params) => {
const {data} = await axios.delete(`${apiUrl}/${resource}/${params.id}`)

return {data}
try {
const {data} = await axios.delete(`${apiUrl}/${resource}/${params.id}`)
return {data}
} catch (e) {
throw new Error(parseError(e))
}
},
deleteMany: async (resource, params) => {
const data = await Promise.all(params.ids.map((id) => axios.delete(`${apiUrl}/${resource}/${id}`)))

return {data: data.map(({data}) => data.id)}
try {
const data = await Promise.all(params.ids.map((id) => axios.delete(`${apiUrl}/${resource}/${id}`)))
return {data: data.map(({data}) => data.id)}
} catch (e) {
throw new Error(parseError(e))
}
},
}
9 changes: 6 additions & 3 deletions src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,12 @@ const ReactQueryProvider: FC<PropsWithChildren> = ({children}) => {

// ak nie, ale mame message v `.non_field_errors`, ukazeme ten
const nonFieldErrors = 'non_field_errors' in data && data.non_field_errors
const nonFieldError = Array.isArray(nonFieldErrors) && (nonFieldErrors as unknown[])[0]
if (typeof nonFieldError === 'string') {
alert(nonFieldError)
const nonFieldErrorsUnknown = Array.isArray(nonFieldErrors) ? (nonFieldErrors as unknown[]) : []
const nonFieldErrorsJoined = nonFieldErrorsUnknown.every((e) => typeof e === 'string')
? nonFieldErrorsUnknown.join('\n')
: ''
if (nonFieldErrorsJoined) {
alert(nonFieldErrorsJoined)
return
}

Expand Down

0 comments on commit bfa065a

Please sign in to comment.