Skip to content

Commit

Permalink
refactor: split api configuration from api route definition
Browse files Browse the repository at this point in the history
  • Loading branch information
AndreaGiulianelli committed Mar 7, 2023
1 parent ec9fb4f commit 1421cf8
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 162 deletions.
164 changes: 2 additions & 162 deletions src/main/kotlin/infrastructure/api/APIController.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,16 @@

package infrastructure.api

import application.controller.MedicalTechnologyController
import application.controller.RoomController
import application.presenter.api.deserializer.ApiDeserializer.toMedicalTechnology
import application.presenter.api.deserializer.ApiDeserializer.toRoom
import application.presenter.api.model.MedicalTechnologyApiDto
import application.presenter.api.model.MedicalTechnologyPatch
import application.presenter.api.model.RoomApiDto
import application.presenter.api.serializer.ApiSerializer.toMedicalTechnologyApiDto
import application.presenter.api.serializer.ApiSerializer.toRoomApiDto
import application.service.MedicalTechnologyService
import application.service.RoomService
import entity.medicaltechnology.MedicalTechnologyID
import entity.zone.RoomID
import infrastructure.api.util.ApiResponses
import infrastructure.provider.ManagerProvider
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.application.install
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import io.ktor.server.plugins.contentnegotiation.ContentNegotiation
import io.ktor.server.plugins.statuspages.StatusPages
import io.ktor.server.request.receive
import io.ktor.server.response.header
import io.ktor.server.response.respond
import io.ktor.server.response.respondText
import io.ktor.server.routing.delete
import io.ktor.server.routing.get
import io.ktor.server.routing.patch
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import java.time.Instant
import java.time.format.DateTimeParseException

/**
Expand All @@ -63,8 +38,8 @@ class APIController(private val provider: ManagerProvider) {

private fun dispatcher(app: Application) {
with(app) {
roomAPI(this)
medicalTechnologyAPI(this)
roomAPI(apiPath, port, provider)
medicalTechnologyAPI(apiPath, port, provider)
}
}

Expand All @@ -81,141 +56,6 @@ class APIController(private val provider: ManagerProvider) {
}
}

/**
* The Room API available to handle room requests.
* @param[app] it represents the running ktor web application
*/
private fun roomAPI(app: Application) {
with(app) {
routing {
post("$apiPath/rooms") {
val room = call.receive<RoomApiDto>().toRoom()
RoomService.CreateRoom(
room,
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager)
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.Conflict)
else -> {
call.response.header(
HttpHeaders.Location,
"http://localhost:$port$apiPath/rooms/${room.id.value}"
)
call.respond(HttpStatusCode.Created)
}
}
}
}
get("$apiPath/rooms") {
val entries = RoomService.GetAllRoomEntry(
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager)
).execute().map { entry ->
ApiResponses.ResponseEntry(entry, "http://localhost:$port$apiPath/rooms/${entry.id}")
}
call.response.status(if (entries.isNotEmpty()) HttpStatusCode.OK else HttpStatusCode.NoContent)
call.respond(ApiResponses.ResponseEntryList(entries))
}
get("$apiPath/rooms/{roomId}") {
RoomService.GetRoom(
RoomID(call.parameters["roomId"].orEmpty()),
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager),
call.request.queryParameters["dateTime"]?.let { rawDateTime -> Instant.parse(rawDateTime) }
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.NotFound)
else -> call.respond(this.toRoomApiDto())
}
}
}
delete("$apiPath/rooms/{roomId}") {
call.respond(
RoomService.DeleteRoom(
RoomID(call.parameters["roomId"].orEmpty()),
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager)
).execute().let { result ->
if (result) HttpStatusCode.NoContent else HttpStatusCode.NotFound
}
)
}
}
}
}

