Apollo-link-rest: Manejo de la respuesta de error

Creado en 2 oct. 2018  ·  16Comentarios  ·  Fuente: apollographql/apollo-link-rest

Hola, tengo esta API de inicio de sesión que tomará el cuerpo de la solicitud como:

{
    "authentications": {
        "emailAddress": "[email protected]",
        "password": "11111111"
    }
}

El servidor devuelve el token si tiene éxito:

{
    "authentications": {
        "token": "eyJhbGoiU3RvcmUifV0sImNyZWF0ZWRBdCI6IjIwMTgtMDktMTZUMTg6NTA6NTYuNT"
    }
}

En caso de que la entrada de correo electrónico o contraseña sea incorrecta, devolverá:

{
    "message": "Cannot find document for class 'User'. searched with parameters: '{\"emailAddress\":\"[email protected]\"}'",
    "errorCode": 1103,
    "status": 404
}

Puedo iniciar sesión con éxito con un esquema GraphQL como este:

gql`
  fragment Authentications on any {
    emailAddress: String
    password: String
  }

  fragment AuthInput on REST {
    authentications {
      Authentications
    }
  }

  mutation signIn($input: AuthInput!) {
    authPayload(input: $input) 
      @rest(type: "AuthPayload", path: "/api/v1/authentications", endpoint:"UsersService", method:"POST") {
      authentications @type(name:"Auth"){
        token
      }
    }
  }
`;

Mi pregunta es ¿cómo puedo obtener la respuesta en caso de error (correo electrónico / contraseña incorrectos)? Porque en este momento, si el servidor devuelve un error, la respuesta siempre es nula:

Object {
    "data": Object {
        "authPayload": null,
    },
    "errors": undefined,
}
help wanted 🛠 question❔

Comentario más útil

También estoy atascado en este tema. ¿Hay alguna razón para no devolver la respuesta 404 completa en lugar de nula?

Todos 16 comentarios

Si no puede detectar el error 400+, creo que este problema será útil.
https://github.com/apollographql/apollo-link-rest/issues/151

FYI: para credenciales incorrectas, debe devolver el 401.
https://stackoverflow.com/questions/1959947/whats-an-apropiado-http-status-code-to-return-by-a-rest-api-service-for-a-val

Hola todos,

Me acabo de encontrar con esto y también me pregunto cuál es la forma recomendada de manejar un 404. No activa el apollo-link-error por ejemplo.

Hasta ahora, estoy pensando en escribir un enlace de controlador de errores personalizado o verificar el contenido de datos en la respuesta en cada componente <Query /> .

FWIW: Tengo el mismo caso en el que un servidor devuelve un 404 en lugar de un 401, por ejemplo, pero, lamentablemente, cambiar el servidor no es una opción en este momento.

Creo que valdría la pena abordar este caso de uso porque los códigos de estado para REST son muy diferentes, y más variados e importantes, que los de GraphQL.

También estoy atascado en este tema. ¿Hay alguna razón para no devolver la respuesta 404 completa en lugar de nula?

Todavía tengo que encontrarme con un caso en el que no tratar 404 como un error me haya ayudado, sigo tratando de encontrar una buena manera de solucionar ese hecho.

¿El pensamiento de que 404 No encontrado podría describir una consulta de datos que arroja correctamente el conjunto vacío?

También podría indicar que los propietarios del servicio hicieron un cambio tan importante que un punto final previamente disponible ha desaparecido.

Creo que el primer caso podría manejarse mejor con 200 OK junto con una entidad de aplicación vacía o nula. Al menos, parece que estos dos casos deberían ser fácilmente discernibles por el cliente, ya que son muy diferentes.

Sí, los conjuntos de datos intencionalmente vacíos son un poco más comunes de lo que uno podría pensar. (¡Al menos me sorprendió!) Dado que los usuarios a menudo recopilan múltiples redes y otras llamadas en una sola meta llamada, la omisión de arrojar un error en 404 tiene un impacto descomunal, porque un 404 terminaría todas las demás búsquedas de datos que ocurren en paralelo. Estoy de acuerdo si solo hubiera una llamada REST por consulta GraphQL ejecutada, me pareció que deberíamos lanzar un error dada la semántica oficial de REST.

¡En la práctica, no arrojar un error por defecto parecía mejor! Ya que puede solucionar esto agregando una búsqueda personalizada, y esto se siente como "sea liberal en lo que acepta"; esta elección parece coincidir con uno de los propósitos clave de Apollo-link-rest: ayudar a los usuarios que no necesariamente controlan el backend, y hay muchos servidores "principalmente REST", por lo que las violaciones semánticas son comunes .

@williamboman es relativamente sencillo configurar Apollo-link-rest para lanzar 404s si usa el parámetro customFetch No estoy en mi computadora, ¡pero avíseme si necesita ayuda para hacerlo!

