[FOLIO-1716] Uniquely identify backend API validation errors Created: 17/Jan/19  Updated: 02/Sep/21  Resolved: 02/Sep/21

Status: Closed
Project: FOLIO
Components: None
Affects versions: None
Fix versions: None

Type: Task Priority: P2
Reporter: Marc Johnson Assignee: Unassigned
Resolution: Won't Do Votes: 0
Labels: i18n, potential-decision
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original estimate: Not Specified

Issue links:
Gantt End to Start
has to be done before UIU-977 renewal failure messages are not inte... Open
Relates
relates to CIRC-1146 Internationalize back-end failure mes... In Progress
relates to UIREQ-211 Make Request Policy Effective At Requ... Closed
relates to UIREQ-603 Internationalize back-end failure mes... Closed
relates to FOLIO-671 Respond with descriptive information ... Closed
relates to CIRC-476 Blocked patron can successfully place... Closed
relates to FOLIO-1965 API design for deletion prevention Closed
Sprint:
Development Team: Core: Platform
Affected Institution:
GBV

 Description   

It seems we have started using code as part of validation error in order to:

  • make decisions based upon the presence of a specific validation error in the client
  • facilitate localization of validation error messages in the client

See https://github.com/folio-org/raml/blob/raml1.0/schemas/error.schema

Is this intended to be the standard approach?

Does the UI currently use some of the existing examples?

If it is intended to be the standard approach, I believe there are some decisions we could need to make.

