Failing commands and reporting them as HTTP status code

Within command handler of my entity I do some business rules validation. So far, I simply reported an invalid command, but I’d like a more verbose reason as to why.

So, I changed:

if (someDondition) {
  ctx.invalidCommand("REASON")
  ctx.done
}

to

if (someDondition) {
  ctx.commandFailed(BadRequest("REASON"))
  ctx.done
}

When re-running my tests, I got the following warning:

[WARN] [SECURITY][07/08/2019 10:54:37.443] [ScalaTest-run-running-FooEntitySpec] [akka.serialization.Serialization(akka://FooEntitySpec)] Using the default Java serializer for class [com.lightbend.lagom.scaladsl.api.transport.BadRequest] which is not recommended because of performance implications. Use another serializer or disable this warning using the setting 'akka.actor.warn-about-java-serializer-usage'

With the following issue:

Vector(
  Object [
    com.lightbend.lagom.scaladsl.api.transport.BadRequest: REASON (400/1003 Unsupported Data/Bad Request)] 
  does not equal [
    com.lightbend.lagom.scaladsl.api.transport.BadRequest: REASON (400/1003 Unsupported Data/Bad Request)] 

after serialization/deserialization) was not empty

I feel like I’m misusing the API, since I believe I read that TransportExceptions that come with Lagom have a serializer out of the box.

Any insights?

Hi Ivan,

I personally do not use commandFailed but would say that BadRequest is used in Message serializer and not in Persistent entity one. You would need to register it explicitly.

I would not recommend using API related exceptions in Persistent Entity because it is coupling it with API logic.
You could create custom exception or create custom “command reply” object and then map it to API logic (BadRequest for example).

Hope this helps.

Br,
Alan

Yeah, I digged a bit deeper and saw no Persistent entity serializer for BadRequest.

When would you then recommend using invalidCommand (since it calls commandFailed under the hood, with InvalidCommandException as argument) over a command reply object (which would have semantics similar to Either or Validated)?

I use custom reply object that is replied instead of Done. So not using invalidCommand or commandFailed but reply.
Something similar used in ReadOnlyCommand for GET.
Example: this

Br,
Alan

I saw a recommendation on (on GitHub, I believe) not to use types with holes as reply types.
I’m assuming I need some ADT then which will be some success or failure.
If that is so, am I correct that my service impl should use ServerServiceCall and map replies to HTTP statuses as well?

...
ref.ask(MyCommand(...)).map {
  case reply @ (_: Ok) => (ResponseHeader.Ok, reply)
  case reply @ (_: NotOk) => (ResponseHeader.BadRequest, reply)
}

You do not need to use ServerServiceCall but just throw BadRequest exception in case of NotOk.
Example: this

Br,
Alan

Yeah, I’ve seen this, but I’m trying to avoid using exceptions to control the execution flow, let it be as simple as this.

What are the implications of throwing exceptions in entities, then catching them in services and re-throwing again?
I know Lagom is in no way a purist framework, but I find more peace of mind when I encode my results (successes and failures) into types rather than relying on exceptions which are not really visible from the outside of the class.

If you are referring to commandFailed, there are no implications. It is valid like reply or invalidCommand.
Maybe my suggestion regarding not using BadRequest exception (as specific API exception) in entity confused you.

Ah, cool!
So, let’s see if I understood you correctly: It’s OK to use an ADT to represent successful command replies, and it’s OK to use Throwable subclasses to represent failed commands (via commandFailed).

You understood it correctly.