Hacker Public Radio

HPR3392: Structured error reporting


Listen Later

Initial state
When I originally wanted a unified error reporting on the server-side, I made one huge type that enumerated all the possible error cases that could be reported:
-- | Error codes for all errors returned by API
data ErrorCode
-- common error codes
= ResourceNotFound
| InsufficientRights
| FailedToParseDataInDatabase
-- errors specific to news
| SpecialEventHasAlreadyBeenResolved
| UnsupportedArticleType
| SpecialNewsExtractionFailed
| TriedToMakeChoiceForRegularArticle
-- errors specific to simulation state
| SimulationStatusNotFound
| DeltaTIsTooBig
| TurnProcessingAndStateChangeDisallowed
| SimulationNotOpenForCommands
| SimulationNotOpenForBrowsing
-- errors specific to people
| StatIsTooLow Text
| CouldNotConfirmDateOfBirth
| DateOfBirthIsInFuture
| FirstNameIsEmpty
| FamilyNameIsEmpty
| CognomenIsEmpty
| RegnalNumberIsLessThanZero
-- errors specific to new person creation
| AgeBracketStartIsGreaterThanEnd
| PersonCreationFailed
deriving (Show, Read, Eq)
Then I had some helper functions to turn any value of that type into a nice error message:
errorCodeToStatusCode :: ErrorCode -> Int
statusCodeToText :: Int -> ByteString
errorCodeToText :: ErrorCode -> Text
raiseIfErrors :: [ErrorCode] -> HandlerFor App ()
errorCodeToStatusCode was responsible for turning ErrorCode into http status code. For example StatIsTooLow "intrigue" would be 400. statusCodeToText would take this code and turn it into short error message given in http response. 400 would be Bad Request. errorCodeToText would give a bit more verbose explanation of what happened, StatIsTooLow "intrigue" would be mapped to "Stat intrigue is too low". Finally raiseIfErrors would take a list of ErrorCode and use these helper functions to turn them into a http response with correct status code, error message and json body detailing all errors that had happened:
[
{ code:
{ tag: "StatIsTooLow"
, contents: "intrique"
}
, error: "Stat intrigue is too low"
}
]
There’s two tags: code, which contains machine readable details about the error and error, which contains error message that can be shown to user.
While this worked fine, there was some problems with it. ErrorCode type was growing larger and larger and the module it was defined in was referred all over the codebase. Every time I added a new error message, all the modules that used error reporting had to be compiled and it was getting slow.
Solution
Breaking up the ErrorCode to smaller types and moving them to different modules would means less modules were going to built when I added a new error code. The problem was that raiseIfErrors :: [ErrorCode] -> HandlerFor App () wanted a list of ErrorCode and elements in a list have to be of same type.
I started by splitting ErrorCode to smaller types. Each of the smaller error types have automatically derived toJSON and fromJSON functions for serializing them to and from JSON:
data PersonCreationError =
StatIsTooLow Text
| CouldNotConfirmDateOfBirth
| DateOfBirthIsInFuture
| FirstNameIsEmpty
| FamilyNameIsEmpty
| CognomenIsEmpty
| RegnalNumberIsLessThanZero
deriving (Show, Read, Eq)
$(deriveJSON defaultOptions ''PersonCreationError)
That $(deriveJSON defaultOptions ''PersonCreationError) is template haskell call. Basica
...more
View all episodesView all episodes
Download on the App Store

Hacker Public RadioBy Hacker Public Radio

  • 4.2
  • 4.2
  • 4.2
  • 4.2
  • 4.2

4.2

34 ratings


More shows like Hacker Public Radio

View all
The Changelog: Software Development, Open Source by Changelog Media

The Changelog: Software Development, Open Source

290 Listeners

Defensive Security Podcast - Malware, Hacking, Cyber Security & Infosec by Jerry Bell and Andrew Kalat

Defensive Security Podcast - Malware, Hacking, Cyber Security & Infosec

372 Listeners

LINUX Unplugged by Jupiter Broadcasting

LINUX Unplugged

268 Listeners

SANS Internet Stormcenter Daily Cyber Security Podcast (Stormcast) by Johannes B. Ullrich

SANS Internet Stormcenter Daily Cyber Security Podcast (Stormcast)

651 Listeners

Curious Cases by BBC Radio 4

Curious Cases

822 Listeners

The Strong Towns Podcast by Strong Towns

The Strong Towns Podcast

423 Listeners

Late Night Linux by The Late Night Linux Family

Late Night Linux

164 Listeners

Darknet Diaries by Jack Rhysider

Darknet Diaries

8,061 Listeners

Cybersecurity Today by Jim Love

Cybersecurity Today

179 Listeners

CISO Series Podcast by David Spark, Mike Johnson, and Andy Ellis

CISO Series Podcast

189 Listeners

TechCrunch Daily Crunch by TechCrunch

TechCrunch Daily Crunch

42 Listeners

Strict Scrutiny by Crooked Media

Strict Scrutiny

5,797 Listeners

2.5 Admins by The Late Night Linux Family

2.5 Admins

98 Listeners

Cyber Security Headlines by CISO Series

Cyber Security Headlines

139 Listeners

What the Hack? by DeleteMe

What the Hack?

228 Listeners