Marcel Overdijk
Marcel Overdijk
Explore posts from servers
CDCloudflare Developers
Created by Marcel Overdijk on 8/27/2024 in #workers-help
Global ContextHolder
I'm using Hono on cloudflare workers and my handle functions look like:
async handle(ctx: Context<Env>) { .. }
async handle(ctx: Context<Env>) { .. }
and I'm then passing that ctx that to other method calls in multiple layers. which feels quite cumbersome. is it possible to create some global ContextHolder where I can set and get the ctx from? Like a request-scoped holder... I wonder how others do this?
3 replies
CDCloudflare Developers
Created by Marcel Overdijk on 8/27/2024 in #workers-help
Simple logging in development
In development I want to be able to do some logging, like:
logger.debug('Fetching customer with id=%s', id);
logger.trace('Querying database for customer with id=%s', id);
logger.debug('Fetching customer with id=%s', id);
logger.trace('Querying database for customer with id=%s', id);
by default it's fine to have just debug, but sometimes I would also like to trace logs for more details. Besides the log message itself, I would like to log also automatically some context info, like the Hono request-id. I tried Pino js logger, but it gives some problems on Cloudflare workers, so I wonder if there are other (simple) solutions, or that I can better write my own?
3 replies
CDCloudflare Developers
Created by Marcel Overdijk on 5/4/2024 in #workers-help
Logging
I'm wondering what others are using for application level logging? Just console.log ? I woud like to enable some custom logging statements based on the environment, like log.debug, log.warn Has anyone tries libraries like Winston or Pino on workers? Is there a recommendation?
10 replies
CDCloudflare Developers
Created by Marcel Overdijk on 4/8/2024 in #workers-help
D1 false type-safety using TypeScript
As explained here: https://developers.cloudflare.com/d1/build-with-d1/d1-client-api/#typescript-support
D1 client API is fully-typed via the @cloudflare/workers-types package, and also supports generic types as part of its TypeScript API. A generic type allows you to provide an optional type parameter so that a function understands the type of the data it is handling.

When using the query statement methods stmt.all(), stmt.raw() and stmt.first(), you can provide a type representing each database row. D1’s API will return the result object with the correct type.

For example, providing an OrderRow type as a type parameter to stmt.all() will return a typed Array<OrderRow> object instead of the default Record<string, unknown> type:
D1 client API is fully-typed via the @cloudflare/workers-types package, and also supports generic types as part of its TypeScript API. A generic type allows you to provide an optional type parameter so that a function understands the type of the data it is handling.

When using the query statement methods stmt.all(), stmt.raw() and stmt.first(), you can provide a type representing each database row. D1’s API will return the result object with the correct type.

For example, providing an OrderRow type as a type parameter to stmt.all() will return a typed Array<OrderRow> object instead of the default Record<string, unknown> type:
but trying this out it's giving false type-safety. Imagine this type definition:
type PetRow = {
id: number;
type: "DOG" | "CAT";
name: string;
dateOfBirth: string;
dateOfDeath: string;
chipNumber: string;
}
type PetRow = {
id: number;
type: "DOG" | "CAT";
name: string;
dateOfBirth: string;
dateOfDeath: string;
chipNumber: string;
}
(note the camel case property names, and there is no breed field) and the following query:
const result = await context.env.DB.prepare(
`SELECT id, type, name, date_of_birth, date_of_death, chip_number, breed
FROM pet
ORDER BY name ASC
LIMIT 100`
).all<PetRow>();

const pets = result.results;
const result = await context.env.DB.prepare(
`SELECT id, type, name, date_of_birth, date_of_death, chip_number, breed
FROM pet
ORDER BY name ASC
LIMIT 100`
).all<PetRow>();

const pets = result.results;
(note the underscore case as it is stored like that in the database) Now the result is:
[
{
"id": 1,
"type": "DOG",
"name": "Simba",
"date_of_birth": null,
"date_of_death": null,
"chip_number": '1234567890',
"breed": 'Australian Shepard',
},
..
]
[
{
"id": 1,
"type": "DOG",
"name": "Simba",
"date_of_birth": null,
"date_of_death": null,
"chip_number": '1234567890',
"breed": 'Australian Shepard',
},
..
]
All properties (date_of_birth, date_of_death, chip_number, breed) in the query that do not match the type definition are still included in the result. It gives some false type-safety.
2 replies
CDCloudflare Developers
Created by Marcel Overdijk on 4/8/2024 in #pages-help
[TS] Passing object/data from CF Functions middleware to function handlers
I would like to setup Prisma in a functions _middleware.ts like:
import { PrismaClient } from '@prisma/client';
import { PrismaD1 } from '@prisma/adapter-d1';

export const onRequest: PagesFunction<Env> = async (context) => {
const adapter = new PrismaD1(context.env.DB);
const prisma = new PrismaClient({ adapter });

// now store prisma so it's available in function hadlers!
context.env.prisma = prisma;
// or
context.data.prisma = prisma;

return await context.next();
}
import { PrismaClient } from '@prisma/client';
import { PrismaD1 } from '@prisma/adapter-d1';

