Last active
March 4, 2023 22:39
-
-
Save emadb/d2a0337faa0cfc942317e5a32fc103f2 to your computer and use it in GitHub Desktop.
Validation and domain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Controller HTTP | |
public class Controller | |
{ | |
public UserResponse Post(UserRequest req) | |
{ | |
User user = createUserValidator.Validate(req); | |
// Fino a qui sono nel contesto HTTP | |
// Qui entro nel dominio. Forse sarebbe meglio usare un gateway per accedere al dominio | |
// ma dipende dal tipo di applicazione. | |
user.Create(); | |
// Qui torno nel contesto HTTP | |
return CreateUserResponse(user); | |
} | |
} | |
// Valiratore dell'operazione di creazione di un utente (sono ancora nel contesto HTTP) | |
public class CreateUserValidator | |
{ | |
private IUserRepository repo; | |
public CreateUserValidator(IUserRepository repo) | |
{ | |
this.repo = repo; | |
} | |
public User Validate(UserRequest req) | |
{ | |
if (String.IsNullOrEmpty(req.Email) | |
{ | |
throw MissingEmailException(); | |
} | |
// Potrei verificare anche se l'email è univoca | |
IList<Roles> roles = req.Roles.Select(r => repo.GetRole(r)); | |
if (roles.Some(r => r == RoleNotFound.Value)) | |
{ | |
throw MissingRoleException(); | |
} | |
return UserFactory.create(req.email, roles); | |
} | |
} | |
// DM: classe di dominio | |
public class User : AggregateRoot | |
{ | |
public User(/*varie dipendenze: repo, serivizi, ecc...*/) | |
{} | |
public User Create(User user) | |
{ | |
// Fai qualcosa con l'utente: | |
// - schedula l'invio di una mail tramite apposito servizio | |
// - fa qualcos'altro | |
return this.userRepository.save(user); | |
} | |
} |
Ad essere pignoli, sarebbe dovuto essere /users/id, in quanto nel mio esempio l'id e' noto a priori
class EmaDB
{
class Controller : ASP.ControllerBase
{
private Context _db;
[ASP.HttpPost]
public ASP.IActionResult CreateUser(ApiUser apiUser)
{
return DbUser
.WithEmail(apiUser.Email)
.ForAll(apiUser.Roles, LoadRole)
.Match<ASP.IActionResult>(u =>
{
_db.Users.Add(u);
_db.SaveChanges();
return NoContent();
},
() => BadRequest("Roles not found"));
}
Option<Role> LoadRole(ApiRole apiRole) =>
_db.Roles.SingleOrDefault(r => r.Name == apiRole.Name);
}
}
static class UserExtensions
{
internal static Option<DbUser> ForAll(this DbUser dbUser, IEnumerable<ApiRole> roles, Func<ApiRole, Option<Role>> loadRole) =>
roles.Select(loadRole).Sequence().Select(roles => dbUser with { Roles = roles.ToArray() });
}
internal record ApiUser(String Email, IEnumerable<ApiRole> Roles);
internal record ApiRole(String Name);
internal record DbUser(String Email, IEnumerable<Role> Roles = null)
{
public static DbUser WithEmail(string email) => new(Email: email);
}
internal record Role(Guid Id, String Name);
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
For sake of simplicity, I didn't introduce any interface