Patrick Ramsey
05/01/2021, 1:06 AMPatrick Ramsey
05/01/2021, 1:07 AMPatrick Ramsey
05/01/2021, 1:10 AMPatrick Ramsey
05/01/2021, 1:10 AMRob Murdock
05/01/2021, 2:18 AMRob Murdock
05/01/2021, 2:19 AMRob Murdock
05/01/2021, 2:22 AMsealed class Result<V>
data class SuccessfulResult<V>(val value: V) : Result<V>()
data class NotFoundResult<V>(val entityName: String) : Result<V>()
data class ErrorResult<V>(val message: String) : Result<V>()
class UnauthorizedResult<V> : Result<V>()
Def not perfect, but now I know everything coming through this process meets one of these forms. And if I need a new form, I add it, or refactor somehow.Patrick Ramsey
05/01/2021, 2:23 AMRob Murdock
05/01/2021, 2:25 AMPatrick Ramsey
05/01/2021, 2:27 AMRob Murdock
05/01/2021, 2:28 AMPatrick Ramsey
05/01/2021, 2:30 AMRob Murdock
05/01/2021, 2:30 AMRob Murdock
05/01/2021, 2:30 AMRob Murdock
05/01/2021, 2:31 AMPatrick Ramsey
05/01/2021, 2:31 AMRob Murdock
05/01/2021, 2:31 AMPatrick Ramsey
05/01/2021, 2:31 AMRob Murdock
05/01/2021, 2:31 AMRob Murdock
05/01/2021, 2:32 AMRob Murdock
05/01/2021, 2:33 AMPatrick Ramsey
05/01/2021, 2:35 AMPatrick Ramsey
05/01/2021, 2:37 AMPatrick Ramsey
05/01/2021, 2:37 AMRob Murdock
05/01/2021, 2:38 AMPatrick Ramsey
05/01/2021, 2:39 AMPatrick Ramsey
05/01/2021, 2:40 AMRob Murdock
05/01/2021, 2:45 AMRob Murdock
05/01/2021, 2:45 AMRob Murdock
05/01/2021, 2:45 AMPatrick Ramsey
05/01/2021, 2:47 AMHanno
05/01/2021, 4:13 PMCLOVIS
05/01/2021, 9:05 PMeither
block helps a lot. Essentially, it let's you have short-circuiting operations without exceptions.
For example:
val result = either {
val id = call.parameter(...).bind() // if fails, short-circuits the block
val token = call.parameter(...).bind() // same
db.doStuff(token, id).bind() // same
}
// Now, 'result' is either a failure (my own sealed class hierarchy of what could go wrong), or a successful value
This whole syntax abuses suspend
quite a bit, but it let's you code as if you had exceptions, but you don't, it's all an Either
return type.CLOVIS
05/01/2021, 9:06 PM!
instead of .bind())
Hanno
05/01/2021, 10:09 PMJordan Stewart
05/01/2021, 10:13 PMPatrick Ramsey
05/03/2021, 5:19 PMJordan Stewart
05/03/2021, 7:24 PMPatrick Ramsey
05/03/2021, 7:24 PMPatrick Ramsey
05/03/2021, 7:25 PMPatrick Ramsey
05/03/2021, 7:25 PMHanno
05/03/2021, 8:57 PMJordan Stewart
05/05/2021, 4:29 PMTest-User: <some user id>
, and then layer a custom interceptor on top of the standard http stack to replace this with a Authorization: Bearer <a dynamically issued JWT for 'some user id'>
header. This would leave the standard http stack untouched, make the test really clear about the authenticated user’s id (no need to decode a jwt to see the user id), etc.
With Ktor I couldn’t see how to modify the request object, so instead of simply modifying the request I had to add an ApplicationCall attribute in my interceptor and then have the standard http stack look for this attribute and treat whatever is in it as a trusted identity assertion. I guess this is probably ok from a security perspective (as long as client code can’t ever arbitrarily inject these attributes) but it’s certainly not as good as what I wanted to do in the first place, which is really easy to do in http4k since requests, whilst immutable, are passed as parameters between http interceptors.
I also found testing some stuff painful as everything is tied together, e.g. you can’t just create a request, as it needs an ApplicationCall, which needs an Application.Hanno
05/05/2021, 6:04 PM