React Native
...
Cloud Functions
Validadores y contexto en Cloud Functions para React Native
10 min
uso de validadores de cloud function en una aplicación de react native introducción en esta guía, aprenderás cómo usar los validadores de funciones de cloud code de parse y el uso de contexto desde una aplicación de react native verás ejemplos de validadores implementados en funciones en la nube, cómo usar el contexto entre diferentes funciones y también comprobarás cómo implementar un componente de react native utilizando estas funciones mejoradas en back4app requisitos previos para completar este tutorial, necesitarás una aplicación de react native creada y conectada a back4app entender cómo desplegar una función en la nube en back4app si deseas ejecutar la aplicación de ejemplo de esta guía, deberías configurar el react native paper react native paper biblioteca objetivo ejecutar funciones de cloud code de parse con validadores y uso de contexto en back4app desde una aplicación de react native 1 entendiendo los validadores de funciones de cloud code usar funciones de cloud code funciones de cloud code en tu aplicación permite una gran flexibilidad en tu código, haciendo posible desacoplar métodos reutilizables de tu aplicación y controlar mejor su comportamiento puedes consultar o revisar cómo usarlos en nuestra guía de inicio de funciones en la nube https //www back4app com/docs/get started/cloud functions los datos enviados a estas funciones en la nube deben ser validados para evitar errores inesperados, y parse cloud code (a partir de la versión 4 4 0) ofrece validadores validadores , que pueden ser pasados como un objeto objeto o incluso otra función estas pruebas se llaman antes de ejecutar cualquier código dentro de tu función, por lo que siempre puedes asumir que los datos serán válidos si los validadores los aceptan toma la siguiente función en la nube como ejemplo, en la que se calcula el promedio de una cierta calificación de película el nombre de la película es requerido( película película ), por lo que puedes usar el siguiente objeto para asegurarte de que se pase si el parámetro de la película no se pasa, la función devolverá un error que contiene el mensaje “la validación falló por favor especifica datos para la película ” 1 parse cloud define('getmovieaveragerating', async (request) => { 2 const query = new parse query("review"); 3 query equalto("movie", request params movie); 4 const results = await query find(); 5 let sum = 0; 6 for (let review of results) { 7 sum += review\ get("rate"); 8 } 9 return { 10 result sum / results length, 11 }; 12 },{ 13 fields \['movie'], 14 }); también puedes pasar opciones más avanzadas al validador validador , como requerir que el usuario que llama a la función esté autenticado usando el requireuser requireuser flag otra adición útil es agregar una condición para validar el valor de un parámetro, como la siguiente, asegurando que el valor de la película película sea una cadena y tenga al menos 3 caracteres de longitud 1 parse cloud define('getmovieaveragerating', async (request) => { 2 const query = new parse query("review"); 3 query equalto("movie", request params movie); 4 const results = await query find(); 5 let sum = 0; 6 for (let review of results) { 7 sum += review\ get("rate"); 8 } 9 return { 10 result sum / results length, 11 }; 12 },{ 13 fields { 14 movie { 15 required true, 16 type string, 17 options val => { 18 return val length >= 3; 19 }, 20 error 'movie must have at least 3 characters' 21 } 22 }, 23 }); la lista completa de validación validación opciones se puede ver en la documentación https //docs parseplatform org/cloudcode/guide/#implementing cloud function validation 2 entendiendo el contexto de las funciones de cloud code al usar cloud code (a partir de la versión 4 3 0) los triggers de guardado en tu aplicación, puedes pasar un contexto contexto en el parse object save parse object save método y también pasarlo desde un beforesave beforesave manejador a un aftersave aftersave manejador esto se puede usar para asegurar la consistencia de los datos o para realizar cualquier tipo de operación asíncrona que solo se puede hacer después de guardar exitosamente tu objeto toma el siguiente desencadenador de función en la nube como ejemplo, en el que un revisión revisión objeto se guarda y queremos diferenciar si la llamada de guardado del objeto se realizó desde tu aplicación o desde el panel de control esto se logrará configurando el contexto antes de guardar el objeto en el código de tu aplicación de la siguiente manera 1 const review = new parse object('review'); 2 review\ set('text', 'great movie!'); 3 review\ set('rate', 5); 4 review\ set('movie', 'mission very possible'); 5	 6 const context = { fromapplication true }; 7 const savedreview = await review\ save(null, {context context}); aquí están las funciones de desencadenador de guardado, ten en cuenta que el objeto de contexto se puede acceder directamente desde la solicitud en ambas 1 parse cloud beforesave('review', async (request) => { 2 // try to get context 3 try { 4 const context = request context; 5 if (context fromapplication === true) { 6 // set a flag in the object before saving 7 request object set('fromapplication', true); 8 } 9 } catch(error){} 10	 11 const text = request object get('text'); 12 if (text length > 20) { 13 // truncate and add a 14 request object set('text', text substring(0, 17) + ' '); 15 } 16 }); 17	 18 parse cloud aftersave('review', async (request) => { 19 // try to get context 20 try { 21 const context = request context; 22 if (context fromapplication === true) { 23 // do something when coming from application, like sending a notification or email 24 console log('got context fromapplication when saving review object'); 25 } 26 } catch(error){} 27 }); 3 usando código en la nube validado desde un componente de react native ahora usemos el mismo ejemplo de componente de la última guía https //www back4app com/docs/react native/parse sdk/cloud functions/react native cloud functions como base y agreguemos algunos cambios para resaltar las funciones que ahora utilizan validadores y contexto recuerde desplegar las funciones en la nube mostradas en los pasos 1 y 2 y, después de eso, cambie la función de creación del objeto “revisión” a la siguiente, con la adición del argumento de contexto en el método de guardado javascript 1 const createreview = async function () { 2 try { 3 // this values come from state variables linked to 4 // the screen form fields 5 const reviewtextvalue = reviewtext; 6 const reviewratevalue = number(reviewrate); 7	 8 // creates a new parse object instance 9 let review = new parse object('review'); 10	 11 // set data to parse object 12 // simple title field 13 review\ set('text', reviewtextvalue); 14	 15 // simple number field 16 review\ set('rate', reviewratevalue); 17	 18 // set default movie 19 review\ set('movie', 'mission very possible'); 20	 21 // after setting the values, save it on the server 22 try { 23 // add 24 const context = {fromapplication true}; 25 await review\ save(null, {context context}); 26 // success 27 alert alert('success!'); 28 // updates query result list 29 doreviewquery(); 30 rungetmovieaveragerating(); 31 return true; 32 } catch (error) { 33 // error can be caused by lack of internet connection 34 alert alert('error!', error message); 35 return false; 36 } 37 } catch (error) { 38 // error can be caused by lack of field values 39 alert alert('error!', error message); 40 return false; 41 } 42 };1 const createreview = async function () promise\<boolean> { 2 try { 3 // this values come from state variables linked to 4 // the screen form fields 5 const reviewtextvalue string = reviewtext; 6 const reviewratevalue number = number(reviewrate); 7	 8 // creates a new parse object instance 9 let review parse object = new parse object('review'); 10	 11 // set data to parse object 12 // simple title field 13 review\ set('text', reviewtextvalue); 14	 15 // simple number field 16 review\ set('rate', reviewratevalue); 17	 18 // set default movie 19 review\ set('movie', 'mission very possible'); 20	 21 // after setting the values, save it on the server 22 try { 23 const context = {fromapplication true}; 24 await review\ save(null, {context context}); 25 // success 26 alert alert('success!'); 27 // updates query result list 28 doreviewquery(); 29 rungetmovieaveragerating(); 30 return true; 31 } catch (error) { 32 // error can be caused by lack of internet connection 33 alert alert('error!', error message); 34 return false; 35 } 36 } catch (error) { 37 // error can be caused by lack of field values 38 alert alert('error!', error message); 39 return false; 40 } 41 }; para resaltar la función validadora de cálculo del promedio de la película, agrega una nueva función que consulte una película llamada “yo” y agrega otro botón que la llame recuerda que nuestro validador hará que la solicitud falle debido a la longitud del nombre de la película aquí está el nuevo código de la función javascript 1 const createreview = async function () { 2 try { 3 // this values come from state variables linked to 4 // the screen form fields 5 const reviewtextvalue = reviewtext; 6 const reviewratevalue = number(reviewrate); 7	 8 // creates a new parse object instance 9 let review = new parse object('review'); 10	 11 // set data to parse object 12 // simple title field 13 review\ set('text', reviewtextvalue); 14	 15 // simple number field 16 review\ set('rate', reviewratevalue); 17	 18 // set default movie 19 review\ set('movie', 'mission very possible'); 20	 21 // after setting the values, save it on the server 22 try { 23 // add 24 const context = {fromapplication true}; 25 await review\ save(null, {context context}); 26 // success 27 alert alert('success!'); 28 // updates query result list 29 doreviewquery(); 30 rungetmovieaveragerating(); 31 return true; 32 } catch (error) { 33 // error can be caused by lack of internet connection 34 alert alert('error!', error message); 35 return false; 36 } 37 } catch (error) { 38 // error can be caused by lack of field values 39 alert alert('error!', error message); 40 return false; 41 } 42 };1 const createreview = async function () promise\<boolean> { 2 try { 3 // this values come from state variables linked to 4 // the screen form fields 5 const reviewtextvalue string = reviewtext; 6 const reviewratevalue number = number(reviewrate); 7	 8 // creates a new parse object instance 9 let review parse object = new parse object('review'); 10	 11 // set data to parse object 12 // simple title field 13 review\ set('text', reviewtextvalue); 14	 15 // simple number field 16 review\ set('rate', reviewratevalue); 17	 18 // set default movie 19 review\ set('movie', 'mission very possible'); 20	 21 // after setting the values, save it on the server 22 try { 23 const context = {fromapplication true}; 24 await review\ save(null, {context context}); 25 // success 26 alert alert('success!'); 27 // updates query result list 28 doreviewquery(); 29 rungetmovieaveragerating(); 30 return true; 31 } catch (error) { 32 // error can be caused by lack of internet connection 33 alert alert('error!', error message); 34 return false; 35 } 36 } catch (error) { 37 // error can be caused by lack of field values 38 alert alert('error!', error message); 39 return false; 40 } 41 }; así es como se organiza el nuevo código completo del componente, note que hay una nueva línea en el título del elemento de la lista que muestra si la revisión fue creada desde la aplicación o no javascript 1 import react, {usestate} from 'react'; 2 import {alert, image, view, scrollview, stylesheet} from 'react native'; 3 import parse from 'parse/react native'; 4 import { 5 list, 6 title, 7 textinput as papertextinput, 8 button as paperbutton, 9 text as papertext, 10 } from 'react native paper'; 11	 12 export const movieratings = () => { 13 // state variable 14 const \[queryresults, setqueryresults] = usestate(null); 15 const \[ratingsaverage, setratingsaverage] = usestate(''); 16 const \[reviewtext, setreviewtext] = usestate(''); 17 const \[reviewrate, setreviewrate] = usestate(''); 18	 19 const rungetmovieaveragerating = async function () { 20 try { 21 const params = { 22 movie 'mission very possible', 23 }; 24 let resultobject = await parse cloud run( 25 'getmovieaveragerating', 26 params, 27 ); 28 // set query results to state variable using state hook 29 setratingsaverage(resultobject result tofixed(1)); 30 return true; 31 } catch (error) { 32 // error can be caused by lack of internet connection 33 // or by not having an valid review object yet 34 alert alert( 35 'error!', 36 'make sure that the cloud function is deployed and that the review class table is created', 37 ); 38 return false; 39 } 40 }; 41	 42 const rungetmemovieaveragerating = async function () { 43 try { 44 const params = { 45 movie 'me', 46 }; 47 let resultobject = await parse cloud run( 48 'getmovieaveragerating', 49 params, 50 ); 51 return true; 52 } catch (error) { 53 // error can be caused by lack of internet connection 54 // or by not having an valid review object yet 55 alert alert('error!', json stringify(error message)); 56 return false; 57 } 58 }; 59	 60 const doreviewquery = async function () { 61 // create our query 62 let parsequery = new parse query('review'); 63 try { 64 let results = await parsequery find(); 65 // set query results to state variable 66 setqueryresults(results); 67 return true; 68 } catch (error) { 69 // error can be caused by lack of internet connection 70 alert alert('error!', error message); 71 return false; 72 } 73 }; 74	 75 const createreview = async function () { 76 try { 77 // this values come from state variables linked to 78 // the screen form fields 79 const reviewtextvalue = reviewtext; 80 const reviewratevalue = number(reviewrate); 81	 82 // creates a new parse object instance 83 let review = new parse object('review'); 84	 85 // set data to parse object 86 // simple title field 87 review\ set('text', reviewtextvalue); 88	 89 // simple number field 90 review\ set('rate', reviewratevalue); 91	 92 // set default movie 93 review\ set('movie', 'mission very possible'); 94	 95 // after setting the values, save it on the server 96 try { 97 const context = {fromapplication true}; 98 await review\ save(null, {context context}); 99 // success 100 alert alert('success!'); 101 // updates query result list 102 doreviewquery(); 103 rungetmovieaveragerating(); 104 return true; 105 } catch (error) { 106 // error can be caused by lack of internet connection 107 alert alert('error!', error message); 108 return false; 109 } 110 } catch (error) { 111 // error can be caused by lack of field values 112 alert alert('error!', error message); 113 return false; 114 } 115 }; 116	 117 return ( 118 <> 119 \<view style={styles header}> 120 \<image 121 style={styles header logo} 122 source={ {uri 'https //blog back4app com/wp content/uploads/2019/05/back4app white logo 500px png',} } 123 /> 124 \<papertext style={styles header text}> 125 \<papertext style={styles header text bold}> 126 {'react native on back4app '} 127 \</papertext> 128 {' cloud code movie ratings'} 129 \</papertext> 130 \</view> 131 \<scrollview style={styles wrapper}> 132 \<view> 133 \<title>{'mission very possible reviews'}\</title> 134 \<papertext>{`ratings average ${ratingsaverage}`}\</papertext> 135 {/ query list /} 136 {queryresults !== null && 137 queryresults !== undefined && 138 queryresults map((result) => ( 139 \<list item 140 key={result id} 141 title={`review text ${result get('text')}`} 142 description={`rate ${result get('rate')}\nfrom app ${ 143 result get('fromapplication') !== undefined ? 'yes' 'no' 144 }`} 145 titlestyle={styles list text} 146 style={styles list item} 147 /> 148 ))} 149 {queryresults === null || 150 queryresults === undefined || 151 (queryresults !== null && 152 queryresults !== undefined && 153 queryresults length <= 0) ? ( 154 \<papertext>{'no results here!'}\</papertext> 155 ) null} 156 \</view> 157 \<view> 158 \<title>action buttons\</title> 159 \<paperbutton 160 onpress={() => rungetmovieaveragerating()} 161 mode="contained" 162 icon="search web" 163 color={'#208aec'} 164 style={styles list button}> 165 {'calculate review average'} 166 \</paperbutton> 167 \<paperbutton 168 onpress={() => rungetmemovieaveragerating()} 169 mode="contained" 170 icon="search web" 171 color={'#208aec'} 172 style={styles list button}> 173 {'calculate me movie review average'} 174 \</paperbutton> 175 \<paperbutton 176 onpress={() => doreviewquery()} 177 mode="contained" 178 icon="search web" 179 color={'#208aec'} 180 style={styles list button}> 181 {'query reviews'} 182 \</paperbutton> 183 \</view> 184 \<view> 185 \<title>add new review\</title> 186 \<papertextinput 187 value={reviewtext} 188 onchangetext={text => setreviewtext(text)} 189 label="text" 190 mode="outlined" 191 style={styles form input} 192 /> 193 \<papertextinput 194 value={reviewrate} 195 onchangetext={text => setreviewrate(text)} 196 keyboardtype={'number pad'} 197 label="rate (1 5)" 198 mode="outlined" 199 style={styles form input} 200 /> 201 \<paperbutton 202 onpress={() => createreview()} 203 mode="contained" 204 icon="plus" 205 style={styles submit button}> 206 {'add'} 207 \</paperbutton> 208 \</view> 209 \</scrollview> 210 \</> 211 ); 212 }; 213	 214 // these define the screen component styles 215 const styles = stylesheet create({ 216 header { 217 alignitems 'center', 218 paddingtop 30, 219 paddingbottom 50, 220 backgroundcolor '#208aec', 221 }, 222 header logo { 223 height 50, 224 width 220, 225 resizemode 'contain', 226 }, 227 header text { 228 margintop 15, 229 color '#f0f0f0', 230 fontsize 16, 231 }, 232 header text bold { 233 color '#fff', 234 fontweight 'bold', 235 }, 236 wrapper { 237 width '90%', 238 alignself 'center', 239 }, 240 list button { 241 margintop 6, 242 marginleft 15, 243 height 40, 244 }, 245 list item { 246 borderbottomwidth 1, 247 borderbottomcolor 'rgba(0, 0, 0, 0 12)', 248 }, 249 list text { 250 fontsize 15, 251 }, 252 form input { 253 height 44, 254 marginbottom 16, 255 backgroundcolor '#fff', 256 fontsize 14, 257 }, 258 submit button { 259 width '100%', 260 maxheight 50, 261 alignself 'center', 262 backgroundcolor '#208aec', 263 }, 264 });1 import react, {fc, reactelement, usestate} from 'react'; 2 import {alert, image, view, scrollview, stylesheet} from 'react native'; 3 import parse from 'parse/react native'; 4 import { 5 list, 6 title, 7 textinput as papertextinput, 8 button as paperbutton, 9 text as papertext, 10 } from 'react native paper'; 11	 12 export const movieratings fc<{}> = ({}) reactelement => { 13 // state variable 14 const \[queryresults, setqueryresults] = usestate(null); 15 const \[ratingsaverage, setratingsaverage] = usestate(''); 16 const \[reviewtext, setreviewtext] = usestate(''); 17 const \[reviewrate, setreviewrate] = usestate(''); 18	 19 const rungetmovieaveragerating = async function () promise\<boolean> { 20 try { 21 const params {movie string} = { 22 movie 'mission very possible', 23 }; 24 let resultobject {result number} = await parse cloud run( 25 'getmovieaveragerating', 26 params, 27 ); 28 // set query results to state variable using state hook 29 setratingsaverage(resultobject result tofixed(1)); 30 return true; 31 } catch (error) { 32 // error can be caused by lack of internet connection 33 // or by not having an valid review object yet 34 alert alert( 35 'error!', 36 'make sure that the cloud function is deployed and that the review class table is created', 37 ); 38 return false; 39 } 40 }; 41	 42 const rungetmemovieaveragerating = async function () promise\<boolean> { 43 try { 44 const params {movie string} = { 45 movie 'me', 46 }; 47 let resultobject object = await parse cloud run( 48 'getmovieaveragerating', 49 params, 50 ); 51 return true; 52 } catch (error) { 53 // error can be caused by lack of internet connection 54 // or by not having an valid review object yet 55 alert alert('error!', json stringify(error message)); 56 return false; 57 } 58 }; 59	 60 const doreviewquery = async function () promise\<boolean> { 61 // create our query 62 let parsequery parse query = new parse query('review'); 63 try { 64 let results \[parse object] = await parsequery find(); 65 // set query results to state variable 66 setqueryresults(results); 67 return true; 68 } catch (error) { 69 // error can be caused by lack of internet connection 70 alert alert('error!', error message); 71 return false; 72 } 73 }; 74	 75 const createreview = async function () promise\<boolean> { 76 try { 77 // this values come from state variables linked to 78 // the screen form fields 79 const reviewtextvalue string = reviewtext; 80 const reviewratevalue number = number(reviewrate); 81	 82 // creates a new parse object instance 83 let review parse object = new parse object('review'); 84	 85 // set data to parse object 86 // simple title field 87 review\ set('text', reviewtextvalue); 88	 89 // simple number field 90 review\ set('rate', reviewratevalue); 91	 92 // set default movie 93 review\ set('movie', 'mission very possible'); 94	 95 // after setting the values, save it on the server 96 try { 97 const context = {fromapplication true}; 98 await review\ save(null, {context context}); 99 // success 100 alert alert('success!'); 101 // updates query result list 102 doreviewquery(); 103 rungetmovieaveragerating(); 104 return true; 105 } catch (error) { 106 // error can be caused by lack of internet connection 107 alert alert('error!', error message); 108 return false; 109 } 110 } catch (error) { 111 // error can be caused by lack of field values 112 alert alert('error!', error message); 113 return false; 114 } 115 }; 116	 117 return ( 118 <> 119 \<view style={styles header}> 120 \<image 121 style={styles header logo} 122 source={ { 123 uri 124 'https //blog back4app com/wp content/uploads/2019/05/back4app white logo 500px png', 125 } } 126 /> 127 \<papertext style={styles header text}> 128 \<papertext style={styles header text bold}> 129 {'react native on back4app '} 130 \</papertext> 131 {' cloud code movie ratings'} 132 \</papertext> 133 \</view> 134 \<scrollview style={styles wrapper}> 135 \<view> 136 \<title>{'mission very possible reviews'}\</title> 137 \<papertext>{`ratings average ${ratingsaverage}`}\</papertext> 138 {/ query list /} 139 {queryresults !== null && 140 queryresults !== undefined && 141 queryresults map((result parse object) => ( 142 \<list item 143 key={result id} 144 title={`review text ${result get('text')}`} 145 description={`rate ${result get('rate')}\nfrom app ${ 146 result get('fromapplication') !== undefined ? 'yes' 'no' 147 }`} 148 titlestyle={styles list text} 149 style={styles list item} 150 /> 151 ))} 152 {queryresults === null || 153 queryresults === undefined || 154 (queryresults !== null && 155 queryresults !== undefined && 156 queryresults length <= 0) ? ( 157 \<papertext>{'no results here!'}\</papertext> 158 ) null} 159 \</view> 160 \<view> 161 \<title>action buttons\</title> 162 \<paperbutton 163 onpress={() => rungetmovieaveragerating()} 164 mode="contained" 165 icon="search web" 166 color={'#208aec'} 167 style={styles list button}> 168 {'calculate review average'} 169 \</paperbutton> 170 \<paperbutton 171 onpress={() => rungetmemovieaveragerating()} 172 mode="contained" 173 icon="search web" 174 color={'#208aec'} 175 style={styles list button}> 176 {'calculate me movie review average'} 177 \</paperbutton> 178 \<paperbutton 179 onpress={() => doreviewquery()} 180 mode="contained" 181 icon="search web" 182 color={'#208aec'} 183 style={styles list button}> 184 {'query reviews'} 185 \</paperbutton> 186 \</view> 187 \<view> 188 \<title>add new review\</title> 189 \<papertextinput 190 value={reviewtext} 191 onchangetext={text => setreviewtext(text)} 192 label="text" 193 mode="outlined" 194 style={styles form input} 195 /> 196 \<papertextinput 197 value={reviewrate} 198 onchangetext={text => setreviewrate(text)} 199 keyboardtype={'number pad'} 200 label="rate (1 5)" 201 mode="outlined" 202 style={styles form input} 203 /> 204 \<paperbutton 205 onpress={() => createreview()} 206 mode="contained" 207 icon="plus" 208 style={styles submit button}> 209 {'add'} 210 \</paperbutton> 211 \</view> 212 \</scrollview> 213 \</> 214 ); 215 }; 216	 217 // these define the screen component styles 218 const styles = stylesheet create({ 219 header { 220 alignitems 'center', 221 paddingtop 30, 222 paddingbottom 50, 223 backgroundcolor '#208aec', 224 }, 225 header logo { 226 height 50, 227 width 220, 228 resizemode 'contain', 229 }, 230 header text { 231 margintop 15, 232 color '#f0f0f0', 233 fontsize 16, 234 }, 235 header text bold { 236 color '#fff', 237 fontweight 'bold', 238 }, 239 wrapper { 240 width '90%', 241 alignself 'center', 242 }, 243 list button { 244 margintop 6, 245 marginleft 15, 246 height 40, 247 }, 248 list item { 249 borderbottomwidth 1, 250 borderbottomcolor 'rgba(0, 0, 0, 0 12)', 251 }, 252 list text { 253 fontsize 15, 254 }, 255 form input { 256 height 44, 257 marginbottom 16, 258 backgroundcolor '#fff', 259 fontsize 14, 260 }, 261 submit button { 262 width '100%', 263 maxheight 50, 264 alignself 'center', 265 backgroundcolor '#208aec', 266 }, 267 }); así es como debería verse el componente después de renderizar y consultar mediante una de las funciones de consulta conclusión al final de esta guía, aprendiste cómo usar los validadores de funciones de código en la nube de parse y el contexto en la próxima guía, aprenderás cómo trabajar con usuarios en parse