/**
* The Medical Technology API available to handle medical technology requests.
* @param[app] it represents the running ktor web application
*/
private fun medicalTechnologyAPI(app: Application) {
with(app) {
routing {
post("$apiPath/medical-technologies") {
val medicalTechnology = call.receive<MedicalTechnologyApiDto>().toMedicalTechnology()
MedicalTechnologyService.CreateMedicalTechnology(
medicalTechnology,
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
)
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.Conflict)
else -> {
call.response.header(
HttpHeaders.Location,
"http://localhost:$port$apiPath/medical-technologies/${medicalTechnology.id.value}"
)
call.respond(HttpStatusCode.Created)
}
}
}
}
get("$apiPath/medical-technologies/{technologyId}") {
MedicalTechnologyService.GetMedicalTechnology(
MedicalTechnologyID(call.parameters["technologyId"].orEmpty()),
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
),
call.request.queryParameters["dateTime"]?.let { rawDateTime -> Instant.parse(rawDateTime) }
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.NotFound)
else -> call.respond(this.toMedicalTechnologyApiDto())
}
}
}
delete("$apiPath/medical-technologies/{technologyId}") {
call.respond(
MedicalTechnologyService.DeleteMedicalTechnology(
MedicalTechnologyID(call.parameters["technologyId"].orEmpty()),
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
),
).execute().let { result ->
if (result) HttpStatusCode.NoContent else HttpStatusCode.NotFound
}
)
}
patch("$apiPath/medical-technologies/{technologyId}") {
call.respond(
MedicalTechnologyService.MapMedicalTechnologyToRoom(
MedicalTechnologyID(call.parameters["technologyId"].orEmpty()),
call.receive<MedicalTechnologyPatch>().roomId?.let { roomId -> RoomID(roomId.trim()) },
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager),
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
)
).execute().let { result ->
if (result) HttpStatusCode.NoContent else HttpStatusCode.NotFound
}
)
}
}
}
}

companion object {
private const val port = 3000
private const val apiVersion = "v1"
Expand Down
108 changes: 108 additions & 0 deletions src/main/kotlin/infrastructure/api/MedicalTechnologyApi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2023. Smart Operating Block
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

package infrastructure.api

import application.controller.MedicalTechnologyController
import application.controller.RoomController
import application.presenter.api.deserializer.ApiDeserializer.toMedicalTechnology
import application.presenter.api.model.MedicalTechnologyApiDto
import application.presenter.api.model.MedicalTechnologyPatch
import application.presenter.api.serializer.ApiSerializer.toMedicalTechnologyApiDto
import application.service.MedicalTechnologyService
import entity.medicaltechnology.MedicalTechnologyID
import entity.zone.RoomID
import infrastructure.provider.ManagerProvider
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.request.receive
import io.ktor.server.response.header
import io.ktor.server.response.respond
import io.ktor.server.routing.delete
import io.ktor.server.routing.get
import io.ktor.server.routing.patch
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import java.time.Instant

/**
* The Medical Technology API available to handle medical technology requests.
* @param[apiPath] it represents the path to reach the api.
* @param[port] the port where the api are exposed.
* @param[provider] the provider of managers.
*/
fun Application.medicalTechnologyAPI(apiPath: String, port: Int, provider: ManagerProvider) {
routing {
post("$apiPath/medical-technologies") {
val medicalTechnology = call.receive<MedicalTechnologyApiDto>().toMedicalTechnology()
MedicalTechnologyService.CreateMedicalTechnology(
medicalTechnology,
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
)
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.Conflict)
else -> {
call.response.header(
HttpHeaders.Location,
"http://localhost:$port$apiPath/medical-technologies/${medicalTechnology.id.value}"
)
call.respond(HttpStatusCode.Created)
}
}
}
}
get("$apiPath/medical-technologies/{technologyId}") {
MedicalTechnologyService.GetMedicalTechnology(
MedicalTechnologyID(call.parameters["technologyId"].orEmpty()),
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
),
call.request.queryParameters["dateTime"]?.let { rawDateTime -> Instant.parse(rawDateTime) }
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.NotFound)
else -> call.respond(this.toMedicalTechnologyApiDto())
}
}
}
delete("$apiPath/medical-technologies/{technologyId}") {
call.respond(
MedicalTechnologyService.DeleteMedicalTechnology(
MedicalTechnologyID(call.parameters["technologyId"].orEmpty()),
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
),
).execute().let { result ->
if (result) HttpStatusCode.NoContent else HttpStatusCode.NotFound
}
)
}
patch("$apiPath/medical-technologies/{technologyId}") {
call.respond(
MedicalTechnologyService.MapMedicalTechnologyToRoom(
MedicalTechnologyID(call.parameters["technologyId"].orEmpty()),
call.receive<MedicalTechnologyPatch>().roomId?.let { roomId -> RoomID(roomId.trim()) },
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager),
MedicalTechnologyController(
provider.medicalTechnologyDigitalTwinManager,
provider.medicalTechnologyDatabaseManager
)
).execute().let { result ->
if (result) HttpStatusCode.NoContent else HttpStatusCode.NotFound
}
)
}
}
}
90 changes: 90 additions & 0 deletions src/main/kotlin/infrastructure/api/RoomApi.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (c) 2023. Smart Operating Block
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/MIT.
*/

