My goal is to validate User's fields within the object's applymethod before creating one effective User instance:
case class User(String userName, String password)
object User {
def apply(userValidator: UserValidator): ValidationNel[UserCreationFailure, User] = {
//call UserValidator's validate() method here and initialize effective User instance.
}
}
I chose to use Validation from Scalaz7 to accumulate potential illegal arguments / errors.
One drawback in the following code is that Scalaz7 API force me to make the validator creates itself the instance. However, by following Single-Responsibility principle, it's clearly not its role. Its role would be to just validate fields and to return some errors list.
Let's first present my actual code (for information, Empty**** objects are just some case object extending UserCreationFailure):
class UserValidator(val userName: String, val password: String)
extends CommonValidator[UserCreationFailure] {
def validate(): ValidationNel[UserCreationFailure, User] = {
(checkForUserName ⊛
checkForPassword)((userName, password) => new User(userName, password)
}
private def checkForUserName: ValidationNel[UserCreationFailure, String] = {
checkForNonEmptyString(userName) {
EmptyUserName
}
}
def checkForPassword: ValidationNel[UserCreationFailure, String] = {
checkForNonEmptyString(password) {
EmptyPassword
}
}
}
What I would expect is to merely return this snippet code:
(checkForUserName ⊛ checkForPassword)
and bring the appropriate result into my User class, allowing to create the effective instance by doing:
def apply(userValidator: UserValidator): ValidationNel[UserCreationFailure, User] = {
userValidator(username, password).validate()((userName, password)(new User(userName, password))
}
Indeed, it would be more friendly with SRP.
But (checkForUserName ⊛ checkForPassword) returns a totally private type type:
private[scalaz] trait ApplicativeBuilder[M[_], A, B],
thus I don't have the hand on the type of class returned.
Therefore, I am forced to directly associate User's creation with it.
How could I keep SRP and keep this validation mechanism?
-----UPDATE----
As #Travis Brown mentioned, the intent to use an external class for my UserValidator may seem weird. Actually, I expect the validator to be mockable and thus, I'm forced to use composition over trait/abstract class.
I'm not sure I understand why you need a dedicated UserValidator class in the first place. In a case like this I'd be more likely to bundle all of my generic validation code into a separate trait, and to have my User companion object (or whatever other piece I want to be responsible for creating User instances) extend that trait. Here's a quick sketch:
import scalaz._, Scalaz._
trait Validator[E] {
def checkNonEmpty(error: E)(s: String): ValidationNel[E, String] =
if (s.isEmpty) error.failNel else s.successNel
}
sealed trait UserCreationFailure
case object EmptyPassword extends UserCreationFailure
case object EmptyUsername extends UserCreationFailure
case class User(name: String, pass: String)
object User extends Validator[UserCreationFailure] {
def validated(
name: String,
pass: String
): ValidationNel[UserCreationFailure, User] = (
checkNonEmpty(EmptyUsername)(name) |#| checkNonEmpty(EmptyPassword)(pass)
)(apply)
}
And then:
scala> println(User.validated("", ""))
Failure(NonEmptyList(EmptyUsername, EmptyPassword))
scala> println(User.validated("a", ""))
Failure(NonEmptyList(EmptyPassword))
scala> println(User.validated("", "b"))
Failure(NonEmptyList(EmptyUsername))
scala> println(User.validated("a", "b"))
Success(User(a,b))
If you have a huge amount of User-specific validation logic that you don't want polluting your User object, I suppose you could factor it out into a UserValidator trait that would extend your generic Validator and be extended by User.
Related
I just want to print name of every user stored in database.
I am using this repository:
#Repository
interface User: JpaSpecificationExecutor<User>, PagingAndSortingRepository<User, Long> {
#Query("from User")
fun findAllUsers(): Stream<User>
}
inside this Service:
#Service
class MyService(val user: User) {
private val log = LoggerFactory.getLogger(javaClass)
#Transactional(readOnly = true)
fun printNames() {
log.info("here")
user.findAllUsers().use { users ->
users.map { it.firstName }
}
}
}
and it prints only here in console, but no name.
It seems like map() automatically closed the stream but I don`t know why and how to workaround it. When I put inside of use{} block only log.info(users.count()) it prints number of users stored in database. So there is a user I can print.
My question is, how can I print all names from the given stream?
Kotlin's use function is just a short-hand way of executing some code (your closure function) and then call close on the receiver (in this case the Stream) once done.
What you called users is actually the Stream<User>returned by your repository, so basically your code is just calling users.map {...}. Now, the map operator is an intermediate operator, and since Java streams are lazy, they won't actually do anything until you call a terminal operator (such as .collect or .forEach).
Assuming you want to print the user, try with:
user.findAllUsers().use {
it.forEach { println(it.firstName) }
}
Full working example (without Spring data):
import java.util.stream.Stream
// simulate a repository
fun findAllUsers() = Stream.of("First", "Second", "Third")
fun printNames() {
findAllUsers().use {
it.forEach(::println)
}
}
fun main() {
printNames()
}
Prints:
First
Second
Third
I have custom scalars for my users ID, CustomerID and ProviderID, I would like to validate them when someone call a mutation to ensure that the given ID match a user and of correct type.
We cannot make CustomerScalar parseValue method asynchronous, so I'm looking for a nice way to deal with such things.
Maybe customerDecorator ? I don't know ? Any idea ?
I would like to access my repository using Dependencies Injection to ensure that the passed ID exists in the database and is really a Customer.
Field Middleware and Directive seems not to support Deps injection.
#InputType()
export class CreateBillInput {
#Field(() => CustomerIDScalar)
customerID: CustomerID;
#Field()
name: string;
#Field(() => Int)
amount: number;
}
What I wanted that cannot work :
#Injectable()
export class CustomerIDScalar implements CustomScalar<string, CustomerID> {
constructor(private userRepository: IUserRepository) {}
parseValue(value: string) {
return this.getCustomerID(value);
}
parseLiteral(ast: ValueNode) {
if (ast.kind !== Kind.STRING) {
throw new TypeError('Argument is not a string value.');
}
return this.getCustomerID(value);;
}
serialize(value: CustomerID) {
return value.value; // value sent to the client
}
// TODO: Not usable here
private async getCustomerID(userID: string): Promise<CustomerID> {
const user = await this.userRepository.getByID(userID);
if (!user || !user.isCustomer()) {
throw new BadRequestException('There is no such customer user for provided ID.');
}
return user.id as CustomerID;
}
}
Thanks
First of all. gql scalars validation are about technical check to validate all data are correct (schema check). It's not suppose to have any business rules validation stuff there.
To achieve desired result you can use the next things:
Nest validation pipes with #Args decorator:
#Mutation(returns => Group)
async createGroup(
#Args('group', new ValidationPipe())
input: CreateGroupInput,
)
class-validation https://github.com/typestack/class-validator
Simply put a regular ID/Int scalar for the input type & validate it later in service class that responsive for such operation (recommend to use this approach for such things in gql)
The problem's pretty straightforward. I have a couple of events that derive from the same interface, and I'd like to deserialize them to their propper super-class.
I know how to do that with an object mapper, but using my own mapper would mean letting Spring-Boot parse the #RequestBody as a String and then doing it myself, which isn't the worlds end, but I can't help but suspect that Spring provides proper tools to handle this kind of situation. Trouble is, I can't seem to find them.
Here's a bit of sample code:
example event:
interface YellowOpsEvent {
val user: String
val partner: String
val subject: String
val change: NatureOfChange
}
data class StatusChangedEvent(override val user: String,
override val partner: String,
override val subject: String,
val before: String,
val after: String): YellowOpsEvent {
override val change = NatureOfChange.Changed
}
controller:
#PostMapping("/event")
fun writeEvent(#RequestBody event: YellowOpsEvent) { // < I expect this not to throw an exception
val bugme = event is StatusChangedEvent // < I expect this to return true if I send the proper event data.
}
Just to clarify, I perfectly understand why this doesn't work out of the box. The trouble is, I can't find out what I need to do to make it work.
The link in pL4Gu33's comment lead me in the right direction, but it took some additional searching and fiddling, plucking information from here and there to arrive at the solution that would finally work, so I'm summarising it here for completeness.
The trouble is that you'll need two annotations, one on the interface and one on the implementing classes, the combined use of which seems somewhat ill-documented.
First, on the interface, add this annotation. Contrary to some tutorials you will find, no further annotation of the interface is required:
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="#class")
interface YellowOpsEvent {
val user: String
val partner: String
val subject: String
val change: NatureOfChange
}
According to some documentation, this alone should be enough for propper deserialisation. The spring-boot controller, however, will throw an exception because the passed root name does not match the class it was expecting.
// the above will throw an exception when the serialization product is sent to this controller:
#PostMapping("/event")
fun writeEvent(#RequestBody event: YellowOpsEvent) { // < I expect this not to throw an exception
val bugme = event is StatusChangedEvent // < I expect this to return true if I send the proper event data.
}
To fix that, add the #JsonRootName annotation to any implementing classes, with the interface's name. Most documentation of this annotation don't use it for this, instead just for renaming the type, and even when it's mentioned in the linked question in the context of polymorphism, it wrongly uses its own name. This is what it needs to look like:
#JsonRootName("YellowOpsEvent")
data class StatusChangedEvent(override val user: String,
override val partner: String,
override val subject: String,
val before: String,
val after: String): YellowOpsEvent {
override val change = NatureOfChange.Changed
}
Now it works! :)
I've found some limitations in Play Faramework default Validation.
My biggest limitation is uniqueness validation.
Let say I'm Validating user registration form and i want to check if passed login already exists.
To do so, i need to ask db to count users by name
UsersService.countByName(s: String): Future[Long]
Is there a posiblity to solve this problem using scalaz Validation and |#|?
case class RegistrationForm(login: String)
object RegistrationForm {
def nonEmptyLogin(login: String): ValidationNel[String, String] = {
if(login.isEmpty)
"validation.error.blank.login".failureNel
else
login.successNel
}
def isLoginUnique(login: String): Future[ValidationNel[String, String]] = {
???
}
def validate(registrationForm: RegistrationForm): Future[ValidationNel[String, RegistrationForm]] = {
nonEmptyLogin(registrationForm.login) |#|
isLoginUnique(registrationForm.login) {
(_) => registrationForm
}
}
}
How should I implement the isLoginUnique method?
I'm not sure if I wrote validdate method correctly either. I just wanted to show my vision of validation.
I have the following method:
#org.springframework.stereotype.Service
class EntityCacheManager {
def get(cacheId: String, entityClass: Class[_]): AnyRef = { ... }
//...
}
So to use it, i have to write this:
val cachedEntity = entityCacheManager.get(cacheId, classOf[SomeEntity]).asInstanceOf[SomeEntity]
Is there some way to make EntityCacheManager.get() returning instance of type entityClass which is specified in method params? I'd like to avoid casting asInstanceOf every time i use this method. I know it would be nice to use generic definition of type EntityCacheManager, but it's also a spring-managed bean, so i think using generics will cause troubles.
You can use a more idiomatic scala approach by using the ClassTag typeclass
class EntityCacheManager {
def get[T: ClassTag](cacheId: String): T = {
val entityClass = implicitly[ClassTag[T]].runtimeClass
val myObject: T = ??? // you retrieve your object somehow using entityClass
myObject
}
}
you can now use it like this:
val myEntityClassInstance = get[MyEntityClass]("key")