Skip to content

Commit ab2e556

Browse files
authored
Merge pull request #285 from navikt/kodeverk-integrasjon
Kodeverk integrasjon og navn i PDL respons
2 parents 85e178e + ed8fdbb commit ab2e556

File tree

19 files changed

+933
-28
lines changed

19 files changed

+933
-28
lines changed

.nais/dev.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ spec:
6363
namespace: teamsykefravr
6464
- application: logging
6565
namespace: nais-system
66+
- application: kodeverk-api
67+
namespace: team-rocket
6668
inbound:
6769
rules:
6870
- application: rpa-medlemskap-og-avgift

.nais/prod.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ spec:
6363
namespace: teamsykefravr
6464
- application: logging
6565
namespace: nais-system
66+
- application: kodeverk-api
67+
namespace: team-rocket
6668
inbound:
6769
rules:
6870
- application: rpa-medlemskap-og-avgift

build.gradle.kts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ plugins {
2424
id("org.jetbrains.kotlin.plugin.serialization") version "2.2.10"
2525
id("com.gradleup.shadow") version "8.3.8"
2626
id("com.expediagroup.graphql") version "8.8.1"
27+
id("org.openapi.generator") version "7.15.0"
2728
}
2829

2930
group = "no.nav"
@@ -161,8 +162,40 @@ val generatePDLClient by tasks.creating(GraphQLGenerateClientTask::class) {
161162
dependsOn("downloadPDLSchema")
162163
}
163164

165+
val generatedSourcesPath = "$buildDir/generated/source/openapi"
166+
167+
openApiGenerate {
168+
inputSpec.set("${project.projectDir}/src/main/resources/kodeverk/openapi.json")
169+
outputDir.set(generatedSourcesPath)
170+
generatorName.set("kotlin")
171+
packageName.set("no.nav.api.generated.kodeverk")
172+
configOptions.set(
173+
mapOf(
174+
"library" to "jvm-ktor",
175+
"serializationLibrary" to "kotlinx_serialization",
176+
"dateLibrary" to "kotlinx-datetime",
177+
),
178+
)
179+
}
180+
164181
tasks {
182+
register("generateApi") {
183+
group = "build"
184+
description = "Generate API"
185+
dependsOn("openApiGenerate")
186+
}
165187
processResources {
166-
dependsOn("generatePDLClient")
188+
dependsOn("generateApi", "generatePDLClient")
189+
}
190+
compileKotlin {
191+
dependsOn("generateApi")
192+
}
193+
}
194+
195+
sourceSets {
196+
main {
197+
kotlin {
198+
srcDir("$generatedSourcesPath/src/main/kotlin/")
199+
}
167200
}
168201
}

src/main/kotlin/no/nav/Consumers.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package no.nav
33
import no.nav.api.dialog.saf.SafClient
44
import no.nav.api.dialog.sf.SFClient
55
import no.nav.api.digdir.DigdirClient
6+
import no.nav.api.kodeverk.KodeverkClient
67
import no.nav.api.kontonummer.KontonummerRegister
78
import no.nav.api.oppfolging.Nom
89
import no.nav.api.oppfolging.OppfolgingClient
@@ -29,6 +30,7 @@ interface Consumers {
2930
val kontonummerRegister: KontonummerRegister
3031
val utbetalingerClient: UtbetalingerClient
3132
val sfClient: SFClient
33+
val kodeverkClient: KodeverkClient
3234
}
3335

