J. Carpeta « libclienteweb »

Versión para imprimir.

A. libclienteweb / consume.js

1
import { ProblemDetailsError } from "./ProblemDetailsError.js"
2
3
/**
4
 * Espera a que la promesa de un fetch termine. Si
5
 * hay error, lanza una excepción.
6
 * 
7
 * @param {Promise<Response> } servicio
8
 */
9
export async function consume(servicio) {
10
 const respuesta = await servicio
11
 if (respuesta.ok) {
12
  return respuesta
13
 } else {
14
  const contentType = respuesta.headers.get("Content-Type")
15
  if (
16
   contentType !== null && contentType.startsWith("application/problem+json")
17
  )
18
   throw new ProblemDetailsError(await respuesta.json())
19
  else
20
   throw new Error(respuesta.statusText)
21
 }
22
}

B. libclienteweb / manejaErrores.js

1
import { muestraError } from "./muestraError.js"
2
3
/**
4
 * Intercepta Response.prototype.json para capturar errores de parseo
5
 * y asegurar que se reporten correctamente en navegadores Chromium.
6
 */
7
{
8
 const originalJson = Response.prototype.json
9
10
 Response.prototype.json = function () {
11
  // Llamamos al método original usando el contexto (this) de la respuesta
12
  return originalJson.call(this)
13
   .catch((/** @type {any} */ error) => {
14
    // Corrige un error de Chrome que evita el manejo correcto de errores.
15
    throw new Error(error)
16
   })
17
 }
18
}
19
20
window.onerror = function (
21
 /** @type {Event | string} */ _event,
22
 /** @type {string | undefined} */ _fuente,
23
 /** @type {number | undefined} */ _numeroDeLinea,
24
 /** @type {number | undefined} */ _numeroDeColumna,
25
 /** @type {Error | undefined} */ error
26
) {
27
 muestraError(error)
28
 return true
29
}
30
31
window.addEventListener('unhandledrejection', event => {
32
 muestraError(event.reason)
33
 event.preventDefault()
34
})

C. libclienteweb / muestraError.js

1
import { ProblemDetailsError } from "./ProblemDetailsError.js"
2
3
/**
4
 * Muestra los datos de una Error en la consola y en un cuadro de alerta.
5
 * @param { unknown } error descripción del error.
6
 */
7
export function muestraError(error) {
8
9
 if (error instanceof ProblemDetailsError) {
10
11
  const problemDetails = error.problemDetails
12
13
  let mensaje =
14
   typeof problemDetails["title"] === "string" ? problemDetails["title"] : ""
15
  if (typeof problemDetails["detail"] === "string") {
16
   if (mensaje !== "") {
17
    mensaje += "\n"
18
   }
19
   mensaje += problemDetails["detail"]
20
  }
21
  if (mensaje === "") {
22
   mensaje = "Error"
23
  }
24
  console.error(error, problemDetails)
25
  alert(mensaje)
26
27
 } else if (
28
  typeof error === "object" && error !== null && "message" in error
29
 ) {
30
31
  console.error(error)
32
  alert(error.message)
33
34
 } else {
35
36
  console.error("Error", error)
37
  alert("Error")
38
39
 }
40
41
}

D. libclienteweb / ProblemDetailsError.js

1
export class ProblemDetailsError extends Error {
2
3
 /**
4
  * Detalle de los errores devueltos por un servicio.
5
  * Crea una instancia de ProblemDetailsError.
6
  * @param {any} problemDetails Objeto con la descripcipon del error.
7
  */
8
 constructor(problemDetails) {
9
10
  super(
11
   typeof problemDetails["detail"] === "string"
12
    ? problemDetails["detail"]
13
    : (
14
     typeof problemDetails["title"] === "string"
15
      ? problemDetails["title"]
16
      : "Error"
17
    )
18
  )
19
20
  this.problemDetails = problemDetails
21
22
 }
23
24
}

E. libclienteweb / submitFormRecibeJson.js

1
/**
2
 * Envía los datos de un formolario a la url usando la codificación
3
 * multipart/form-data.
4
 * @param {string} url
5
 * @param {HTMLFormElement | FormData} formulario
6
 * @param { "GET" | "POST"| "PUT" | "PATCH" | "DELETE" | "TRACE" | "OPTIONS"
7
 *  | "CONNECT" | "HEAD" } metodoHttp
8
 */
9
export function submitFormRecibeJson(url, formulario, metodoHttp = "POST") {
10
11
 const formData =
12
  formulario instanceof FormData ? formulario : new FormData(formulario)
13
14
 if (tieneArchivos(formData)) {
15
16
  return fetch(
17
   url,
18
   {
19
    method: metodoHttp,
20
    headers: { "Accept": "application/json, application/problem+json" },
21
    body: formData
22
   }
23
  )
24
25
 } else {
26
27
  // @ts-ignore
28
  const params = new URLSearchParams(formData)
29
  const queryString = params.toString()
30
31
  return fetch(
32
   url,
33
   {
34
    method: metodoHttp,
35
    headers: {
36
     'Content-Type': 'application/x-www-form-urlencoded',
37
     "Accept": "application/json, application/problem+json"
38
    },
39
    body: queryString
40
   }
41
  )
42
43
 }
44
45
}
46
47
/**
48
 * @param {FormData} formData
49
 */
50
function tieneArchivos(formData) {
51
 for (const value of formData.values()) {
52
  if (value instanceof File) {
53
   return true
54
  }
55
 }
56
 return false
57
}