Ktor-OpenAPI-Generator icon indicating copy to clipboard operation
Ktor-OpenAPI-Generator copied to clipboard

Proper handling of library generated errors

Open Wicpar opened this issue 5 years ago • 4 comments

Creating this because of #28 Currently there is no system to handle errors that occurred during runtime with this library. Instead i opted to use default values when parsing fails as it has best risk/effort ratio of the low effort options.

But now comes the time to implement it properly.

What it should do:

  • Have a default behaviour that is expected by the user
  • A standard format used by the library and it's extensions.
  • The errors should be aggregatable, all errors that can be known should be shown. (execution must continue after an error to catch other possible ones, i.e. two parameters have the wrong format or missing)
  • Error codes should allow for easy internationalisation
  • Contain What, Why and where it went wrong for every issue.
  • Should not leak information to the frontend beyond what is required to handle the error properly (No stacktraces.)

Wicpar avatar Mar 30 '20 22:03 Wicpar

I am open to suggestions.

The basic idea would be like this:

@FallbackHandler(DefaultExceptionHandlerObject::class)
class KtorOpenAPIGenException(val errors: List<KtorOpenAPIGenError>): Exception("Relevant human readable version")

data class KtorOpenAPIGenError(val origin: KClass<*>, val what: String, val why: String, val where: String)

// example

KtorOpenAPIGenError(PrimitiveParser::class, "Could not parse parameter", "Bad format, should be an int", "theParameterName")

Ideally there would be hints as to what the value should be beyond just the type, like if it is annotated by @Min and @Max it should reflect that if possible. But i haven't thought that through yet.

Wicpar avatar Mar 30 '20 22:03 Wicpar

In a similar vein, how does one handle parsing requests types. Previously I would assign and type cast the incoming request in the body of route that would allow me to handle parsing issues e.g.

try{
val fooRequest = call.receive<FooRequest>()
...
 } catch (e : Exception) {
            e.printStackTrace()
                    when(e) {
                        is MissingKotlinParameterException, is JsonParseException -> {
                            this.pipeline.call.respond(HttpStatusCode.BadRequest)
                        }
                        else -> this.pipeline.call.respond(HttpStatusCode.InternalServerError)
                    }
                }        

However this now appears to be out of my control, any suggestions on how I could handle the parsing of requests?

stefan-cross avatar Nov 02 '20 13:11 stefan-cross

regarding the above 👆

Ignore me, i had overlooked your examples, for the benefit of others though here was how to capture potential parsing of request types...

data class Error<P>(val id: String, val payload: P)

throws(HttpStatusCode.BadRequest, Error::class, ({e: MissingKotlinParameterException -> Error("Your error", "and more details..")})) {
            route("/foo").post(....

Happy to help contribute on this project as its very useful, perhaps I can help with the docs?

stefan-cross avatar Nov 02 '20 13:11 stefan-cross

Any help is welcome, especially with the docs :)

Wicpar avatar Nov 02 '20 14:11 Wicpar