export const onRequest: PagesFunction<Env> = async (context) => {
const adapter = new PrismaD1(context.env.DB);
const prisma = new PrismaClient({ adapter });

// now store prisma so it's available in function hadlers!
context.env.prisma = prisma;
// or
context.data.prisma = prisma;

return await context.next();
}
I have a wrangler types functions/worker-configuration.d.ts generated file that looks like:
// Generated by Wrangler on Fri Apr 05 2024 23:40:46 GMT+0200 (Central European Summer Time)
// by running `wrangler types functions/worker-configuration.d.ts`

interface Env {
DB: D1Database;
}
// Generated by Wrangler on Fri Apr 05 2024 23:40:46 GMT+0200 (Central European Summer Time)
// by running `wrangler types functions/worker-configuration.d.ts`

interface Env {
DB: D1Database;
}
In my function handler I would like to use prisma client (type-safe) like:
export const onRequestGet: PagesFunction<Env> = async (context) => {
// TODO: get typed prisma client
const pets = await prisma.pet.findMany();
return Response.json(pets);
};
export const onRequestGet: PagesFunction<Env> = async (context) => {
// TODO: get typed prisma client
const pets = await prisma.pet.findMany();
return Response.json(pets);
};
How should I pass the prisma client best? Via context.env or context.data ? And how to type it?
1 replies
CDCloudflare Developers
Created by Marcel Overdijk on 4/7/2024 in #pages-help
Failed: an internal error occurred. If this continues, contact support: https://cfl.re/3WgEyrH
I've see multiple Failed: an internal error occurred errors here, but non of them helped me track down why my app is giving me the same. Unfortunately there is no detailed error log, it just gives me:
22:53:42.785 Success: Finished cloning repository files
22:53:44.548 wrangler.toml config file detected
22:53:45.465 Failed: an internal error occurred. If this continues, contact support: https://cfl.re/3WgEyrH
22:53:42.785 Success: Finished cloning repository files
22:53:44.548 wrangler.toml config file detected
22:53:45.465 Failed: an internal error occurred. If this continues, contact support: https://cfl.re/3WgEyrH
It's a very small app, the dist folder just being 7 files and 508 KB. It has some functions using Prisma using the D1 binding. Locally the app runs fine with wrangler dev... Deployment ID: 03c8c103127e788e820573a1587a5cab0808522a
7 replies
CDCloudflare Developers
Created by Marcel Overdijk on 4/5/2024 in #pages-help
running `ng serve` together with `wrangler pages dev`
I'm running a POC with an Angular frontend (non-SSR) and an API inside the functions folders. The setup is running nicely on CF when deployed. But I'm now seeking for a good development workflow... With wrangler pages dev I can test my api on port 8787 and it picks up changes to my API in development without restarting. I would like to integrate the Angular reload capabilities in my development environment as well via, ng serve (that runs on port 4200). Ideally I would like to run them on the same port.. Maybe proxying client request towards to 8787 to 4200 in wrangler dev? I wonder how others are doing this. Btw this is similar for running a React setup using Functions.
1 replies
CDCloudflare Developers
Created by Marcel Overdijk on 4/2/2024 in #pages-help
Downloading data before building pages (SSG/SSR)
I have the use case that I'm experimenting building a Cloudflare Pages project using Astro. It will using a dynamic GraphQL endpoint which queries data from a D1 database. However it will also generate static pages (SSG). For these static pages I have a local SQLite file that will be queries to dynamically create the (static) pages. Locally on my development machine this works perfectly. However, I would like to switch to a mode that I automatically re-deploy my site via a push to Github. Now that local SQLite is ~60MB (zipped ~6MB) and I don't want to upload that Github... Is it possible to either download that file during the build process, or upload it somewhere before the build kicks off? Note that the SQLite file (zip) is publicly available so that's not an issue. I'm looking at the possibilities I have; and what possible limitations are.
14 replies
CDCloudflare Developers
Created by Marcel Overdijk on 3/29/2024 in #workers-help
drizzle best practices for create drizzle instance
From this example, is it a good practice to create the db every time or should I cache? I’m coming from a Java world where caching and connection pooling is the way to go. But I understand CF is cloud solution and this might be different. I could create that db in middleware and make it available via locals, but is that smart in terms of costs? Having an endpoint that does not access the d1 database will construct it then… should I make it lazy or something in locals?
import { drizzle } from 'drizzle-orm/d1';

export interface Env {
<BINDING_NAME>: D1Database;
}

export default {
async fetch(request: Request, env: Env) {
const db = drizzle(env.<BINDING_NAME>);
const result = await db.select().from(users).all()
return Response.json(result);
},
};
import { drizzle } from 'drizzle-orm/d1';

export interface Env {
<BINDING_NAME>: D1Database;
}

export default {
async fetch(request: Request, env: Env) {
const db = drizzle(env.<BINDING_NAME>);
const result = await db.select().from(users).all()
return Response.json(result);
},
};
2 replies