refactor(SW-188): replace anon or auth procedure with serviceProcedure

This commit is contained in:
Chuma McPhoy
2024-08-13 15:59:07 +02:00
parent a1a0a73e3a
commit ed379202c8
7 changed files with 55 additions and 80 deletions

View File

@@ -16,10 +16,4 @@ export namespace endpoints {
} }
} }
export const getHotelEndpoint = (hotelId: string | number) => export type Endpoint = endpoints.v0 | endpoints.v1
`${endpoints.v1.hotels}/${hotelId}` as const
export type Endpoint =
| endpoints.v0
| endpoints.v1
| ReturnType<typeof getHotelEndpoint>

View File

@@ -9,7 +9,7 @@ import type {
} from "@/types/fetch" } from "@/types/fetch"
import type { Endpoint } from "./endpoints" import type { Endpoint } from "./endpoints"
export { endpoints, getHotelEndpoint } from "./endpoints" export { endpoints } from "./endpoints"
const defaultOptions: RequestInit = { const defaultOptions: RequestInit = {
cache: "no-store", cache: "no-store",
@@ -27,7 +27,7 @@ const fetch = fetchRetry(global.fetch, {
}) })
export async function get( export async function get(
endpoint: Endpoint, endpoint: Endpoint | `${Endpoint}/${string}`,
options: RequestOptionsWithOutBody, options: RequestOptionsWithOutBody,
params?: URLSearchParams params?: URLSearchParams
) { ) {

View File

@@ -1,11 +1,7 @@
import * as api from "@/lib/api" import * as api from "@/lib/api"
import { getHotelEndpoint } from "@/lib/api/endpoints"
import { badRequestError } from "@/server/errors/trpc" import { badRequestError } from "@/server/errors/trpc"
import { import { publicProcedure, router, serviceProcedure } from "@/server/trpc"
anonymousOrAuthProcedure, import { toApiLang } from "@/server/utils"
publicProcedure,
router,
} from "@/server/trpc"
import { import {
getFiltersInputSchema, getFiltersInputSchema,
@@ -21,28 +17,28 @@ import {
import tempFilterData from "./tempFilterData.json" import tempFilterData from "./tempFilterData.json"
// import tempHotelData from "./tempHotelData.json" // import tempHotelData from "./tempHotelData.json"
import tempRatesData from "./tempRatesData.json" import tempRatesData from "./tempRatesData.json"
import { toApiLang } from "./utils"
export const hotelQueryRouter = router({ export const hotelQueryRouter = router({
getHotel: anonymousOrAuthProcedure getHotel: serviceProcedure
.input(getHotelInputSchema) .input(getHotelInputSchema)
.query(async ({ input, ctx }) => { .query(async ({ input, ctx }) => {
const { hotelId, language, include } = input const { hotelId, language, include } = input
const params = new URLSearchParams() const params = new URLSearchParams()
const apiLang = toApiLang(language) const apiLang = toApiLang(language)
params.set("language", apiLang) params.set("language", apiLang)
if (include) { if (include) {
params.set("include", include.join(",")) params.set("include", include.join(","))
} }
const authToken = await ctx.getToken()
const apiResponse = await api.get( const apiResponse = await api.get(
getHotelEndpoint(hotelId), `${api.endpoints.v1.hotels}/${hotelId}`,
{ {
cache: "no-store", cache: "no-store",
headers: { headers: {
Authorization: `Bearer ${authToken}`, Authorization: `Bearer ${ctx.serviceToken}`,
}, },
}, },
params params

View File

@@ -1,22 +0,0 @@
import { Lang } from "@/constants/languages"
const langMap: { [key in Lang]: string } = {
[Lang.en]: "En",
[Lang.sv]: "Sv",
[Lang.no]: "No",
[Lang.fi]: "Fi",
[Lang.da]: "Da",
[Lang.de]: "De",
}
/**
* Helper function to convert Lang enum to uppercase
* Needed for the Hotel endpoint.
*/
export const toApiLang = (lang: Lang): string => {
const result = langMap[lang]
if (!result) {
throw new Error("Invalid language")
}
return result
}

View File

@@ -4,27 +4,23 @@ import { ServiceTokenResponse } from "@/types/tokens"
const SERVICE_TOKEN_REVALIDATE_SECONDS = 3599 // 59 minutes and 59 seconds. const SERVICE_TOKEN_REVALIDATE_SECONDS = 3599 // 59 minutes and 59 seconds.
async function fetchServiceToken(): Promise<ServiceTokenResponse> { export async function fetchServiceToken(): Promise<ServiceTokenResponse> {
try { try {
const response = await fetch( const response = await fetch(`${env.CURITY_ISSUER_USER}/oauth/v2/token`, {
`${env.CURITY_ISSUER_SERVICE}/oauth/v2/token`, method: "POST",
{ headers: {
method: "POST", "Content-Type": "application/x-www-form-urlencoded",
headers: { Accept: "application/json",
"Content-Type": "application/x-www-form-urlencoded", },
Accept: "application/json", body: new URLSearchParams({
}, grant_type: "client_credentials",
body: new URLSearchParams({ client_id: env.CURITY_CLIENT_ID_SERVICE,
grant_type: "client_credentials", client_secret: env.CURITY_CLIENT_SECRET_SERVICE,
client_id: env.CURITY_CLIENT_ID_SERVICE, }),
client_secret: env.CURITY_CLIENT_SECRET_SERVICE, next: {
scope: "hotel", revalidate: SERVICE_TOKEN_REVALIDATE_SECONDS,
}), },
next: { })
revalidate: SERVICE_TOKEN_REVALIDATE_SECONDS,
},
}
)
if (!response.ok) { if (!response.ok) {
throw new Error("Failed to obtain service token") throw new Error("Failed to obtain service token")
@@ -36,12 +32,3 @@ async function fetchServiceToken(): Promise<ServiceTokenResponse> {
throw error throw error
} }
} }
export async function getAuthToken(userToken?: string | null): Promise<string> {
if (userToken) {
return userToken
}
const { access_token } = await fetchServiceToken()
return access_token
}

View File

@@ -4,10 +4,11 @@ import { env } from "@/env/server"
import { import {
badRequestError, badRequestError,
internalServerError,
sessionExpiredError, sessionExpiredError,
unauthorizedError, unauthorizedError,
} from "./errors/trpc" } from "./errors/trpc"
import { getAuthToken } from "./tokenManager" import { fetchServiceToken } from "./tokenManager"
import { transformer } from "./transformer" import { transformer } from "./transformer"
import { langInput } from "./utils" import { langInput } from "./utils"
@@ -101,16 +102,14 @@ export const safeProtectedProcedure = t.procedure.use(async function (opts) {
}) })
}) })
export const anonymousOrAuthProcedure = t.procedure.use(async function (opts) { export const serviceProcedure = t.procedure.use(async (opts) => {
const session: Session | null = await opts.ctx.auth() const { access_token } = await fetchServiceToken()
const userToken = session?.token?.access_token || null if (!access_token) {
throw internalServerError("Failed to obtain service token")
const getToken = async () => await getAuthToken(userToken) }
return opts.next({ return opts.next({
ctx: { ctx: {
session, serviceToken: access_token,
getToken,
}, },
}) })
}) })

View File

@@ -5,3 +5,24 @@ import { Lang } from "@/constants/languages"
export const langInput = z.object({ export const langInput = z.object({
lang: z.nativeEnum(Lang), lang: z.nativeEnum(Lang),
}) })
/**
* Helper function to convert Lang enum to uppercase
* Needed for the Hotel endpoint.
*/
export const toApiLang = (lang: Lang): string => {
const result = toApiLangMap[lang]
if (!result) {
throw new Error("Invalid language")
}
return result
}
const toApiLangMap: { [key in Lang]: string } = {
[Lang.en]: "En",
[Lang.sv]: "Sv",
[Lang.no]: "No",
[Lang.fi]: "Fi",
[Lang.da]: "Da",
[Lang.de]: "De",
}