Skip to content

Commit 6d839f3

Browse files
jaflatenkarl-run
andcommitted
chore: wip updating types for fetch api response
Co-authored-by: Karl O <[email protected]>
1 parent 7634f55 commit 6d839f3

File tree

12 files changed

+126
-48
lines changed

12 files changed

+126
-48
lines changed

src/app/(fhir)/fhir/resources/sykmelding/write-to-ehr/route.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,24 @@ export async function POST(request: Request): Promise<Response | DocRefResponseR
1818

1919
const sykmeldingId = request.headers.get('sykmeldingId')
2020
if (sykmeldingId == null) {
21+
logger.error('Missing sykmeldingId header')
2122
return new Response('Missing sykmeldingId header', { status: 400 })
2223
}
2324

2425
const hpr = request.headers.get('HPR')
2526
if (hpr == null) {
27+
logger.error('Missing HPR header')
2628
return new Response('Missing HPR header', { status: 400 })
2729
}
2830

29-
const sykmeldingPdf = await sykInnApiService.getSykmeldingPdf(sykmeldingId, hpr)
30-
if ('errorType' in sykmeldingPdf) {
31+
const sykmeldingPdfArrayBuffer = await sykInnApiService.getSykmeldingPdf(sykmeldingId, hpr)
32+
if ('errorType' in sykmeldingPdfArrayBuffer) {
33+
logger.error(`Failed to retrieve sykmelding pdf ${sykmeldingPdfArrayBuffer.errorType}`)
3134
return new Response('Failed to retrieve sykmelding pdf', { status: 500 })
3235
}
3336

37+
const sykmeldingBase64 = Buffer.from(sykmeldingPdfArrayBuffer).toString('base64')
38+
3439
// check if document reference already exists
3540
const existingDocumentReference = await serverFhirResources.getDocumentReference(sykmeldingId)
3641

@@ -51,7 +56,7 @@ export async function POST(request: Request): Promise<Response | DocRefResponseR
5156
}
5257

