Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PI-2469: Added reference data endpoint #476

Merged
merged 2 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ dependencies {
testImplementation("org.wiremock:wiremock-standalone:3.2.0")
testImplementation("io.kotest.extensions:kotest-extensions-spring:1.1.3")
testImplementation("org.mockito:mockito-core:5.7.0")
testImplementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.17.2")

annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")
}
Expand Down
1 change: 0 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,3 @@
#
# To stop the dps-gradle-spring-boot project from overwriting any project specific customisations here, remove the
# warning at the top of this file.
kotlin.incremental.useClasspathSnapshot=false
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.controllers.v1

import ReferenceData
import io.swagger.v3.oas.annotations.Hidden
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.media.ExampleObject
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.config.AuthorisationConfig
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.services.ReferenceDataService

@Hidden
@RestController
@EnableConfigurationProperties(AuthorisationConfig::class)
@RequestMapping("/v1/hmpps/reference-data")
class ReferenceDataController(
var referenceDataService: ReferenceDataService,
) {
@GetMapping
@Operation(
summary = """
Returns probation and prison reference data.
> Prison Reference Data Types: PHONE_TYPE, ALERT_TYPE, ETHNICITY, GENDER
> Probation Reference Data Types: PHONE_TYPE, REGISTER_TYPE, ETHNICITY, GENDER
""",
responses = [
ApiResponse(
responseCode = "200",
description = "Successfully returned prison and probation reference data.",
content = [
Content(
schema = Schema(implementation = Response::class),
examples = [
ExampleObject(
"""{
"data": {
"prisonReferenceData": {
"PHONE_TYPE": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
],
"ALERT_TYPE": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
],
"ETHNICITY": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
],
"GENDER": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
]
},
"probationReferenceData": {
"PHONE_TYPE": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
],
"REGISTER_TYPE": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
],
"ETHNICITY": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
],
"GENDER": [
{
"code": "a",
"description": "desc_a"
},
{
"code": "b",
"description": "desc_b"
},
{
"code": "c",
"description": "desc_c"
}
]
},
"errors": []
}""",
),
],
),
],
),
ApiResponse(responseCode = "500", content = [Content(schema = Schema(ref = "#/components/schemas/InternalServerError"))]),
],
)
fun getReferenceData(): Response<ReferenceData?> {
return referenceDataService.referenceData()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import org.springframework.web.reactive.function.BodyInserters
import org.springframework.web.reactive.function.client.ExchangeStrategies
import org.springframework.web.reactive.function.client.WebClient
import org.springframework.web.reactive.function.client.WebClientResponseException
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApiError

Expand Down Expand Up @@ -112,3 +113,11 @@ class WebClientWrapper(
)
}
}