Hola @fbartho ¿Pueden ayudarme a escribir customFetch para manejar errores 404? ¿Hay algún ejemplo al respecto?

@anasnain :

En javascript, se vería así:

export async function customFetch(requestInfo, init) {
  const response = await fetch(requestInfo, init);
  if (response.status === 404) {
    throw new Error("404 File Not Found"); // Customize this however you like!
  }
  return response;
}

(En TypeScript sería un poco más detallado)

@fbartho Gracias por la rápida respuesta. Ahora puedo coger el 404.
Pero, ¿cómo me aseguro de que networkError de apollo-link-error detecta el error (lanza un nuevo Error ("404 Archivo no encontrado")) escrito dentro de la recuperación personalizada?

Ah, desafortunadamente, creo que aparecerá adjunto a la matriz graphQLErrors (no en la propiedad networkError ) debido a las reglas internas de ApolloClient (sobre cómo funcionan los enlaces).

Es posible que esto se pueda arreglar, pero no sé cómo. - HTTPLink debe saber cómo hacerlo y no he tenido la oportunidad de investigar. Tenemos un método auxiliar en nuestra base de código (de trabajo) que simplemente descomprime los errores anidados. (Esto también era necesario para los errores lanzados desde apollo-link-state para nosotros, por lo que en realidad no era una prioridad)

@fbartho No recibo ningún error en este caso. los datos devuelven nulos. esperaba un error en lugar de datos si arrojamos un error. No estoy seguro de cómo implementar esto.

@anasnain Ha pasado tanto tiempo desde que lo configuré, lo olvidé.

También necesita configurar una instancia de apollo-link-error, esta es mi configuración:

const attachGQLErrorsToNetworkError = (
    graphQLErrors: readonly GraphQLError[],
    networkError: Error,
): void => {
    (networkError as any).tr_graphQLErrors = graphQLErrors;
    return;
};

/** Set behavior when errors occur and handle our own TR errors */
export const apolloErrorLink = onError((errorResponse: ErrorResponse) => {
    const {
        graphQLErrors = [],
        networkError,
    }: {
        graphQLErrors?: readonly GraphQLError[];
        networkError?: Error;
    } = errorResponse;

    /**
     * Our error parsing (function recursiveGQLErrorsFromNetworkError) rely
     * on attaching the following graphql errors.
     * Let's make sure to not attach anything `wrong` (ie: null, empty, ...)
     */
    const hasGraphQLErrors: boolean =
        graphQLErrors != null &&
        Array.isArray(graphQLErrors) &&
        graphQLErrors.length > 0;

    if (networkError && hasGraphQLErrors) {
        /*
         * graphQLErrors are not being passed through the chain of links,
         * but network errors are attaching the graphQLErrors to networkError
         * to be able to access them in a component
         */
        attachGQLErrorsToNetworkError(graphQLErrors, networkError);
    }
});

Después de una mayor reflexión: no estoy del todo seguro de entender la situación que estás describiendo.

¿El problema es que no puede leer el "error 404" en su componente / código de reacción?

@fbartho
Escenario: estoy ejecutando por debajo de rest APIquery y la expectativa es que debería obtener un objeto de error en caso de que devuelva el código de error 404, como en el caso de otros errores 4xx y errores 5xx. pero en este caso, el error no está definido y los datos son nulos.
const {cargando, error, datos} = useQuery (CLIENT_API_QUERY);

Esta es la instancia del cliente Apollo:

async function customFetch(requestInfo, init) {
    const response = await fetch(requestInfo, init);
    if (response.status === 404) {
        response.json().then((errorResponse) => {
          throw new Error(errorResponse);
        });
    }
    return response;
  }

const errorLink = onError(({ operation, response, graphQLErrors, networkError }) => {
    if (graphQLErrors) {
      graphQLErrors.forEach(({ message, path }) =>
           console.log(`[GraphQL error]: Message: ${message}, Path: ${path}`),
      );
    }
    if (networkError) {
        console.log(`[Network error ${operation.operationName}]: ${networkError.message}`);
    }
  });

const restLink = new RestLink({
    uri: 'https://run.mocky.io/v3/df72bacd-39cb-476d-bfda-06d7f5e9d77d',
    customFetch: (requestInfo, init) => customFetch(requestInfo, init)
});

const apolloClient = new ApolloClient({
    link: ApolloLink.from([errorLink, restLink]),
    new InMemoryCache(),
  });
export default apolloClient;

@anasnain : una cosa de la que soy consciente es que no creo que puedas pasar un objeto arbitrario al hacer new Error

Además, creo que te estás perdiendo un await, por lo que la instrucción throw ocurre fuera de la llamada restLink customFetch

const err = new Error("404 Error");
try {
  err.responseJson = await response.json(); // This await crucial to get the error in the right spot!
} catch (parsingError) {
  // figure out what you want to do with parsingError?
}
throw err;
¿Fue útil esta página
0 / 5 - 0 calificaciones