5358
// create document reference as it didn't exist
54-
const createdDocRef = await serverFhirResources.createDocumentReference(sykmeldingPdf.dokument, sykmeldingPdf.title)
59+
const createdDocRef = await serverFhirResources.createDocumentReference(sykmeldingBase64, 'Sykmelding for Foo Bar') // TODO title
5560
if ('errorType' in createdDocRef) {
5661
logger.error(`Failed to create DocumentReference: ${JSON.stringify(createdDocRef, null, 2)}`)
5762

Original file line numberDiff line numberDiff line change
@@ -1,34 +1,36 @@
1-
//TODO her skal vi mocke shit for document ref get og post
2-
3-
import { unauthorized } from 'next/navigation'
41
import { logger as pinoLogger } from '@navikt/next-logger'
52

3+
import { cleanPath } from '../../utils'
4+
65
const logger = pinoLogger.child({}, { msgPrefix: '[FHIR-MOCK] ' })
76

8-
export async function GET(request: Request): Promise<Response> {
9-
verifyAuthed(request)
10-
return mockedDocumentReference()
11-
}
7+
export async function GET(req: Request): Promise<Response> {
8+
const url = new URL(req.url)
9+
const fhirPath = cleanPath(url.pathname)
10+
logger.info(`Incoming request: ${req.method} - ${fhirPath}`)
11+
12+
// verifyAuthed(req)
1213

13-
export async function POST(request: Request): Promise<Response> {
14-
verifyAuthed(request)
1514
return mockedDocumentReference()
1615
}
1716

18-
function verifyAuthed(req: Request): void {
19-
if (req.headers.get('Authorization') == null) {
20-
logger.warn('Mock resource was unauthed, 401ing >:(')
21-
unauthorized()
22-
}
23-
}
17+
// function verifyAuthed(req: Request): void {
18+
// if (req.headers.get('Authorization') == null) {
19+
// logger.warn('Mock resource was unauthed, 401ing >:(')
20+
// unauthorized()
21+
// }
22+
// }
2423

2524
function mockedDocumentReference(): Response {
26-
return Response.json({
27-
resourceType: 'DocumentReference',
28-
id: 'aa66036d-b63c-4c5a-b3d5-b1d1f812da8d',
29-
meta: {
30-
versionId: '1',
31-
lastUpdated: '2025-03-04T03:21:36.880-05:00',
25+
return Response.json(
26+
{
27+
resourceType: 'DocumentReference',
28+
id: 'aa66036d-b63c-4c5a-b3d5-b1d1f871337c',
29+
meta: {
30+
versionId: '1',
31+
lastUpdated: '2025-03-04T03:21:36.880-05:00',
32+
},
3233
},
33-
})
34+
{ status: 200 },
35+
)
3436
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { unauthorized } from 'next/navigation'
2+
import { logger as pinoLogger } from '@navikt/next-logger'
3+
4+
import { cleanPath } from '../utils'
5+
6+
const logger = pinoLogger.child({}, { msgPrefix: '[FHIR-MOCK] ' })
7+
8+
export async function POST(req: Request): Promise<Response> {
9+
const url = new URL(req.url)
10+
const fhirPath = cleanPath(url.pathname)
11+
logger.info(`Incoming request: ${req.method} - ${fhirPath}`)
12+
13+
verifyAuthed(req)
14+
15+
if (req.method !== 'POST') {
16+
return new Response('DocumentReference without a specific id parameter only supports POST')
17+
}
18+
19+
return mockedDocumentReference()
20+
}
21+
22+
function verifyAuthed(req: Request): void {
23+
if (req.headers.get('Authorization') == null) {
24+
logger.warn('Mock resource was unauthed, 401ing >:(')
25+
unauthorized()
26+
}
27+
}
28+
29+
function mockedDocumentReference(): Response {
30+
return Response.json(
31+
{
32+
resourceType: 'DocumentReference',
33+
id: 'aa66036d-b63c-4c5a-b3d5-b1d1f80000d',
34+
meta: {
35+
versionId: '1',
36+
lastUpdated: '2025-03-04T03:21:36.880-05:00',
37+
},
38+
},
39+
{ status: 200 },
40+
)
41+
}

src/app/api/mocks/fhir/(resources)/[[...path]]/route.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ async function handler(req: Request): Promise<Response> {
2020

2121
switch (mockIdentifier) {
2222
case 'GET - /Patient/cd09f5d4-55f7-4a24-a25d-a5b65c7a8805': {
23-
verifyAuthed(req)
23+
// verifyAuthed(req)
2424
return Response.json(data.patient['Espen Eksempel'], { status: 200 })
2525
}
2626
case 'GET - /Practitioner/a1f1ed62-066a-4050-90f7-81e8f62eb3c2': {

src/app/api/mocks/fhir/(resources)/data/base64pdf.ts

+1
Large diffs are not rendered by default.

src/data-fetcher/data-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {SubmitSykmeldingFormValues} from "@services/syk-inn-api/SykInnApiSchema";
1+
import { SubmitSykmeldingFormValues } from '@services/syk-inn-api/SykInnApiSchema'
22

33
export type NotAvailable = typeof NotAvailable
44
export const NotAvailable = {

src/fhir/fhir-data/fhir-data-server.ts

-2
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ export const serverFhirResources = {
7474
if (currentSession == null) {
7575
throw new Error('Active session is required')
7676
}
77-
// her kan vi bruke mocken. currentSession er meg sjølv.
78-
// shit , ta med resten av url
7977
const resourcePath = `${currentSession.issuer}/DocumentReference/${sykmeldingId}`
8078
logger.info(`Resource path: ${resourcePath}`)
8179
const documentReferenceResponse = await fetch(resourcePath, {

src/fhir/fhir-data/fhir-data-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export function createFhirDataService(behandler: BehandlerInfo): DataService {
1919
},
2020
mutation: {
2121
sendSykmelding: (sykmelding) => nonFhirResources.sendSykmelding(sykmelding, behandler.hpr),
22-
writeToEhr: (sykmeldingId) => nonFhirResources.writeToEhr(sykmeldingId),
22+
writeToEhr: (sykmeldingId) => nonFhirResources.writeToEhr(sykmeldingId, behandler.hpr),
2323
},
2424
}
2525
}

src/fhir/fhir-data/non-fhir-data.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,12 @@ export const nonFhirResources = {
7070
return NySykmeldingSchema.parse(result)
7171
},
7272

73-
writeToEhr: async (sykmeldingId: string) => {
73+
writeToEhr: async (sykmeldingId: string, hpr: string) => {
7474
const result = await getSecuredResource(`/sykmelding/write-to-ehr`, {
7575
method: 'POST',
7676
headers: {
7777
sykmeldingId: sykmeldingId,
78+
HPR: hpr,
7879
},
7980
})
8081

src/services/api-fetcher.ts

+26-5
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,13 @@ export type ApiFetchErrors<AdditionalErrors extends string = never> = {
2323
errorType: ErrorTypes | AdditionalErrors
2424
}
2525

26-
type FetchInternalAPIOptionsWithSchema<T extends z.ZodType, AdditionalErrors> = {
26+
type NonZodResponses = {
27+
ArrayBuffer: ArrayBuffer
28+
}
29+
30+
type ValidNonZodResponses = keyof NonZodResponses
31+
32+
type FetchInternalAPIOptionsWithSchema<T extends z.ZodType | ValidNonZodResponses, AdditionalErrors> = {
2733
api: keyof typeof internalApis
2834
path: `/${string}`
2935
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD'
@@ -33,7 +39,15 @@ type FetchInternalAPIOptionsWithSchema<T extends z.ZodType, AdditionalErrors> =
3339
onApiError?: (response: Response) => AdditionalErrors | undefined
3440
}
3541

36-
export async function fetchInternalAPI<Schema extends z.ZodType, AdditionalErrors extends string = never>({
42+
export async function fetchInternalAPI<
43+
Schema extends z.ZodType | ValidNonZodResponses,
44+
AdditionalErrors extends string = never,
45+
InferredReturnValue = Schema extends z.ZodType
46+
? z.infer<Schema>
47+
: Schema extends ValidNonZodResponses
48+
? NonZodResponses[Schema]
49+
: never,
50+
>({
3751
api,
3852
path,
3953
headers,
@@ -42,7 +56,7 @@ export async function fetchInternalAPI<Schema extends z.ZodType, AdditionalError
4256
responseSchema,
4357
onApiError,
4458
}: FetchInternalAPIOptionsWithSchema<Schema, AdditionalErrors>): Promise<
45-
z.infer<Schema> | ApiFetchErrors<AdditionalErrors>
59+
InferredReturnValue | ApiFetchErrors<AdditionalErrors>
4660
> {
4761
const apiConfig = internalApis[api]
4862
const scope = `api://dev-gcp.${apiConfig.namespace}.${api}/.default`
@@ -66,9 +80,9 @@ export async function fetchInternalAPI<Schema extends z.ZodType, AdditionalError
6680
})
6781

6882
if (!response.ok) {
69-
const additionalError = onApiError?.(response)
83+
const additionalError: AdditionalErrors | undefined = onApiError?.(response)
7084
if (additionalError) {
71-
return additionalError
85+
return { errorType: additionalError }
7286
}
7387

7488
const responseBody = await getFailedResponseBody(response)
@@ -77,6 +91,13 @@ export async function fetchInternalAPI<Schema extends z.ZodType, AdditionalError
7791
return { errorType: 'API_CALL_FAILED' }
7892
}
7993

94+
const isPdfResponse: boolean = response.headers.get('Content-Type')?.includes('application/pdf') ?? false
95+
if (typeof responseSchema === 'string' && responseSchema === 'ArrayBuffer') {
96+
return (await response.arrayBuffer()) as InferredReturnValue
97+
} else if (isPdfResponse && responseSchema !== 'ArrayBuffer') {
98+
raise(`Got PDF but expected response was not ArrayBuffer, for ${api}${path}, whats up?`)
99+
}
100+
80101
const isJsonResponse: boolean = response.headers.get('Content-Type')?.includes('application/json') ?? false
81102
if (!isJsonResponse) {
82103
raise(

src/services/syk-inn-api/SykInnApiSchema.ts

-6
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,3 @@ export type NySykmelding = z.infer<typeof NySykmeldingSchema>
6262
export const NySykmeldingSchema = z.object({
6363
sykmeldingId: z.string(),
6464
})
65-
66-
export type SykmeldingPdf = z.infer<typeof SykmeldingPdfSchema>
67-
export const SykmeldingPdfSchema = z.object({
68-
dokument: z.string(),
69-
title: z.string(),
70-
})

src/services/syk-inn-api/SykInnApiService.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1+
import { logger } from '@navikt/next-logger'
2+
13
import {
24
ExistingSykmelding,
35
ExistingSykmeldingSchema,
46
NySykmelding,
57
NySykmeldingSchema,
6-
SykmeldingPdf,
7-
SykmeldingPdfSchema,
88
} from '@services/syk-inn-api/SykInnApiSchema'
99
import { ApiFetchErrors, fetchInternalAPI } from '@services/api-fetcher'
10+
import { isE2E, isLocalOrDemo } from '@utils/env'
11+
12+
import { pdf } from '../../app/api/mocks/fhir/(resources)/data/base64pdf'
1013

1114
type NySykmeldingPayload = {
1215
pasientFnr: string
@@ -65,8 +68,19 @@ export const sykInnApiService = {
6568
},
6669
responseSchema: ExistingSykmeldingSchema.array(),
6770
}),
68-
getSykmeldingPdf: async (sykmeldingId: string, hpr: string): Promise<SykmeldingPdf | ApiFetchErrors> =>
69-
fetchInternalAPI({
71+
getSykmeldingPdf: async (sykmeldingId: string, hpr: string): Promise<ArrayBuffer | ApiFetchErrors> => {
72+
if (isLocalOrDemo || isE2E) {
73+
logger.warn('Is in demo, local or e2e, returning mocked sykmelding data')
74+
75+
const response = new Response(Buffer.from(pdf), {
76+
headers: { 'Content-Type': 'application/pdf' },
77+
status: 200,
78+
})
79+
80+
return await response.arrayBuffer()
81+
}
82+
83+
return await fetchInternalAPI({
7084
api: 'syk-inn-api',
7185
path: `/api/v1/sykmelding/${sykmeldingId}/pdf`,
7286
method: 'GET',
@@ -75,6 +89,7 @@ export const sykInnApiService = {
7589
sykmeldingId: sykmeldingId,
7690
HPR: hpr,
7791
},
78-
responseSchema: SykmeldingPdfSchema,
79-
}),
92+
responseSchema: 'ArrayBuffer',
93+
})
94+
},
8095
}

0 commit comments

Comments
 (0)