diff --git a/README.md b/README.md index 3413738..ded9be1 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,14 @@ # themepark-assistant A tool for improving your trips to themeparks - once developed -## Repo structure -- /api: API implementation - - ./: config files - - /src: API Code - - /db: Database client, schema & migrations - - /errors: Error types - - index.ts: Exporter for all error classes - - /jobs: Background tasks - - /lib: Reusable functions - - /routes: API Endpoints - - /types: Data type definitions - - index.ts: Entrypoint for API Requests & background tasks on Cloudflare Workers +## Testing +Send request - -## Development -### Run enviromnment -Run worker locally (without remote d1 access, scheduled tasks not available) -```bash -npx wrangler dev -``` - -Run worker locally (without remote d1 access, scheduled tasks available) -```bash -npx wrangler dev --test-scheduled -``` - -Run worker locally (with remote connection to d1, scheduled tasks available) -```bash -npx wrangler dev --remote --test-scheduled -``` - -### Requests -Send request with bearer authentication ```bash curl -H "Authorization: Bearer insecure-token" http://127.0.0.1:8787/notification/list ``` -Run request with cron expression (for executing background tasks) -```bash -curl "http://localhost:8787/__scheduled?cron=*+*+*+*+*" -``` - -### Drizzle DB migrations -Update cloudflare d1 db +## Update cloudflare d1 db DB scheme is defined in typescript apply changes @@ -57,25 +21,35 @@ export sql statements instead of running migration npx drizzle-kit export --config=drizzle-dev.config.ts ``` -### Useful sql statements for SQLite / D1 +## SQLite / D1 Delete view ```sql DROP VIEW IF EXISTS attraction_subscriptions; ``` -### Cloudflare workers tricks +## Cloudflare workers tricks If types are missing, run: ```bash npx wrangler types ``` -## Authentication endpoints (auth.js) +## Testing cronjobs +Run worker locally (without remote d1 access) +```bash +npx wrangler dev --test-scheduled +``` + +Run worker locally (with remote connection to d1) +```bash +npx wrangler dev --remote --test-scheduled +``` + +Run curl request with cron expression +```bash +curl "http://localhost:8787/__scheduled?cron=*+*+*+*+*" +``` + +## Authentication endpoints - /auth/signin -> Login - /auth/signout -> Logout -- /auth/callback/github -> Callback for GitHub OAuth config - -## Contributing -TBD - -## License -TBD \ No newline at end of file +- /auth/callback/github -> Callback for GitHub OAuth config \ No newline at end of file diff --git a/api/src/errors/background-error.ts b/api/src/errors/background-error.ts index d05207f..338a5ad 100644 --- a/api/src/errors/background-error.ts +++ b/api/src/errors/background-error.ts @@ -1,8 +1,15 @@ // Error classes for background jobs -import { BaseError } from "./base-error"; // Class for custom background errors -export class BackgroundJobError extends BaseError{} +export class BackgroundJobError extends Error{ + cause?: unknown; + + constructor(message: string, cause?: unknown){ + super(message); + this.name = this.constructor.name; + this.cause = cause; + } +} // Errors based on class BackgroundJobError export class BackgroundDatabaseError extends BackgroundJobError{ @@ -11,6 +18,12 @@ export class BackgroundDatabaseError extends BackgroundJobError{ } } +export class BackgroundFetchError extends BackgroundJobError{ + constructor(cause?: unknown){ + super('Fetching data failed', cause); + } +} + export class AttractionImportError extends BackgroundJobError{ constructor(cause?: unknown){ super('Failed to import attractions into database.', cause); diff --git a/api/src/errors/base-error.ts b/api/src/errors/base-error.ts deleted file mode 100644 index 3e17ce4..0000000 --- a/api/src/errors/base-error.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Base for new error domains/classes -export class BaseError extends Error{ - cause?: unknown; - - constructor(message: string, cause?: unknown){ - super(message); - this.name = this.constructor.name; - this.cause = cause; - } -} \ No newline at end of file diff --git a/api/src/errors/index.ts b/api/src/errors/index.ts deleted file mode 100644 index 4eaca3f..0000000 --- a/api/src/errors/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './background-error' -export * from './http-error' -export * from './lib-error' \ No newline at end of file diff --git a/api/src/errors/lib-error.ts b/api/src/errors/lib-error.ts deleted file mode 100644 index 2cad4da..0000000 --- a/api/src/errors/lib-error.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Errors in custom libs -import { BaseError } from "./base-error"; - -export class LibError extends BaseError{} - -export class FetchError extends LibError{ - constructor(cause?: unknown, source?: string){ - super( - source - ? `Fetching data from ${source} failed` - : 'Fetching data failed', - cause); - } -} - -export class BatchExecutionError extends LibError{ - constructor(cause?: unknown){ - super('Batched execution failed.', cause); - } -} - -export class HTTPError extends LibError{ - constructor(errorCode: number, cause?: unknown){ - super(`Received HTTP error code: ${errorCode}`, cause); - } -} \ No newline at end of file diff --git a/api/src/jobs/send-notifications.ts b/api/src/jobs/send-notifications.ts index 11fa89a..af7c610 100644 --- a/api/src/jobs/send-notifications.ts +++ b/api/src/jobs/send-notifications.ts @@ -3,7 +3,7 @@ import { getDbEnv } from '../db/client' import { subscribedThemeparks, attractionSubscriptions } from "../db/schema"; import { SubscribedThemeparks } from "../types/subscribed-themeparks"; import { AttractionSubscription } from "../types/attraction-subscriptions"; -import { KVParseError, SendNotificationError } from "../errors"; +import { KVParseError, SendNotificationError } from "../errors/background-error"; import httpRequest from "../lib/http-request"; import fetchAttractions from "../lib/fetch-attractions"; diff --git a/api/src/jobs/update-attraction-list.ts b/api/src/jobs/update-attraction-list.ts index 0fed46b..eddfeba 100644 --- a/api/src/jobs/update-attraction-list.ts +++ b/api/src/jobs/update-attraction-list.ts @@ -3,7 +3,7 @@ import { attraction, themepark } from '../db/schema' import { inArray } from 'drizzle-orm' import { Attraction } from '../types/attraction' import { ThemeparkSelect } from '../types/themepark' -import { AttractionImportError, BackgroundDatabaseError } from '../errors' +import { AttractionImportError, BackgroundDatabaseError } from '../errors/background-error' import asyncBatchJob from '../lib/async-batch-job' import fetchAttractions from '../lib/fetch-attractions' diff --git a/api/src/jobs/update-themepark-data.ts b/api/src/jobs/update-themepark-data.ts index 44d8ca9..daec8de 100644 --- a/api/src/jobs/update-themepark-data.ts +++ b/api/src/jobs/update-themepark-data.ts @@ -1,7 +1,7 @@ import { getDbEnv } from '../db/client' import { themepark } from '../db/schema' import { countryCodesDE } from '../lib/countries' -import { FetchError, ThemeparkUpdateError } from '../errors' +import { BackgroundFetchError, ThemeparkUpdateError } from '../errors/background-error' import httpRequest from '../lib/http-request' import asyncBatchJob from '../lib/async-batch-job' @@ -31,7 +31,7 @@ async function fetchThemeparks( return result; } catch(e){ - throw new FetchError(e); + throw new BackgroundFetchError(e); } } diff --git a/api/src/lib/async-batch-job.ts b/api/src/lib/async-batch-job.ts index a9e84ca..f41818c 100644 --- a/api/src/lib/async-batch-job.ts +++ b/api/src/lib/async-batch-job.ts @@ -1,5 +1,3 @@ -import { BatchExecutionError } from "../errors"; - /** * Run any async operation in (multiple) batches * @param data Array to split into batches @@ -14,6 +12,6 @@ export default async function asyncBatchJob(data: T[], batchSize: number = 20 } } catch(e){ - throw new BatchExecutionError(e); + throw new Error(`Batch execution failed: ${e}`); } } \ No newline at end of file diff --git a/api/src/lib/fetch-attractions.ts b/api/src/lib/fetch-attractions.ts index 53a3950..c83e7e1 100644 --- a/api/src/lib/fetch-attractions.ts +++ b/api/src/lib/fetch-attractions.ts @@ -1,6 +1,5 @@ import { AttractionImport } from '../types/attraction' import httpRequest from '../lib/http-request' -import { FetchError } from '../errors'; /** * Fetching the attractions from a specified park @@ -26,6 +25,6 @@ export default async function fetchAttractions( return result; } catch(e){ - throw new FetchError(e, endpoint); + throw new Error(`Failed to fetch attractions: ${e}`); } } \ No newline at end of file diff --git a/api/src/lib/http-request.ts b/api/src/lib/http-request.ts index fdc0aea..47267e2 100644 --- a/api/src/lib/http-request.ts +++ b/api/src/lib/http-request.ts @@ -1,5 +1,3 @@ -import { HTTPError } from "../errors"; - /** * Executes a HTTP Request with option for custom header & body parameters * @param endpoint Request endpoint @@ -28,7 +26,7 @@ export default async function httpRequest( if (!response.ok){ - throw new HTTPError(response.status); + throw new Error(`HTTP error! Status: ${response.status}`); } if(response.status === 204){ diff --git a/api/src/lib/user-auth.ts b/api/src/lib/user-auth.ts index 550be54..f71b586 100644 --- a/api/src/lib/user-auth.ts +++ b/api/src/lib/user-auth.ts @@ -4,7 +4,7 @@ import { UserSelect } from "../types/user"; import { user } from "../db/schema"; import { like } from "drizzle-orm"; import { DrizzleD1Database } from "drizzle-orm/d1"; -import { MissingMailError, UserInactiveError, DatabaseError } from "../errors"; +import { MissingMailError, UserInactiveError, DatabaseError } from "../errors/http-error"; /** * Returns the details of a user from the given context diff --git a/api/src/routes/attraction.ts b/api/src/routes/attraction.ts index bf59d49..291d429 100644 --- a/api/src/routes/attraction.ts +++ b/api/src/routes/attraction.ts @@ -2,7 +2,7 @@ import { Hono, Context } from 'hono' import { getDbContext } from '../db/client' import { attractionNotification, notificationMethod } from '../db/schema' import { and, eq } from 'drizzle-orm' -import { DatabaseError, InvalidParameter, MissingParameter } from '../errors' +import { DatabaseError, InvalidParameter, MissingParameter } from '../errors/http-error' import { getUser } from '../lib/user-auth' import { Message } from '../types/response' import { NotificationMethodSelect } from '../types/notification-method' diff --git a/api/src/routes/themepark.ts b/api/src/routes/themepark.ts index 7bd89b9..c1b4d03 100644 --- a/api/src/routes/themepark.ts +++ b/api/src/routes/themepark.ts @@ -3,7 +3,7 @@ import { getDbContext } from '../db/client' import { themepark, attraction } from '../db/schema' import { responseCache } from '../lib/cache' import { eq } from 'drizzle-orm' -import { DatabaseError } from '../errors' +import { DatabaseError } from '../errors/http-error' const app = new Hono()