@@ -18,138 +18,14 @@ Deploy the following Worker code using Sessions API, which will prompt you to cr
1818
1919 [ ![ Deploy to Cloudflare] ( https://deploy.workers.cloudflare.com/button )] ( https://deploy.workers.cloudflare.com/?url=https://github.com/cloudflare/templates/tree/staging/d1-starter-sessions-api )
2020
21- ``` ts collapse={1-6, 34-130}
22- import { D1Database , D1DatabaseSession } from " @cloudflare/workers-types" ;
23-
24- export type Env = {
25- DB01: D1Database ;
26- };
27-
28- export default {
29- async fetch(request , env , ctx ): Promise <Response > {
30- const url = new URL (request .url );
31-
32- // A. Create the session.
33- // When we create a D1 session, we can continue where we left off from a previous
34- // session if we have that session's last bookmark or use a constraint.
35- const bookmark = request .headers .get (' x-d1-bookmark' ) ?? ' first-unconstrained' ;
36- const session = env .DB01 .withSession (bookmark );
37-
38- try {
39- // Use this session for all our Workers' routes.
40- const response = await withTablesInitialized (session , async () => await handleRequest (request , session ));
41-
42- // B. Return the bookmark so we can continue the session in another request.
43- response .headers .set (' x-d1-bookmark' , session .getBookmark () ?? " " );
44-
45- return response ;
46-
47- } catch (e ) {
48- console .error ({ message: " Failed to handle request" , error: String (e ), errorProps: e , url , bookmark });
49- return Response .json (
50- { error: String (e ), errorDetails: e },
51- { status: 500 }
52- );
53- }
54- },
55- } satisfies ExportedHandler <Env >;
56-
57- type Order = {
58- orderId: string ,
59- customerId: string ,
60- quantity: number ,
61- }
62-
63- async function handleRequest(request : Request , session : D1DatabaseSession ) {
64- const { pathname } = new URL (request .url );
65-
66- const tsStart = Date .now ();
67-
68- if (request .method === " GET" && pathname === ' /api/orders' ) {
69- // C. session read query.
70- const resp = await session .prepare (' SELECT * FROM Orders' ).all ();
71- return Response .json (buildResponse (session , resp , tsStart ));
72-
73- } else if (request .method === " POST" && pathname === ' /api/orders' ) {
74- const order = await request .json <Order >();
75-
76- // D. session write query.
77- // Since this is a write query, D1 will transparently forward the query.
78- await session
79- .prepare (' INSERT INTO Orders VALUES (?, ?, ?)' )
80- .bind (order .customerId , order .orderId , order .quantity )
81- .run ();
82-
83- // E. session read-after-write query.
84- // In order for the application to be correct, this SELECT
85- // statement must see the results of the INSERT statement above.
86- const resp = await session
87- .prepare (' SELECT * FROM Orders' )
88- .all ();
89-
90- return Response .json (buildResponse (session , resp , tsStart ));
91-
92- } else if (request .method === " POST" && pathname === ' /api/reset' ) {
93- const resp = await resetTables (session );
94-
95- return Response .json (buildResponse (session , resp , tsStart ));
96- }
97-
98- return new Response (' Not found' , { status: 404 })
99- }
100-
101- function buildResponse(session : D1DatabaseSession , res : D1Result , tsStart : number ) {
102- return {
103- d1Latency: Date .now () - tsStart ,
104-
105- results: res .results ,
106- servedByRegion: res .meta .served_by_region ?? " " ,
107- servedByPrimary: res .meta .served_by_primary ?? " " ,
108-
109- // Add the session bookmark inside the response body too.
110- sessionBookmark: session .getBookmark (),
111- };
112- }
113-
114- /**
115- * This is mostly for DEMO purposes to avoid having to do separate schema migrations step.
116- * This will check if the error is because our main table is missing, and if it is create the table
117- * and rerun the handler.
118- */
119- async function withTablesInitialized(session : D1DatabaseSession , handler : () => Promise <Response >) {
120- try {
121- return await handler ();
122- } catch (e ) {
123- if (String (e ).includes (" no such table: Orders: SQLITE_ERROR" )) {
124- await initTables (session );
125- return await handler ();
126- }
127- throw e ;
128- }
129- }
130-
131- async function initTables(session : D1DatabaseSession ) {
132- return await session
133- .prepare (` CREATE TABLE IF NOT EXISTS Orders(
134- customerId TEXT NOT NULL,
135- orderId TEXT NOT NULL,
136- quantity INTEGER NOT NULL,
137- PRIMARY KEY (customerId, orderId)
138- ) ` )
139- .all ();
140- }
141-
142- async function resetTables(session : D1DatabaseSession ) {
143- return await session
144- .prepare (` DROP TABLE IF EXISTS Orders; CREATE TABLE IF NOT EXISTS Orders(
145- customerId TEXT NOT NULL,
146- orderId TEXT NOT NULL,
147- quantity INTEGER NOT NULL,
148- PRIMARY KEY (customerId, orderId)
149- ) ` )
150- .all ();
151- }
152- ```
21+ <GitHubCode
22+ repo = " cloudflare/templates"
23+ file = " d1-starter-sessions-api/src/index.ts"
24+ commit = " 3912e863acedd2be2438f8758f21374ed426fc54"
25+ lang = " ts"
26+ useTypeScriptExample = { true }
27+ lines = " 7-44"
28+ />
15329
15430## Primary database instance vs read replicas
15531
@@ -587,5 +463,4 @@ You may wish to refer to the following resources:
587463- Blog: [ Building D1: a Global Database] ( https://blog.cloudflare.com/building-d1-a-global-database/ )
588464- [ D1 Sessions API documentation] ( /d1/worker-api/d1-database#withsession )
589465- [ Starter code for D1 Sessions API demo] ( https://github.com/cloudflare/templates/tree/staging/d1-starter-sessions-api )
590- - [ E-commerce store read replication demo] ( https://github.com/harshil1712/e-com-d1 )
591466- [ E-commerce store read replication tutorial] ( /d1/tutorials/using-read-replication-for-e-com )
0 commit comments