From 1334a3c858c83a730fad624351f946d3f5b680d7 Mon Sep 17 00:00:00 2001 From: Ole Langbehn <ole.langbehn@inoio.de> Date: Wed, 6 Sep 2023 15:59:32 +0200 Subject: [PATCH] HOLI-3881 add fake mode for local development without secrets --- .envrc.local.template | 3 +-- app/main.ts | 25 +++++++++++++++++++------ app/server.ts | 31 +++++++++++++++++-------------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/.envrc.local.template b/.envrc.local.template index 67b19f6..149451c 100644 --- a/.envrc.local.template +++ b/.envrc.local.template @@ -1,2 +1 @@ -export GEOAPIFY_API_KEY="" - +export GEOAPIFY_API_KEY="" \ No newline at end of file diff --git a/app/main.ts b/app/main.ts index 8673f1e..9080439 100644 --- a/app/main.ts +++ b/app/main.ts @@ -1,5 +1,5 @@ import { logger, LogSeverity } from "./logging.ts"; -import { startServer } from "./server.ts"; +import { DEFAULT_CACHE_ENABLED, DEFAULT_CACHE_TTL_MS_GEOAPIFY_AUTOCOMPLETE, DEFAULT_PORT, startServer } from "./server.ts"; const environment = Deno.env.get("ENVIRONMENT") || "development"; @@ -8,16 +8,29 @@ logger.setUpLogger( environment === "development" ? LogSeverity.DEFAULT : LogSeverity.INFO, ); +const required = <T>(name: string, t?: T, fallback?: T): T => { + if (t === undefined && fallback === undefined) { + throw Error(`Environment variable "${name}" is required`); + } else { + return t !== undefined ? t : fallback!; + } +}; + + const serverConfigFromEnv = () => { const asNumber = (str?: string) => (str ? Number(str) : undefined); const asBoolean = (str?: string) => (str ? Boolean(str) : undefined); + const fake = asBoolean(Deno.env.get("FAKE")) || false // For local development. If set, the API returns dummy data return { - port: asNumber(Deno.env.get("PORT")), - cacheEnabled: asBoolean(Deno.env.get("CACHE_ENABLED")), - cacheTtlMsPlacesAutocomplete: asNumber( - Deno.env.get("DEFAULT_CACHE_TTL_MS_GEOAPIFY_AUTOCOMPLETE"), + port: required("PORT", asNumber(Deno.env.get("PORT")), DEFAULT_PORT), + cacheEnabled: required("CACHE_ENABLED", asBoolean(Deno.env.get("CACHE_ENABLED")), DEFAULT_CACHE_ENABLED), + cacheTtlMsPlacesAutocomplete: required("DEFAULT_CACHE_TTL_MS_GEOAPIFY_AUTOCOMPLETE", asNumber(Deno.env.get("DEFAULT_CACHE_TTL_MS_GEOAPIFY_AUTOCOMPLETE")), DEFAULT_CACHE_TTL_MS_GEOAPIFY_AUTOCOMPLETE), + geoapifyApiKey: required( + "GEOAPIFY_API_KEY", + Deno.env.get("GEOAPIFY_API_KEY"), + fake ? 'dummy value' : undefined ), - geoapifyApiKey: Deno.env.get("GEOAPIFY_API_KEY"), + fake }; }; diff --git a/app/server.ts b/app/server.ts index 8d63bee..cecf5c4 100644 --- a/app/server.ts +++ b/app/server.ts @@ -32,7 +32,7 @@ const typeDefs = ` type Query { placesAutocomplete(text: String!, limit: Int, level: String): [Place]! - placeDetails(id: String!): PlaceDetails! + placeDetails(id: String!): PlaceDetails } `; @@ -50,24 +50,23 @@ const createResolvers = (config: ServerConfig) => ({ _parent: any, parameters: PlacesAutocompleteParameters, context: GraphQLContext, - ) => + ) => config.fake ? Promise.resolve([]) : fetchPlaces( parameters, getLanguage(context.language), - config.geoapifyApiKey || "", + config.geoapifyApiKey, ), placeDetails: ( // deno-lint-ignore no-explicit-any _parent: any, parameters: PlacesDetailsParameters, context: GraphQLContext, - ) => { - return fetchPlaceDetails( + ) => config.fake ? Promise.resolve(undefined) : + fetchPlaceDetails( parameters, getLanguage(context.language), - config.geoapifyApiKey || "", - ); - }, + config.geoapifyApiKey, + ), }, }); @@ -76,10 +75,11 @@ export const DEFAULT_CACHE_ENABLED = true; export const DEFAULT_CACHE_TTL_MS_GEOAPIFY_AUTOCOMPLETE = 60_000 * 60 * 24; export interface ServerConfig { - port?: number; // default: 8003 - cacheEnabled?: boolean; // default: true - cacheTtlMsPlacesAutocomplete?: number; // default: 24 hours - geoapifyApiKey?: string; + port: number; // default: 8003 + cacheEnabled: boolean; // default: true + cacheTtlMsPlacesAutocomplete: number; // default: 24 hours + geoapifyApiKey: string; + fake: boolean; } export type GraphQLContext = { @@ -94,7 +94,7 @@ export type GraphQLContext = { }; export const createGraphQLServer = (config: ServerConfig): GraphQLServer => { - const plugins = config.cacheEnabled || DEFAULT_CACHE_ENABLED + const plugins = config.cacheEnabled ? [ useResponseCache({ // global cache per language, shared by all users @@ -133,13 +133,16 @@ export type GraphQLServer = any; export const startServer = (config: ServerConfig): Promise<void> => { const graphQLServer: GraphQLServer = createGraphQLServer(config); return serve(graphQLServer.handleRequest, { - port: config.port || DEFAULT_PORT, + port: config.port, onListen({ port, hostname }) { logger.info( `Server started at http://${ hostname === "0.0.0.0" ? "localhost" : hostname }:${port}/graphql`, ); + if(config.fake) { + logger.info(`Server is serving fake data due to FAKE env var set to true`) + } }, }); }; -- GitLab