The document describes a sign in service that validates a client, authenticates a user, and issues an access token. It defines a SignInService class that takes functions for validating clients, authenticating users, and creating access tokens. The signIn method uses these functions in a for comprehension to validate the client, authenticate the user, and create an access token, returning a Future[AccessToken]. It also shows refactoring the service to take functions instead of dependencies and moving the signIn method to a static object.
21. class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
22. class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
23. class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
24. class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
25. class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
EL
26. class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
27. "returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
28. "returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
29. "returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
30. "returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
31. "returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
32. "returns client if credentials match" in new Scope {
val jsonClient = mock[JsonClient]
val clientService = new ClientService(jsonClient)
val jsonResponse = JsonResponse(OkStatus,Json.fromString(...))
when(jsonClient.get(Path() / "clients" / "clientId")
.thenReturn(Future.value(jsonResponse))
clientService.validateClient("clientId", "secret")
==== Client(5)
}
B
34. class ClientService(jsonClient: JsonClient) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
jsonClient.getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
35. class ClientService(getJson: (Path) => Future[JsonResponse]) {
def validateClient(clientId: String, clientSecret: String):
Future[Client]={
getJson(
Path() / "clients" / clientId
).map {
case JsonResponse(OkStatus, json, _, _) => {
val id = (json "id").as[Long]
val secret = (json "secret").as[String]
if (secret != clientSecret) {
throw new Exception("Client doesn't match")
}
Client(id)
:I
36. val jsonClient = JsonClient(host)
val clientService = new ClientService(jsonClient.getJson)
37. val jsonClient = JsonClient(host)
val clientService = new ClientService(jsonClient.getJson)
38. "returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
39. "returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
40. "returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
41. "returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
42. "returns client if credentials match" in new Scope {
val jsonResponse = JsonResponse(OkStatus, Json.fromString(...)
val clientService = new ClientService(_ => Future.value(jsonResponse))
clientService.validateClient("clientId", "secret") ==== Client(5)
}
!E
65. object SignInApi extends FinagleBasedServer with AppConfigComponent{
val clientsJsonClient = JsonClient(host)
val tokensClient = JsonClient(host)
val dbClient = MySqlClient(dbconfig)
val passwordsRepo = new PasswordRepository(dbClient.prepare, dbClient.execute)
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword)
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
val signInHandler = new SignInHandler(signInService.signIn)
override def createRoutes(httpServer: HttpServer): Unit = {
httpServer.register("/sign-in", signInHandler)
}
}
MSEV
66. trait JsonClients {
self: ConfigComponent =>
val clientsJsonClient = JsonClient(config.clientsHost)
val tokensClient = JsonClient(config.tokensHost)
}
67. trait Repositories {
self: ConfigComponent =>
val dbClient = MySqlClient(config.dbHost, config.dbName, ...)
val passwordsRepo = new PasswordRepository(dbClient.prepare,
dbClient.execute)
}
68. trait Repositories {
self: ConfigComponent =>
val dbClient = MySqlClient(config.dbHost, config.dbName, ...)
val passwordRepo = new PasswordRepository(dbClient.prepare,
dbClient.execute)
}
69. trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
70. trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
71. trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
72. trait Services extends JsonClients with Repositories {
self: ConfigComponent =>
val clientService = new ClientService(clientsJsonClient.get)
val authenticatorService = new AuthentictorService(passwordsRepo.getPassword
val tokenService = new TokenService(tokensClient.get)
val signInService = new SignInService(
clientService.validateClient,
authenticatorService.authenticateUser,
tokenService.createAccessToken
)
}
73. object ExampleSignInApi extends FinagleBasedServer
with ConfigComponent
with Services{
val signInHandler = new SignInHandler(signInService.signIn)
override def createRoutes(httpServer: HttpServer): Unit = {
httpServer.register("/sign-in", signInHandler)
}
}
S
74. object ExampleSignInApi extends FinagleBasedServer
with ConfigComponent
with Services{
val signInHandler = new SignInHandler(signInService.signIn)
override def createRoutes(httpServer: HttpServer): Unit = {
httpServer.register("/sign-in", signInHandler)
}
}
S
81. Manual DI Magic DI
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
82. U
Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
Stop spreading
the news!
83. :L
Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
84. Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
85. Manual DI Magic DI (Framework)
● Requires discipline
● Static check
● No framework or fancy
language features to learn
● Boring
● Enforces consistency
● Runtime check?
● Problems can be hare-y
● Slick
:M