inline fun <reified T> WebClientWrapper.WebClientWrapperResponse<T>.getOrError(error: (errors: List<UpstreamApiError>) -> Response<Any?>): T {
if (this is WebClientWrapper.WebClientWrapperResponse.Error) {
error(this.errors)
}
val success = this as WebClientWrapper.WebClientWrapperResponse.Success
return success.data
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
data class ReferenceData(
val prisonReferenceData: Map<String, List<ReferenceDataItem>>?,
val probationReferenceData: Map<String, List<ReferenceDataItem>>?,
)

data class ReferenceDataItem(
val code: String,
val description: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package uk.gov.justice.digital.hmpps.hmppsintegrationapi.services

import ReferenceData
import ReferenceDataItem
import org.springframework.beans.factory.annotation.Value
import org.springframework.http.HttpMethod
import org.springframework.stereotype.Service
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.WebClientWrapper
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.extensions.getOrError
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.gateways.HmppsAuthGateway
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.Response
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.hmpps.UpstreamApi
import uk.gov.justice.digital.hmpps.hmppsintegrationapi.models.nomis.NomisReferenceCode

@Service
class ReferenceDataService(
@Value("\${services.ndelius.base-url}") deliusBaseUrl: String,
@Value("\${services.prison-api.base-url}") prisonBaseUrl: String,
private val hmppsAuthGateway: HmppsAuthGateway,
) {
private val deliusWebClient = WebClientWrapper(deliusBaseUrl)
private val prisonApiWebclient = WebClientWrapper(prisonBaseUrl)

fun referenceData(): Response<ReferenceData?> {
val probationReferenceData =
deliusWebClient.request<ReferenceData>(
HttpMethod.GET,
"/reference-data",
authHeader(),
UpstreamApi.NDELIUS,
).getOrError { (errors) -> return Response(null, errors = listOf(errors)) }.probationReferenceData

val prisonReferenceData =
NomisReferenceDataType.entries.flatMap {
val rd = prisonReferenceData(it.name)
if (rd.errors.isNotEmpty()) {
return Response(data = null, errors = rd.errors)
}
rd.data!!
}.groupByTo(LinkedHashMap(), { NomisReferenceDataType.valueOf(it.domain!!).category }, { ReferenceDataItem(it.code!!, it.description!!) })

return Response(data = ReferenceData(prisonReferenceData, probationReferenceData))
}

private fun prisonReferenceData(domain: String): Response<List<NomisReferenceCode>?> {
val prisonReferenceData =
prisonApiWebclient.requestList<NomisReferenceCode>(
HttpMethod.GET,
"/api/reference-domains/domains/$domain",
prisonAuthHeader(),
UpstreamApi.NOMIS,
).getOrError { (errors) -> return Response(null, errors = listOf(errors)) }
return Response(data = prisonReferenceData)
}

private fun authHeader(): Map<String, String> {
val token = hmppsAuthGateway.getClientToken("nDelius")
return mapOf(
"Authorization" to "Bearer $token",
)
}

private fun prisonAuthHeader(): Map<String, String> {
val token = hmppsAuthGateway.getClientToken("NOMIS")
val version = "1.0"

return mapOf(
"Authorization" to "Bearer $token",
"version" to version,
"Page-Limit" to Int.MAX_VALUE.toString(),
)
}
}

enum class NomisReferenceDataType(val category: String) {
PHONE_USAGE("PHONE_TYPE"),
ALERT("ALERT_TYPE"),
ETHNICITY("ETHNICITY"),
SEX("GENDER"),
}
3 changes: 3 additions & 0 deletions src/main/resources/application-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ authorisation:
- "/v1/persons/.*/risks/categories"
- "/v1/persons/.*/person-responsible-officer"
- "/v1/persons/.*/risk-management-plan"
- "/v1/hmpps/reference-data"
ctrlo:
- "/v1/epf/person-details/.*/[^/]*$"
moj-pes:
Expand All @@ -72,6 +73,7 @@ authorisation:
- "/v1/persons/.*/licences/conditions"
- "/v1/persons/.*/person-responsible-officer"
- "/v1/persons/.*/status-information"
- "/v1/hmpps/reference-data"
event-service:
- "/v1/config/authorisation"
mryall:
Expand All @@ -87,3 +89,4 @@ authorisation:
- "/v1/persons/.*/licences/conditions"
- "/v1/persons/.*/person-responsible-officer"
- "/v1/persons/.*/status-information"
- "/v1/hmpps/reference-data"
1 change: 1 addition & 0 deletions src/main/resources/application-local.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ authorisation:
- "/health/readiness"
- "/health/liveness"
- "/info"
- "/v1/hmpps/reference-data"
config-test:
- "/v1/config/authorisation"
all-access:
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application-preprod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ authorisation:
- "/v1/persons/.*/name"
- "/v1/hmpps-id/nomis-number/[^/]*$"
- "/v1/persons/.*/cell-location"
- "/v1/hmpps/reference-data"
kubernetes-health-check-client:
- "/health/liveness"
- "/health/readiness"
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ authorisation:
- "/v1/persons/.*/name"
- "/v1/hmpps-id/nomis-number/[^/]*$"
- "/v1/persons/.*/cell-location"
- "/v1/hmpps/reference-data"
kubernetes-health-check-client:
- "/health/liveness"
- "/health/readiness"
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/application-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,6 @@ authorisation:
- "/health/readiness"
- "/health/liveness"
- "/info"
- "/v1/hmpps/reference-data"
config-test:
- "/v1/config/authorisation"
Loading