@@ -182,12 +182,18 @@ For forms that open from a menu item, you can use menu responses. This is useful
182182 <TabItem value = " hono" >
183183
184184 ``` ts title="server/index.ts"
185+ import type { MenuItemRequest , UiResponse } from ' @devvit/web/shared' ;
186+
187+ type NameFormRequest = { name: string };
188+ type ReviewFormRequest = { review: string };
189+
185190 // Menu action that triggers menu response form
186191 app .post (' /internal/menu/start-workflow' , async (c ) => {
192+ const _input = await c .req .json <MenuItemRequest >();
187193 // Server processing before showing form
188194 const userData = await fetchUserData ();
189195
190- return c .json ({
196+ return c .json < UiResponse > ({
191197 showForm: {
192198 name: ' nameForm' ,
193199 form: {
@@ -206,13 +212,13 @@ For forms that open from a menu item, you can use menu responses. This is useful
206212
207213 // Form submission handler that can chain to another form
208214 app .post (' /internal/form/name-submit' , async (c ) => {
209- const { name } = await c .req .json ();
215+ const { name } = await c .req .json < NameFormRequest > ();
210216
211217 // Server processing
212218 await saveUserName (name );
213219
214220 // Show next form in workflow
215- return c .json ({
221+ return c .json < UiResponse > ({
216222 showForm: {
217223 name: ' reviewForm' ,
218224 form: {
@@ -229,11 +235,11 @@ For forms that open from a menu item, you can use menu responses. This is useful
229235 });
230236
231237 app .post (' /internal/form/review-submit' , async (c ) => {
232- const { review } = await c .req .json ();
238+ const { review } = await c .req .json < ReviewFormRequest > ();
233239
234240 await saveReview (review );
235241
236- return c .json ({
242+ return c .json < UiResponse > ({
237243 showToast: ' Thank you for your feedback!'
238244 });
239245 });
@@ -243,10 +249,13 @@ For forms that open from a menu item, you can use menu responses. This is useful
243249 <TabItem value = " express" >
244250
245251 ``` ts title="server/index.ts"
246- import { UIResponse } from ' @devvit/web/shared' ;
252+ import type { MenuItemRequest , UiResponse } from ' @devvit/web/shared' ;
253+
254+ type NameFormRequest = { name: string };
255+ type ReviewFormRequest = { review: string };
247256
248257 // Menu action that triggers menu response form
249- router .post (" /internal/menu/start-workflow" , async (_req , res : Response < UIResponse > ) => {
258+ router .post < string , never , UiResponse , MenuItemRequest > (" /internal/menu/start-workflow" , async (_req , res ) => {
250259 // Server processing before showing form
251260 const userData = await fetchUserData ();
252261
@@ -268,7 +277,7 @@ For forms that open from a menu item, you can use menu responses. This is useful
268277 });
269278
270279 // Form submission handler that can chain to another form
271- router .post (" /internal/form/name-submit" , async (req , res : Response < UIResponse > ) => {
280+ router .post < string , never , UiResponse , NameFormRequest > (" /internal/form/name-submit" , async (req , res ) => {
272281 const { name } = req .body ;
273282
274283 // Server processing
@@ -291,7 +300,7 @@ For forms that open from a menu item, you can use menu responses. This is useful
291300 });
292301 });
293302
294- router .post (" /internal/form/review-submit" , async (req , res : Response < UIResponse > ) => {
303+ router .post < string , never , UiResponse , ReviewFormRequest > (" /internal/form/review-submit" , async (req , res ) => {
295304 const { review } = req .body ;
296305
297306 await saveReview (review );
@@ -677,11 +686,16 @@ Below is a collection of common use cases and patterns.
677686 <TabItem value = " hono" >
678687
679688 ``` ts title="server/index.ts"
689+ import type { MenuItemRequest , UiResponse } from ' @devvit/web/shared' ;
690+
691+ type DynamicFormRequest = { username: string };
692+
680693 // Endpoint that shows form with dynamic data
681694 app .post (' /internal/menu/show-dynamic-form' , async (c ) => {
695+ const _input = await c .req .json <MenuItemRequest >();
682696 const user = await reddit .getCurrentUser ();
683697
684- return c .json ({
698+ return c .json < UiResponse > ({
685699 showForm: {
686700 name: ' dynamicForm' ,
687701 form: {
@@ -702,9 +716,9 @@ Below is a collection of common use cases and patterns.
702716
703717 // Form submission handler
704718 app .post (' /internal/form/dynamic-submit' , async (c ) => {
705- const { username } = await c .req .json ();
719+ const { username } = await c .req .json < DynamicFormRequest > ();
706720
707- return c .json ({
721+ return c .json < UiResponse > ({
708722 showToast: ` Hello ${username } `
709723 });
710724 });
@@ -714,8 +728,12 @@ Below is a collection of common use cases and patterns.
714728 <TabItem value = " express" >
715729
716730 ``` ts title="server/index.ts"
731+ import type { MenuItemRequest , UiResponse } from ' @devvit/web/shared' ;
732+
733+ type DynamicFormRequest = { username: string };
734+
717735 // Endpoint that shows form with dynamic data
718- router .post (" /internal/menu/show-dynamic-form" , async (_req , res : Response < UiResponse > ) => {
736+ router .post < string , never , UiResponse , MenuItemRequest > (" /internal/menu/show-dynamic-form" , async (_req , res ) => {
719737 const user = await reddit .getCurrentUser ();
720738
721739 res .json ({
@@ -738,7 +756,7 @@ Below is a collection of common use cases and patterns.
738756 });
739757
740758 // Form submission handler
741- router .post (" /internal/form/dynamic-submit" , async (req , res : Response < UiResponse > ) => {
759+ router .post < string , never , UiResponse , DynamicFormRequest > (" /internal/form/dynamic-submit" , async (req , res ) => {
742760 const { username } = req .body ;
743761
744762 res .json ({
@@ -889,11 +907,17 @@ Below is a collection of common use cases and patterns.
889907 <TabItem value = " hono" >
890908
891909 ``` ts title="server/index.ts"
910+ import type { UiResponse } from ' @devvit/web/shared' ;
911+
912+ type Step1FormRequest = { name: string };
913+ type Step2FormRequest = { name: string ; food: string };
914+ type Step3FormRequest = { name: string ; food: string ; drink: string };
915+
892916 // Step 1: Name form
893917 app .post (' /internal/form/step1-submit' , async (c ) => {
894- const { name } = await c .req .json ();
918+ const { name } = await c .req .json < Step1FormRequest > ();
895919
896- return c .json ({
920+ return c .json < UiResponse > ({
897921 showForm: {
898922 name: ' step2Form' ,
899923 form: {
@@ -913,9 +937,9 @@ Below is a collection of common use cases and patterns.
913937
914938 // Step 2: Food form
915939 app .post (' /internal/form/step2-submit' , async (c ) => {
916- const { name, food } = await c .req .json ();
940+ const { name, food } = await c .req .json < Step2FormRequest > ();
917941
918- return c .json ({
942+ return c .json < UiResponse > ({
919943 showForm: {
920944 name: ' step3Form' ,
921945 form: {
@@ -935,9 +959,9 @@ Below is a collection of common use cases and patterns.
935959
936960 // Step 3: Final form
937961 app .post (' /internal/form/step3-submit' , async (c ) => {
938- const { name, food, drink } = await c .req .json ();
962+ const { name, food, drink } = await c .req .json < Step3FormRequest > ();
939963
940- return c .json ({
964+ return c .json < UiResponse > ({
941965 showToast: ` Thanks ${name }! You like ${food } and ${drink }. `
942966 });
943967 });
@@ -947,8 +971,14 @@ Below is a collection of common use cases and patterns.
947971 <TabItem value = " express" >
948972
949973 ``` ts title="server/index.ts"
974+ import type { UiResponse } from ' @devvit/web/shared' ;
975+
976+ type Step1FormRequest = { name: string };
977+ type Step2FormRequest = { name: string ; food: string };
978+ type Step3FormRequest = { name: string ; food: string ; drink: string };
979+
950980 // Step 1: Name form
951- router .post (" /internal/form/step1-submit" , async (req , res : Response < UiResponse > ) => {
981+ router .post < string , never , UiResponse , Step1FormRequest > (" /internal/form/step1-submit" , async (req , res ) => {
952982 const { name } = req .body ;
953983
954984 res .json ({
@@ -970,7 +1000,7 @@ Below is a collection of common use cases and patterns.
9701000 });
9711001
9721002 // Step 2: Food form
973- router .post (" /internal/form/step2-submit" , async (req , res : Response < UiResponse > ) => {
1003+ router .post < string , never , UiResponse , Step2FormRequest > (" /internal/form/step2-submit" , async (req , res ) => {
9741004 const { name, food } = req .body ;
9751005
9761006 res .json ({
@@ -992,7 +1022,7 @@ Below is a collection of common use cases and patterns.
9921022 });
9931023
9941024 // Step 3: Final form
995- router .post (" /internal/form/step3-submit" , async (req , res : Response < UiResponse > ) => {
1025+ router .post < string , never , UiResponse , Step3FormRequest > (" /internal/form/step3-submit" , async (req , res ) => {
9961026 const { name, food, drink } = req .body ;
9971027
9981028 res .json ({
@@ -1186,18 +1216,29 @@ This example includes one of each of the [supported field types](#supported-fiel
11861216 <TabItem value = " hono" >
11871217
11881218 ``` ts title="server/index.ts"
1219+ import type { MenuItemRequest , UiResponse } from ' @devvit/web/shared' ;
1220+
1221+ type EverythingFormRequest = {
1222+ food: string ;
1223+ times? : number ;
1224+ what? : string ;
1225+ healthy? : string [];
1226+ again? : boolean ;
1227+ };
1228+
11891229 app .post (' /internal/form/everything-submit' , async (c ) => {
1190- const formValues = await c .req .json ();
1230+ const formValues = await c .req .json < EverythingFormRequest > ();
11911231 console .log (' Form values:' , formValues );
11921232
1193- return c .json ({
1233+ return c .json < UiResponse > ({
11941234 showToast: ' Thanks!'
11951235 });
11961236 });
11971237
11981238 // Example showing the form
11991239 app .post (' /internal/menu/show-everything-form' , async (c ) => {
1200- return c .json ({
1240+ const _input = await c .req .json <MenuItemRequest >();
1241+ return c .json <UiResponse >({
12011242 showForm: {
12021243 name: ' everythingForm' ,
12031244 form: {
@@ -1257,7 +1298,17 @@ This example includes one of each of the [supported field types](#supported-fiel
12571298 <TabItem value = " express" >
12581299
12591300 ``` ts title="server/index.ts"
1260- router .post (" /internal/form/everything-submit" , async (req , res : Response <UiResponse >) => {
1301+ import type { MenuItemRequest , UiResponse } from ' @devvit/web/shared' ;
1302+
1303+ type EverythingFormRequest = {
1304+ food: string ;
1305+ times? : number ;
1306+ what? : string ;
1307+ healthy? : string [];
1308+ again? : boolean ;
1309+ };
1310+
1311+ router .post <string , never , UiResponse , EverythingFormRequest >(" /internal/form/everything-submit" , async (req , res ) => {
12611312 console .log (' Form values:' , req .body );
12621313
12631314 res .json ({
@@ -1266,7 +1317,7 @@ This example includes one of each of the [supported field types](#supported-fiel
12661317 });
12671318
12681319 // Example showing the form
1269- router .post (" /internal/menu/show-everything-form" , async (_req , res : Response < UiResponse > ) => {
1320+ router .post < string , never , UiResponse , MenuItemRequest > (" /internal/menu/show-everything-form" , async (_req , res ) => {
12701321 res .json ({
12711322 showForm: {
12721323 name: ' everythingForm' ,
@@ -1452,12 +1503,16 @@ This example includes one of each of the [supported field types](#supported-fiel
14521503 <TabItem value = " hono" >
14531504
14541505 ``` ts title="server/index.ts"
1506+ import type { UiResponse } from ' @devvit/web/shared' ;
1507+
1508+ type ImageFormRequest = { myImage: string };
1509+
14551510 app .post (' /internal/form/image-submit' , async (c ) => {
1456- const { myImage } = await c .req .json ();
1511+ const { myImage } = await c .req .json < ImageFormRequest > ();
14571512 // Use the mediaUrl to store in redis and display it in an <image> block, or send to external service to modify
14581513 console .log (' Image uploaded:' , myImage );
14591514
1460- return c .json ({
1515+ return c .json < UiResponse > ({
14611516 showToast: ' Image uploaded successfully!'
14621517 });
14631518 });
@@ -1467,7 +1522,11 @@ This example includes one of each of the [supported field types](#supported-fiel
14671522 <TabItem value = " express" >
14681523
14691524 ``` ts title="server/index.ts"
1470- router .post (" /internal/form/image-submit" , async (req , res : Response <UiResponse >) => {
1525+ import type { UiResponse } from ' @devvit/web/shared' ;
1526+
1527+ type ImageFormRequest = { myImage: string };
1528+
1529+ router .post <string , never , UiResponse , ImageFormRequest >(" /internal/form/image-submit" , async (req , res ) => {
14711530 const { myImage } = req .body ;
14721531 // Use the mediaUrl to store in redis and display it in an <image> block, or send to external service to modify
14731532 console .log (' Image uploaded:' , myImage );
0 commit comments