React Native
...
Cloud Functions
React Native用Parse Cloud Functionの検証とコンテキスト利用法
8 分
react nativeアプリでのcloud functionバリデーターの使用 はじめに このガイドでは、react nativeアプリからparse cloud code関数のバリデーターとコンテキストの使用方法を学びます。クラウド関数に実装されたバリデーターの例、異なる関数間でのコンテキストの使用方法、そしてこれらの改善された関数を使用してback4appでreact nativeコンポーネントを実装する方法を確認します。 前提条件 このチュートリアルを完了するには、 作成されたreact nativeアプリと back4appに接続された どのように クラウド関数をデプロイするか を理解すること。 このガイドのサンプルアプリケーションを実行したい場合は、 react native paper react native paper ライブラリ を設定する必要があります。 目標 react nativeアプリからback4appでバリデーターとコンテキストの使用を伴うparse cloud code関数を実行します。 1 cloud code関数バリデーターの理解 アプリケーションでの cloud code関数 cloud code関数 の使用は、コードに大きな柔軟性をもたらし、アプリから再利用可能なメソッドを切り離し、その動作をより良く制御することを可能にします。これらの使用方法については、 私たちのcloud関数スタートガイド https //www back4app com/docs/get started/cloud functions を確認できます。 これらのクラウド関数に送信されるデータは、予期しないエラーを避けるために検証される必要があります。parse cloud code(バージョン4 4 0以降)は、完全に統合された バリデーター バリデーター , を提供しており、これは オブジェクト オブジェクト として渡すことも、別の関数として渡すこともできます。これらのテストは、関数内のコードを実行する前に呼び出されるため、バリデーターが受け入れた場合、データが有効であると常に仮定できます。 次のクラウド関数を例として考えてみましょう。この関数では、特定の映画の評価の平均が計算されます。映画名は必須です( 映画 映画 )、そのため、次のオブジェクトを使用して渡されることを確認できます。映画パラメータが渡されない場合、関数は「検証に失敗しました。映画のデータを指定してください。」というメッセージを含むエラーを返します。 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 }); また、 バリデーター バリデーター に、関数を呼び出すユーザーが認証されていることを要求する requireuser requireuser フラグなど、より高度なオプションを渡すこともできます。もう一つの便利な追加は、次のようにパラメータ値を検証する条件を追加することです。これにより、 映画 映画 の値が文字列であり、少なくとも3文字以上であることが保証されます。 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 }); 完全な 検証 検証 オプションのリストは、parse ドキュメント https //docs parseplatform org/cloudcode/guide/#implementing cloud function validation で見ることができます。 2 クラウドコード関数のコンテキストを理解する cloud code(バージョン4 3 0以降)を使用してアプリケーション内で保存トリガーを使用する場合、 コンテキスト コンテキスト 辞書を parse object save parse object save メソッドに渡すことができ、また beforesave beforesave ハンドラーから aftersave aftersave ハンドラーに渡すこともできます。これは、データの整合性を確保したり、オブジェクトを正常に保存した後にのみ実行可能な非同期操作を実行するために使用できます。 次のクラウド関数トリガーを例に取ります。この例では、 レビュー レビュー オブジェクトが保存され、オブジェクトの保存呼び出しがアプリケーションから行われたのか、ダッシュボードから行われたのかを区別したいと考えています。これは、アプリコード内でオブジェクトを保存する前にコンテキストを設定することで実現されます。 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}); ここに保存トリガー関数があります。コンテキストオブジェクトは、両方のリクエストから直接アクセスできます。 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 react nativeコンポーネントから検証されたクラウドコードを使用する 前回の ガイド https //www back4app com/docs/react native/parse sdk/cloud functions/react native cloud functions をベースに同じコンポーネントの例を使用し、バリデーターとコンテキストを使用する関数を強調するためにいくつかの変更を加えます。ステップ1と2で示されたクラウド関数をデプロイすることを忘れず、その後、保存メソッドにコンテキスト引数を追加して「review」オブジェクト作成関数を次のように変更します 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 }; 映画の平均計算関数バリデーターを強調するために、「me」と呼ばれる映画をクエリする新しい関数を追加し、それを呼び出す別のボタンを追加します。私たちのバリデーターは映画名の長さのためにリクエストを失敗させることを忘れないでください。こちらが新しい関数のコードです 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 }; 新しい完全なコンポーネントコードがどのように配置されているかを示します。レビューがアプリケーションから作成されたかどうかを示す新しい行がリストアイテムのタイトルに表示されることに注意してください。 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 }); コンポーネントがレンダリングされ、クエリ関数の1つでクエリされた後の見た目は次のようになります 結論 このガイドの最後に、parse cloud code関数のバリデーターとコンテキストの使い方を学びました。次のガイドでは、parseでユーザーと作業する方法を学びます。