@@ -63,16 +63,26 @@ Create a file at `form/schema.ts`:
6363``` ts title:src/forms/form/schema.ts
6464import { z } from ' zod'
6565
66- export const SubmissionSchema = z .object ({
66+ export const feedbackSchema = z .object ({
6767 name: z .string (),
6868 rating: z .number ().min (1 ).max (5 ),
6969 feedback: z .string ().optional (),
7070})
7171
72- export type Submission = z .infer <typeof SubmissionSchema >
72+ export const rsvpSchema = z .object ({
73+ name: z .string (),
74+ attending: z .boolean (),
75+ guests: z .number ().int ().min (0 ),
76+ })
77+
78+ export const formSchemas: Record <string , z .ZodObject <any >> = {
79+ feedback: feedbackSchema ,
80+ rsvp: rsvpSchema ,
81+ }
7382```
7483
75- This schema ensures that any incoming submission contains a valid name, a 1–5 rating, and optional feedback.
84+ Feedback Schema: Validates that submissions include a name (string), a rating (number between 1 and 5), and optional feedback (string).
85+ RSVP Schema: Validates that submissions include a name (string), an attending status (boolean), and the number of guests (non-negative integer).
7686
7787## Step 1: Define Resources
7888
@@ -94,18 +104,28 @@ Create an API route that validates and stores form submissions, then triggers fu
94104``` ts title:services/forms.ts
95105import { api } from ' @nitric/sdk'
96106import { submissions , submitted } from ' ../resources/resources'
97- import { SubmissionSchema } from ' ../form/schema'
107+ import { formSchemas } from ' ../form/schema'
98108
99109const formApi = api (' forms' )
100110
101111formApi .post (' /forms/:formId' , async (ctx ) => {
102112 const formId = ctx .req .params .formId
103- const parsed = SubmissionSchema .safeParse (ctx .req .json ())
113+ const schema = formSchemas [formId ]
114+
115+ if (! schema ) {
116+ ctx .res .status = 400
117+ ctx .res .json ({ msg: ` Unknown formId: ${formId } ` })
118+ return
119+ }
120+
121+ const parsed = schema .safeParse (ctx .req .json ())
122+
104123 if (! parsed .success ) {
105124 ctx .res .status = 400
106125 ctx .res .json ({ msg: ' Invalid submission' , errors: parsed .error .format () })
107126 return
108127 }
128+
109129 const data = parsed .data
110130 const id = ` ${formId }-${Date .now ()} `
111131
@@ -125,7 +145,7 @@ import { receipts, submissions, output } from '../resources/resources'
125145import { buildReceipt } from ' ../form/receipt'
126146
127147receipts .subscribe (async (ctx ) => {
128- const { id } = ctx .req .json ()
148+ const { id, formId } = ctx .req .json ()
129149 const submission = await submissions .get (id )
130150
131151 if (! submission ) {
@@ -134,7 +154,7 @@ receipts.subscribe(async (ctx) => {
134154 }
135155
136156 // Build the PDF buffer from the submission data
137- const buffer = await buildReceipt (submission )
157+ const buffer = await buildReceipt (submission , formId )
138158
139159 // Store the PDF file in the bucket
140160 const file = output .file (` ${id }.pdf ` )
@@ -148,45 +168,66 @@ receipts.subscribe(async (ctx) => {
148168
149169``` ts title:form/receipt.ts
150170import PDFDocument from ' pdfkit'
151- import { Submission } from ' ./schema'
171+ import { feedbackSchema , rsvpSchema } from ' ./schema'
172+ import { z } from ' zod'
173+
174+ type FeedbackSubmission = z .infer <typeof feedbackSchema >
175+ type RsvpSubmission = z .infer <typeof rsvpSchema >
152176
153- export const buildReceipt = async (data : Submission ) => {
177+ export const buildReceipt = async (
178+ data : any ,
179+ formId : string ,
180+ ): Promise <Buffer > => {
154181 const receipt = new PDFDocument ({ bufferPages: true })
155182
156183 const doneWriting = new Promise <Buffer >((resolve ) => {
157184 const buffers: Uint8Array [] = []
158185
159- // Collect PDF output in memory as chunks
160186 receipt .on (' data' , buffers .push .bind (buffers ))
161187 receipt .on (' end' , () => {
162188 const pdfData = Buffer .concat (buffers )
163189 resolve (pdfData )
164190 })
165191
166- const { name, rating, feedback } = data
167-
168- // Write header
169192 receipt .font (' Times-Roman' ).fontSize (20 ).text (' Survey - Receipt' , 100 , 100 )
170-
171- // Write section title
172193 receipt
173194 .font (' Times-Roman' )
174195 .fontSize (16 )
175- .text (' Primary Applicant Details' , 100 , 150 )
196+ .text (' Submission Details' , 100 , 150 )
176197
177- // Write submission details
178- receipt
179- .font (' Times-Roman' )
180- .fontSize (12 )
181- .text (
182- ` Name: ${name }
198+ if (formId === ' feedback' ) {
199+ const { name, rating, feedback } = data as FeedbackSubmission
200+
201+ receipt
202+ .font (' Times-Roman' )
203+ .fontSize (12 )
204+ .text (
205+ ` Name: ${name }
183206Rating: ${rating }
184207Feedback: ${feedback || ' N/A' } ` ,
185- 100 ,
186- 175 ,
187- )
208+ 100 ,
209+ 175 ,
210+ )
211+ } else if (formId === ' rsvp' ) {
212+ const { name, attending, guests } = data as RsvpSubmission
213+
214+ receipt
215+ .font (' Times-Roman' )
216+ .fontSize (12 )
217+ .text (
218+ ` Name: ${name }
219+ Attending: ${attending ? ' Yes' : ' No' }
220+ Guests: ${guests } ` ,
221+ 100 ,
222+ 175 ,
223+ )
224+ } else {
225+ receipt
226+ .font (' Times-Roman' )
227+ .fontSize (12 )
228+ .text (' Unknown form type. No details available.' , 100 , 175 )
229+ }
188230
189- // Finalize the PDF
190231 receipt .end ()
191232 })
192233
@@ -206,7 +247,7 @@ import { receipts } from '../resources/resources'
206247receipts .subscribe (async (ctx ) => {
207248 const { id } = ctx .req .json ()
208249
209- // Handle delivery or hook into a real email/SaaS integration
250+ // Simulate delivery or hook into a real email/SaaS integration
210251 console .log (` Delivering receipt for submission: ${id } ` )
211252})
212253```
@@ -239,6 +280,8 @@ nitric start
239280
240281Use the dashboard to submit your survey data -
241282
283+ Form ID: feedback
284+
242285``` json
243286{
244287 "name" : " Jane" ,
@@ -247,10 +290,25 @@ Use the dashboard to submit your survey data -
247290}
248291```
249292
293+ Form ID: rsvp
294+
295+ ``` json
296+ {
297+ "name" : " Jane" ,
298+ "attending" : true ,
299+ "guests" : 5
300+ }
301+ ```
302+
250303![ Submit Form] ( /docs/images/guides/survey-application/submit.png )
251304
252305You should see messages in your console for PDF generation and delivery.
253306
307+ ``` bash
308+ Delivering receipt for submission: rsvp-1744131025791
309+ Receipt stored for rsvp-1744131025791
310+ ```
311+
254312### Get a Receipt
255313
256314Replace ` <timestamp> ` with the value returned from the submission.
0 commit comments