package infrastructure.api

import application.controller.RoomController
import application.presenter.api.deserializer.ApiDeserializer.toRoom
import application.presenter.api.model.RoomApiDto
import application.presenter.api.serializer.ApiSerializer.toRoomApiDto
import application.service.RoomService
import entity.zone.RoomID
import infrastructure.api.util.ApiResponses
import infrastructure.provider.ManagerProvider
import io.ktor.http.HttpHeaders
import io.ktor.http.HttpStatusCode
import io.ktor.server.application.Application
import io.ktor.server.application.call
import io.ktor.server.request.receive
import io.ktor.server.response.header
import io.ktor.server.response.respond
import io.ktor.server.routing.delete
import io.ktor.server.routing.get
import io.ktor.server.routing.post
import io.ktor.server.routing.routing
import java.time.Instant

/**
* The Room API available to handle room requests.
* @param[apiPath] it represents the path to reach the api.
* @param[port] the port where the api are exposed.
* @param[provider] the provider of managers.
*/
fun Application.roomAPI(apiPath: String, port: Int, provider: ManagerProvider) {
routing {
post("$apiPath/rooms") {
val room = call.receive<RoomApiDto>().toRoom()
RoomService.CreateRoom(
room,
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager)
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.Conflict)
else -> {
call.response.header(
HttpHeaders.Location,
"http://localhost:$port$apiPath/rooms/${room.id.value}"
)
call.respond(HttpStatusCode.Created)
}
}
}
}
get("$apiPath/rooms") {
val entries = RoomService.GetAllRoomEntry(
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager)
).execute().map { entry ->
ApiResponses.ResponseEntry(entry, "http://localhost:$port$apiPath/rooms/${entry.id}")
}
call.response.status(if (entries.isNotEmpty()) HttpStatusCode.OK else HttpStatusCode.NoContent)
call.respond(ApiResponses.ResponseEntryList(entries))
}
get("$apiPath/rooms/{roomId}") {
RoomService.GetRoom(
RoomID(call.parameters["roomId"].orEmpty()),
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager),
call.request.queryParameters["dateTime"]?.let { rawDateTime -> Instant.parse(rawDateTime) }
).execute().apply {
when (this) {
null -> call.respond(HttpStatusCode.NotFound)
else -> call.respond(this.toRoomApiDto())
}
}
}
delete("$apiPath/rooms/{roomId}") {
call.respond(
RoomService.DeleteRoom(
RoomID(call.parameters["roomId"].orEmpty()),
RoomController(provider.roomDigitalTwinManager, provider.roomDatabaseManager)
).execute().let { result ->
if (result) HttpStatusCode.NoContent else HttpStatusCode.NotFound
}
)
}
}
}

0 comments on commit 1421cf8

Please sign in to comment.