3436
class ConsumersImpl(
@@ -49,6 +51,7 @@ class ConsumersImpl(
4951
override val oppfolgingClient: OppfolgingClient = OppfolgingClient(env.oppfolgingUrl, oboTokenClient.bindTo(env.oppfolgingScope))
5052
override val syfoClient: SyfoClient = SyfoClient(env.syfoUrl, oboTokenClient.bindTo(env.syfoScope))
5153
override val nom: NomClient = Nom(env.nomUrl, tokenclient.bindTo(env.nomScope)).client
54+
override val kodeverkClient: KodeverkClient = KodeverkClient(env.kodeverkUrl, tokenclient.bindTo(env.kodeverkScope))
5255
override val skrivestotteClient: SkrivestotteClient = SkrivestotteClient(env.skrivestotteUrl)
5356
override val pdlClient: PdlClient = PdlClient(env.pdlUrl, oboTokenClient.bindTo(env.pdlScope))
5457
override val safClient: SafClient = SafClient(env.safUrl, oboTokenClient.bindTo(env.safScope))

src/main/kotlin/no/nav/Env.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ interface Env {
2929
val skrivestotteUrl: String
3030
val sfUrl: String
3131
val sfScope: DownstreamApi
32+
val kodeverkUrl: String
33+
val kodeverkScope: DownstreamApi
3234
val identAllowList: List<String>
3335
}
3436

@@ -53,6 +55,8 @@ class EnvImpl : Env {
5355
override val skrivestotteUrl: String = getRequiredConfig("SKRIVESTOTTE_URL")
5456
override val sfUrl: String = getRequiredConfig("SF_HENVENDELSE_URL")
5557
override val sfScope: DownstreamApi = getRequiredConfig("SF_HENVENDELSE_SCOPE").toDownstreamApi()
58+
override val kodeverkUrl: String = getRequiredConfig("KODEVERK_URL")
59+
override val kodeverkScope: DownstreamApi = getRequiredConfig("KODEVERK_SCOPE").toDownstreamApi()
5660
override val identAllowList: List<String> = getRequiredConfig("IDENT_ALLOW_LIST").uppercase().split(",")
5761
}
5862

src/main/kotlin/no/nav/Services.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import no.nav.api.dialog.DialogService
44
import no.nav.api.dialog.saf.SafService
55
import no.nav.api.dialog.sf.SFService
66
import no.nav.api.digdir.DigdirService
7+
import no.nav.api.kodeverk.KodeverkService
78
import no.nav.api.oppfolging.OppfolgingService
89
import no.nav.api.pdl.PdlService
910
import no.nav.api.skrivestotte.SkrivestotteService
@@ -20,6 +21,7 @@ interface Services {
2021
val sfService: SFService
2122
val dialogService: DialogService
2223
val utbetalingerService: UtbetalingerService
24+
val kodeverkService: KodeverkService
2325
}
2426

2527
class ServicesImpl(
@@ -33,7 +35,8 @@ class ServicesImpl(
3335
override val syfoService = SyfoService(consumers.syfoClient, consumers.nom)
3436
override val skrivestotteService = SkrivestotteService(consumers.skrivestotteClient)
3537
override val digdirService = DigdirService(consumers.digdirClient)
36-
override val pdlService = PdlService(consumers.pdlClient)
38+
override val kodeverkService = KodeverkService(consumers.kodeverkClient)
39+
override val pdlService = PdlService(consumers.pdlClient, kodeverkService)
3740
override val safService = SafService(consumers.safClient)
3841
override val sfService = SFService(consumers.sfClient)
3942
override val dialogService = DialogService(safService, sfService, pdlService)
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
2+
package no.nav.api.kodeverk
3+
import io.ktor.client.engine.HttpClientEngine
4+
import io.ktor.client.engine.okhttp.*
5+
import no.nav.api.generated.kodeverk.apis.KodeverkApi
6+
import no.nav.api.generated.kodeverk.models.GetKodeverkKoderBetydningerResponse
7+
import no.nav.utils.*
8+
9+
class KodeverkClient(
10+
kodeverkUrl: String,
11+
private val tokenClient: BoundedMachineToMachineTokenClient,
12+
httpEngine: HttpClientEngine =
13+
OkHttp.create {
14+
addInterceptor(XCorrelationIdInterceptor())
15+
addInterceptor(
16+
LoggingInterceptor(
17+
name = "kodeverk",
18+
callIdExtractor = { getCallId() },
19+
),
20+
)
21+
addInterceptor(
22+
HeadersInterceptor {
23+
mapOf(
24+
"Nav-Consumer-Id" to navConsumerId,
25+
)
26+
},
27+
)
28+
addInterceptor(
29+
AuthorizationInterceptor {
30+
tokenClient.createMachineToMachineToken()
31+
},
32+
)
33+
},
34+
) {
35+
private val api =
36+
KodeverkApi(kodeverkUrl, httpEngine) { config ->
37+
config.installContentNegotiationAndIgnoreUnknownKeys()
38+
}
39+
40+
suspend fun hentKodeverkRaw(navn: String): GetKodeverkKoderBetydningerResponse =
41+
externalServiceCall {
42+
val response =
43+
api.betydningUsingGET(
44+
navCallId = getCallId(),
45+
navConsumerId = "modia-robot-api",
46+
kodeverksnavn = navn,
47+
spraak = listOf("nb"),
48+
ekskluderUgyldige = null,
49+
oppslagsdato = null,
50+
)
51+
when (response.success) {
52+
true -> response.body()
53+
else -> error("Feil ved henting av kodeverk: ${response.status}")
54+
}
55+
}
56+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package no.nav.api.kodeverk
2+
3+
import kotlinx.coroutines.runBlocking
4+
import no.nav.api.generated.kodeverk.models.GetKodeverkKoderBetydningerResponse
5+
import no.nav.personoversikt.common.utils.Retry
6+
import no.nav.personoversikt.common.utils.SelftestGenerator
7+
import kotlin.collections.set
8+
import kotlin.concurrent.fixedRateTimer
9+
import kotlin.time.Duration.Companion.hours
10+
import kotlin.time.Duration.Companion.seconds
11+
12+
enum class KodeverkNavn(
13+
val kodeverkString: String,
14+
) {
15+
LAND("Landkoder"),
16+
POSTNUMMER("Postnummer"),
17+
}
18+
19+
class KodeverkService(
20+
private val kodeverkClient: KodeverkClient,
21+
) {
22+
private var kodeverkCache: MutableMap<KodeverkNavn, Map<String, String>> = mutableMapOf()
23+
private val emptyKodeverk: Map<String, String> = emptyMap()
24+
private val reporter = SelftestGenerator.Reporter(name = "KodeverkService", critical = false)
25+
private val retry =
26+
Retry(
27+
Retry.Config(
28+
initDelay = 30.seconds,
29+
growthFactor = 2.0,
30+
delayLimit = 1.hours,
31+
),
32+
)
33+
34+
init {
35+
fixedRateTimer(
36+
name = "Prepopuler cache kodeverk",
37+
daemon = true,
38+
period = 1.hours.inWholeMilliseconds,
39+
initialDelay = 0,
40+
) {
41+
runBlocking {
42+
reporter.ping {
43+
prepopulerCache()
44+
}
45+
}
46+
}
47+
}
48+
49+
private fun hentKodeverk(navn: KodeverkNavn): Map<String, String> = (kodeverkCache[navn] ?: emptyKodeverk)
50+
51+
internal fun parseTilKodeverk(respons: GetKodeverkKoderBetydningerResponse): Map<String, String> {
52+
val res =
53+
respons.betydninger.mapValues { entry ->
54+
entry.value
55+
.first()
56+
.beskrivelser["nb"]
57+
?.term ?: entry.key
58+
}
59+
return res
60+
}
61+
62+
fun hentKodeBeskrivelse(
63+
kodeverkNavn: KodeverkNavn,
64+
kodeRef: String,
65+
default: String,
66+
): String {
67+
val kodeverk = this.hentKodeverk(kodeverkNavn)
68+
val beskrivelse = kodeverk[kodeRef]
69+
if (beskrivelse == null) {
70+
return default
71+
}
72+
return beskrivelse
73+
}
74+
75+
internal fun prepopulerCache() {
76+
KodeverkNavn.entries.forEach { navn ->
77+
runBlocking {
78+
retry.run {
79+
kodeverkCache[navn] = parseTilKodeverk(kodeverkClient.hentKodeverkRaw(navn.kodeverkString))
80+
}
81+
}
82+
}
83+
}
84+
}

src/main/kotlin/no/nav/api/pdl/PdlRoutes.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package no.nav.api.pdl
33
import io.bkbn.kompendium.core.metadata.PostInfo
44
import io.bkbn.kompendium.core.plugin.NotarizedRoute
55
import io.ktor.http.*
6-
import io.ktor.server.application.*
76
import io.ktor.server.response.*
87
import io.ktor.server.routing.*
98
import kotlinx.serialization.Serializable
109
import no.nav.api.CommonModels
10+
import no.nav.api.generated.pdl.hentpersonalia.Navn
1111
import no.nav.models.FnrRequest
1212
import no.nav.models.deserializeFnr
1313
import no.nav.utils.getJWT
@@ -77,6 +77,7 @@ data class AktorIdResponse(
7777

7878
@Serializable
7979
data class PdlPersonalia(
80+
val navn: Navn? = null,
8081
val alder: Int? = null,
8182
val bostedsAdresse: PdlAdresse? = null,
8283
val kontaktAdresse: PdlAdresse? = null,

0 commit comments

Comments
 (0)