> I'd say it's probably best to use what's most common in the programming language to be used

Sure, I agree (or perhaps: what's considered "best practice"; or whatever our existing codebase is doing)

> there's a lot of discussions about if booleans, Eithers/Optionals or exceptions should be used

That's just an implementation detail, and misses the point. For example, all of those can be used to 'validate'; e.g.

- A function/method 'v1: JSON -> Boolean'

- A function/method 'v2: JSON -> JSON', which may throw exceptions

- A function/method 'v3: JSON -> Optional JSON'

- A function/method 'v4: JSON -> Either Error JSON'

The reason these are all bad has nothing to do with the language features or error-handling mechanisms employed. The reason they are bad is that they are all completely unnecessary.

For example, here are a bunch of programs which the above validators. They're all essentially equivalent, and hence have the same fundamental flaw:

function trigger1(userInput: JSON) {
if (v1(userInput)) {
print "UNAUTHORISED, ABORTING"
sys.exit(1)
}
else {
launchMissiles(authorisation=userInput)
}
}

function trigger2(userInput: JSON) {
try {
launchMissiles(authorisation=v2(userInput))
}
catch {
print "UNAUTHORISED, ABORTING"
sys.exit(1)
}
}

function trigger3(userInput: JSON) {
v3(userInput) match {
case None => {
print "UNAUTHORISED, ABORTING"
sys.exit(1)
}
case Some(validated) => {
launchMissiles(authorisation=validated)
}
)
}

function trigger4(userInput: JSON) {
v3(userInput) match {
case Left(error) => {
print ("UNAUTHORISED, ABORTING: " + error)
sys.exit(1)
}
case Right(validated) => {
launchMissiles(authorisation=userInput)
}
)
}

The reason they're all flawed is that validation can be skipped. In other words, you can write any validation logic; implemented with any mechanism you like; in any language; but your colleague's codde might never call it! All of the above 'trigger' functions could be replaced by this, and it will still work:

function trigger(userInput: JSON) {
launchMissiles(authoriser=userInput)
}

In contrast, the 'parse' approach cannot be skipped. Here are some examples:

- A function/method 'p1: JSON -> Either Error MyJSON'

- A function/method 'p2: JSON -> Optional MyJSON'

- A function/method 'p3: JSON -> MyJSON', which may throw exceptions

Here are their corresponding 'trigger' functions:

function trigger5(userInput: JSON) {
p1(userInput) match {
case Left(error) => {
print ("UNAUTHORISED, ABORTING: " + error)
sys.exit(1)
}
case Right(parsed) => {
launchMissiles(authorisation=parsed)
}
}
}

function trigger6(userInput: JSON) {
p2(userInput) match {
case None => {
print "UNAUTHORISED, ABORTING"
sys.exit(1)
}
case Some(parsed) => {
launchMissiles(authorisation=parsed)
}
}
}

function trigger7(userInput: JSON) {
try {
launchMissiles(authorisation=p3(userInput))
}
catch {
print ("UNAUTHORISED, ABORTING: " + error)
sys.exit(1)
}
}

These alternatives are much safer, since the 'launchMissiles' function now takes a 'MyJSON' value as argument; so we can't do `launchMissiles(authorisation=userInput)` (since 'userInput' has the type JSON, which isn't a valid input). Our colleages cannot skip or forget to call these p1/p2/p3 functions, since that's they only way they can turn the 'userInput' value they have, into a 'MyJSON' value they need.

> I don't want to implement that method "checkAgainstMySchema". Because I know there's already a library for that.

No, there isn't. I think you may be confused about how such 'parser' functions should be implemented. Nobody is saying to ignore existing libraries, or roll our own JSON grammars, or whatever. It's purely about how your project's datatypes are constructed. For example, something like this:

function parseMyThing(json: JSON) {
if (SomeExistingJSONSchemaLibrary.validate(json, SomeParticularSchemaMyApplicationIsUsing)) {
return Right(SomeDatatypeIHaveWritten(...))
}
else {
// Or use exceptions, or Optional, or whatever; it doesn't matter
return Left("Invalid")
}
}

(If all of your project's datatypes, schemas, class, etc. were already provided by some existing library, then that project would be a bit pointless!)