Access D1 database outside a request

Hello, I am trying to configure a D1 database for my Cloudflare worker. I have already created the database and added it to
wrangler.toml
wrangler.toml
. In the docs (https://developers.cloudflare.com/d1/get-started/), they say we can access the database like this:
export interface Env {
// If you set another name in wrangler.toml as the value for 'binding',
// replace "DB" with the variable name you defined.
DB: D1Database;
}

export default {
async fetch(request, env): Promise<Response> {
const { pathname } = new URL(request.url);

if (pathname === "/api/beverages") {
// If you did not use `DB` as your binding name, change it here
const { results } = await env.DB.prepare(
"SELECT * FROM Customers WHERE CompanyName = ?"
)
.bind("Bs Beverages")
.all();
return Response.json(results);
}

return new Response(
"Call /api/beverages to see everyone who works at Bs Beverages"
);
},
} satisfies ExportedHandler<Env>;
export interface Env {
// If you set another name in wrangler.toml as the value for 'binding',
// replace "DB" with the variable name you defined.
DB: D1Database;
}

export default {
async fetch(request, env): Promise<Response> {
const { pathname } = new URL(request.url);

if (pathname === "/api/beverages") {
// If you did not use `DB` as your binding name, change it here
const { results } = await env.DB.prepare(
"SELECT * FROM Customers WHERE CompanyName = ?"
)
.bind("Bs Beverages")
.all();
return Response.json(results);
}

return new Response(
"Call /api/beverages to see everyone who works at Bs Beverages"
);
},
} satisfies ExportedHandler<Env>;
Well, that's great, but how can I read the database content within a function which is not related to a request and does not have a prebuilt
env
env
parameter?
15 Replies
Hard@Work
Hard@Work4mo ago
You don't. All external I/O must be performed in the context of a Request(or other event)
PneuTueur
PneuTueurOP4mo ago
So I guess that it could be performed for a cron trigger event?
Hard@Work
Hard@Work4mo ago
Yup, HTTP Events, Cron Triggers, Queues, Emails, etc. are all valid event types that give you access to I/O
PneuTueur
PneuTueurOP4mo ago
Thank you for your clarifications. It is also likely that itty router provides access to the database by responding to a request, isn't it?
Hard@Work
Hard@Work4mo ago
Sure, I believe there is a way to pass bindings around with itty
PneuTueur
PneuTueurOP4mo ago
ok, thank you!
gwapes
gwapes4mo ago
Hey, sorry if this is unrelated but doesn’t cloud flare offer a rest api for D1 requests? https://developers.cloudflare.com/api/operations/cloudflare-d1-create-database Unsure if this could help 😅
Cloudflare API Documentation
Interact with Cloudflare's products and services via the Cloudflare API
ItsWendell
ItsWendell4mo ago
I don't see a directly example of itty router with cloudflare in their repository, but Hono, similar to itty router, has direct support for bindings: https://hono.dev/docs/getting-started/cloudflare-workers#bindings
Cloudflare Workers - Hono
Ultrafast web framework for Cloudflare Workers, Fastly Compute, Deno, Bun, Vercel, Node.js, and others. Fast, but not only fast.
Hard@Work
Hard@Work4mo ago
Yes, but you still can't do I/O outside of the Request context. This includes the fetch calls which you would need for that API
gwapes
gwapes4mo ago
Oh right my bad 😅
Pavan
Pavan3mo ago
You can create a middleware that you set a d1 clousure instance and use it without passing context.d1 to your functions that need dababase: ex:
class D1 {
private _db: D1Database | undefined;

get db() {
return this._db as D1Database;
}

setDb(db: D1Database) {
this._db = db;
}
}

export default new D1();
class D1 {
private _db: D1Database | undefined;

get db() {
return this._db as D1Database;
}

setDb(db: D1Database) {
this._db = db;
}
}

export default new D1();
the middleware before all req could be like that:
import D1 from ''

return async function PrepareDBMiddleware(c: Context, next: () => any) {
D1.setDb(c.D1);
await next();
}
import D1 from ''

return async function PrepareDBMiddleware(c: Context, next: () => any) {
D1.setDb(c.D1);
await next();
}
to use
import D1 from ''

const clients = await D1.db.prepare('').........
import D1 from ''

const clients = await D1.db.prepare('').........
PneuTueur
PneuTueurOP3mo ago
this is a very interesting solution, I will make sure to try it out thank you!
Pavan
Pavan3mo ago
Do you use Hono with cloudflare workers, right? Do u can help with that: https://discord.com/channels/595317990191398933/1276333679907704984/1276333679907704984
PneuTueur
PneuTueurOP3mo ago
I am sorry, I am using itty-router with my worker However I also encounter some issues with cors
Kevin
Kevin3mo ago
Bindings are just passed along automatically in the 2nd/env argument to handlers/middleware, if you wired things up manually, you'll need to feed it in yourself, but if you just use the default fetch signature, it'll pick up all the cloudflare args and pass them along (env and context).
import { Router } from 'itty-router'

const router = Router()

router.get('/', (request, env, ctx) => {
// we have access to the request, env/bindings, and context
}

// MANUAL
export default {
fetch: (request, env, ctx) => router.fetch(request, env, ctx)
}

// AUTOMAGIC (same effect as above)
export default router

// or if on a version of wrangler that throws a "middleware" error, just export the deconstructed router like this
export default { ...router }
import { Router } from 'itty-router'

const router = Router()

router.get('/', (request, env, ctx) => {
// we have access to the request, env/bindings, and context
}

// MANUAL
export default {
fetch: (request, env, ctx) => router.fetch(request, env, ctx)
}

// AUTOMAGIC (same effect as above)
export default router

// or if on a version of wrangler that throws a "middleware" error, just export the deconstructed router like this
export default { ...router }
Basically, itty (platform agnostic) allows you to pass anything throughout the entire handler/middleware chain just by passing it to the router.fetch function after the Request object. Cloudflare calls the { fetch } function with these args, so you automatically see them in itty handlers!
Want results from more Discord servers?
Add your server