Bladeren bron

improve web error handling

Aneurin Barker Snook 1 jaar geleden
bovenliggende
commit
318bee8a86
2 gewijzigde bestanden met toevoegingen van 26 en 4 verwijderingen
  1. 10 4
      web/src/api/lib.ts
  2. 16 0
      web/src/components/Notice.tsx

+ 10 - 4
web/src/api/lib.ts

@@ -41,23 +41,29 @@ export class RequestError extends Error {
   /**
   /**
    * Create a request API error by parsing a XMLHTTPRequest (which is presumed to have completed).
    * Create a request API error by parsing a XMLHTTPRequest (which is presumed to have completed).
    *
    *
-   * If the response is a standard REST error, its message and any additional data will be attached automatically to the RequestError.
+   * If the response is a standard REST error, the JSON message will be attached automatically to the RequestError.
+   * Any additional properties will be attached as data.
    * See `error` in <https://github.com/edge/misc-utils/blob/master/lib/http.ts> for more detail.
    * See `error` in <https://github.com/edge/misc-utils/blob/master/lib/http.ts> for more detail.
    *
    *
    * If the response is not a standard REST error then YMMV.
    * If the response is not a standard REST error then YMMV.
    */
    */
   static parse(xhr: XMLHttpRequest) {
   static parse(xhr: XMLHttpRequest) {
     let message = xhr.status.toString()
     let message = xhr.status.toString()
-    let data = undefined
+    let data: Record<string, unknown> | undefined = undefined
 
 
-    if (xhr.getResponseHeader('Content-Type')?.startsWith('application/json')) {
+    if (xhr.getResponseHeader('content-type')?.includes('application/json')) {
       const res = JSON.parse(xhr.response)
       const res = JSON.parse(xhr.response)
       if (isObject(res)) {
       if (isObject(res)) {
         if (res.message && typeof res.message === 'string') message = res.message
         if (res.message && typeof res.message === 'string') message = res.message
-        if (isObject(res.data)) data = res.data
+        data = {}
+        for (const key in res) {
+          if (key === 'message') continue
+          data[key] = res[key]
+        }
       }
       }
     }
     }
 
 
+
     return new this(message, data, xhr)
     return new this(message, data, xhr)
   }
   }
 }
 }

+ 16 - 0
web/src/components/Notice.tsx

@@ -1,5 +1,6 @@
 import './Notice.scss'
 import './Notice.scss'
 import type { PropsWithChildren } from 'react'
 import type { PropsWithChildren } from 'react'
+import type { RequestError } from '@/api'
 
 
 export interface NoticeProps {
 export interface NoticeProps {
   className?: string
   className?: string
@@ -7,6 +8,21 @@ export interface NoticeProps {
 }
 }
 
 
 export default function Notice({ className = '', error, ...props }: PropsWithChildren<NoticeProps>) {
 export default function Notice({ className = '', error, ...props }: PropsWithChildren<NoticeProps>) {
+  if (error?.name === 'RequestError') {
+    let message = ''
+    const re = error as RequestError
+    if (re.data) {
+      if (re.data.param && re.data.reason) message = `Error in ${re.data.param}: ${re.data.reason}`
+      else if (re.data.reason) message = `Error: ${re.data.reason}`
+    } else message = `Error: ${re.message}`
+
+    return (
+      <div className={`notice ${className} error api-error`}>
+        <span>{message}</span>
+      </div>
+    )
+  }
+
   if (error) return (
   if (error) return (
     <div className={`notice ${className} error`}>
     <div className={`notice ${className} error`}>
       <span>{error.message}</span>
       <span>{error.message}</span>