Potential Decisions

  • Should all validation error messages be expected to have a unique code? (and if so, should this be part of the definition of done for backend stories?
  • How should these codes be named?
  • Are codes owned by interfaces or implementing modules?
  • How do we avoid naming conflicts between modules?
  • How does a client know what the set of potential unique errors are?
  • If used for localisation, how does a client map parameterised errors to messages?


 Comments   
Comment by Kostyantyn Khodarev [ 17/Jan/19 ]

Marc Johnson And in addition, should current text messages (for 400, 500 etc. status codes) be converted to codes as well?

Comment by Marc Johnson [ 17/Jan/19 ]

Kostyantyn Khodarev I think that is a good question, that related to the outstanding question in FOLIO-671 Closed .

I think it is worth keeping the decision about validation / process errors (which the reference UI treats differently) separate to other kinds of errors (which at the moment, the reference UI just alerts on verbatim, as they are often not intended to be user actionable).

Comment by Zak Burke [ 02/Apr/19 ]

A Code4lib posting about JHOVE mentions the merits of providing permanent identifiers for server-side error messages:

There are now permanent and unique IDs for all JHOVE error and information messages. This means error catching need no longer be done by string matching.

https://lists.clir.org/cgi-bin/wa?A2=ind1904&L=CODE4LIB&P=12196

Comment by Peter Murray [ 15/Apr/20 ]

Redirecting comments from CIRC-476 Closed :

Please post subsequent comments here rather than CIRC-476 Closed . RFC draft will be available soon.

Comment by Mike Taylor [ 15/Apr/20 ]

Zak Burke and I, briefly discussing on Slack, were both pleased to see how closely our proposals resemble each other, and hope that indicates that they may be closing in on some kind of Platonic Ideal for how to do this stuff.

BTW., this isn't only about validation errors, but potentially any errors. Validation was just an interesting motivating example, because it's easy to imagine wanting to accompany a validation error with structured data containing details about the various fields that failed.

Comment by Marc Johnson [ 08/May/20 ]

Mike Taylor

BTW., this isn't only about validation errors, but potentially any errors

Please could you provide some examples of the other kinds of errors you are thinking about here. Does this refer to business logic decisions, e.g. this item cannot be checked out to patron A because patron B has already requested it, or are we considering any kind of error that the system could encounter e.g. the database is unreachable or another module is unreachable?

Comment by Zak Burke [ 08/May/20 ]

What are the merits of not using static values? Personally, I imagine a static code and/or name and some kind of supplementaryData object where we can provide dynamic values to the client.

{
    errorCode: 123,
    errorName: "ITEM_ALREADY_REQUESTED",
    supplementaryData: {
        requestId: "123abc",
    }
}

{
    errorCode: 123,
    errorName: "ITEM_ALREADY_REQUESTED",
    supplementaryData: {
        checkoutPatronId: "123abc",
        requestPatronId: "789efg"
    }
}

{
    errorCode: 456,
    errorName: "DATABASE_UNREACHABLE",
    supplementaryData: {
        systemResponse: "Something long and verbose and scary sounding, 192.168.11.22, OH NOES! An IP address!!!"
    }
}

Alternatively/additionally/maaaaaybe, we provide an errorMessage field that includes a human-readable message in the language matching the Accept-Language header of the request that generated the error.

{
    errorCode: 123,
    errorName: "ITEM_ALREADY_REQUESTED",
    errorMessage: "Das is nicht really Deutsch da Ich don't actually spraken Deutsch.",
    supplementaryData: {
        requestId: "123abc",
    }
}

This would simplify things on the UI side because we could forward such values directly to the UI, and that's nicer for folks calling the API directly, and maybe there some logging benefits since errors are now localized. But it also means we split translation over the front-end and back-end AND we have to introduce i18n capabilities to all backend modules. I'm not a backend dev, but that feels like a huge project.

Comment by Mike Taylor [ 10/May/20 ]

Marc Johnson The value here arises in any kind of error condition that the client could react to intelligently if it had details. Validation is an obvious one, because it could highlight the relevant fields that had validation errors. But it could be anything.

Comment by Mike Taylor [ 10/May/20 ]

Oh, and Zak Burke I agree we don't want to impose the burden of i18n on back-end modules.

Comment by Marc Johnson [ 11/May/20 ]

Zak Burke

What are the merits of not using static values?

By static value, do you mean a fixed value that is known in advance to both the server and clients that uniquely identifies a particular kind of error?

it also means we split translation over the front-end and back-end AND we have to introduce i18n capabilities to all backend modules. I'm not a backend dev, but that feels like a huge project.

Yes, this would be a significant architectural change and require significant investment. The first step being to determine what the equivalent workflow would be for how translations are changed in the UI modules.

Comment by Marc Johnson [ 11/May/20 ]

Mike Taylor Thanks

The value here arises in any kind of error condition that the client could react to intelligently if it had details. Validation is an obvious one, because it could highlight the relevant fields that had validation errors. But it could be anything.

Can you think of other examples?

I think there likely needs to be some kind of bound on this. For example, would we want this to include technical errors like could not connect to a database, could not publish message, request timed out etc?

Comment by Mike Taylor [ 11/May/20 ]

Marc Johnson The issue here is not what specific scenarios it might be useful, but what category. It's about situations in which the client can actually take action based on the machine-readable code, rather than merely displaying it to the user.

There is no value in the numeric code 54 if all we're doing is telling the user "Error 54, I have no idea what that means". Or even "Error 54: could not connect to database", which is no more informative than "Could not connect to database". But if the client can take some action (or prompt the user to take some action) which would avoid the error, then there is merit in reporting it.

Comment by Zak Burke [ 11/May/20 ]

By static value, do you mean a fixed value that is known in advance to both the server and clients that uniquely identifies a particular kind of error?

Yes.

Can you think of other examples? I think there likely needs to be some kind of bound on this. For example, would we want this to include technical errors like could not connect to a database, could not publish message, request timed out etc?

Why should it be bounded? In the UI, any text that will be presented to the user that is known at compile time is extracted from the code and replaced with placeholder. These placeholders are then replaced at run-time with values pulled from the appropriate locale file. I see no reason for the backend to do anything different with the values it hard-codes.

As above, perhaps the backend does not need to translate those strings, but I see no reason why they should not be extracted and made available to the UI so it can be responsible for cataloging those values and making them available for translation.

Comment by Mike Taylor [ 11/May/20 ]

Zak Burke is right, of course — which means that I was wrong when I said there is no point sending a code 54 for "could not connect to database". If we want to be able to tell the user that at all, then a code is exactly what we do need.

Comment by Marc Johnson [ 11/May/20 ]

Mike Taylor

The issue here is not what specific scenarios it might be useful, but what category. It's about situations in which the client can actually take action based on the machine-readable code, rather than merely displaying it to the user.

Hmm, I thought most of this conversation was focused on localisation of error messages presented to the user. Is localisation an action by the client?

Comment by Marc Johnson [ 11/May/20 ]

Zak Burke

Why should it be bounded? In the UI, any text that will be presented to the user that is known at compile time is extracted from the code and replaced with placeholder. These placeholders are then replaced at run-time with values pulled from the appropriate locale file. I see no reason for the backend to do anything different with the values it hard-codes.

I'm suggesting it needs to be be bounded because this proposal relies on each kind of error being predicted in advance. They need to be predicted in order to be given a code that is understood by all servers and all clients.

There is an overhead to that prediction process and it is likely to be fallible, which means there will need to be agreement on what happens when the actual error cannot be identified as fitting into one of these kinds / categories.

Does that make sense?

Comment by Mike Taylor [ 11/May/20 ]

No, no. We would surely add new error codes to the global list as and when they are needed. Client code would have a fallback path (as indeed it would need any) for unrecognised codes, presumably just displaying them to the user. The idea that we can, in advance, enumerate all possible error conditions seems more than a little fanciful.

Comment by Marc Johnson [ 11/May/20 ]

Mike Taylor

The idea that we can, in advance, enumerate all possible error conditions seems more than a little fanciful.

Agreed.

No, no. We would surely add new error codes to the global list as and when they are needed.

Agreed. This is what I meant by bounded. That the set of known kinds of errors (and hence codes) is limited in some way.

Client code would have a fallback path (as indeed it would need any) for unrecognised codes, presumably just displaying them to the user.

Agreed, there needs to be a fallback. I think there are a few variations on this:

  • There is no code defined for this kind of error (it is effectively unknown to the system)
  • There is a code defined for this kind of error however the server does not know it, so cannot provide it with the error
  • There is a code defined for this kind of error however the client does not know it, so cannot interpret the error
Comment by Mike Taylor [ 11/May/20 ]

What would it mean for a code to be unknown to both the client and the server? What else is there to know it?

I think the only scenarios that matter are:

  • Server provides code that the client recognises
  • Server provides code that the client does not recognise
Comment by Marc Johnson [ 12/May/20 ]

Mike Taylor

What would it mean for a code to be unknown to both the client and the server?

I don't think I described a scenario where it is unknown to both, maybe it is implicit in the error being unknown to FOLIO.

What else is there to know it?

I interpreted your previous statement (below), as suggesting there was a global list of codes defined for FOLIO. That is the other places that knows the codes.

We would surely add new error codes to the global list as and when they are needed

My variations were likely ambiguous. Let me ask them a different way.

  • What should a server do when it encounters an error it does not recognise or know the code for (there may be no code defined)?
  • What should a client do when it encounters an error with a code it does not recognise?
  • If the server can respond with no code for situations it does not recognise or does not know the code, what should a client do when it encounters an error with no code?
Comment by Marc Johnson [ 02/Sep/21 ]

Has been superseded by later conversations

Generated at Thu Feb 08 23:15:22 UTC 2024 using Jira 1001.0.0-SNAPSHOT#100246-sha1:7a5c50119eb0633d306e14180817ddef5e80c75d.