Jekyll2022-05-05T02:06:50+00:00https://mossgreen.github.io/feed.xmlMoss GUCode matters.Moss GUmossgu@outlook.comhttps://mossgreen.github.ioAdd CloudWatch Alarms to A Lambda Function2021-12-12T00:00:00+00:002021-12-12T00:00:00+00:00https://mossgreen.github.io/Add-CloudWatch-Alarm-for-Your-Lambda-Function<p>Better monitoring your app.</p>
<h2 id="jargons">Jargons</h2>
<h2 id="what-alarms-do-you-want-to-set-for-you-service">What alarms do you want to set for you service</h2>
<p><img src="https://user-images.githubusercontent.com/73862580/150747559-84742745-663e-47bc-9db8-6eff11dcf58c.png" alt="image" /></p>
<h3 id="we-want-to-alarm-errors-on-lambda-yes-we-do">we want to alarm Errors on Lambda, yes we do</h3>
<p>Function errors include</p>
<ul>
<li>exceptions that your code throws, e.g., 4xx and 5xx exception</li>
<li>exceptions that the Lambda runtime throws.</li>
</ul>
<p>lambda itself doesn’t have 4xx and 5xx metrics.</p>
<h3 id="we-want-to-alarm-4xx-and-5xx-errors-on-the-api-gateway">we want to alarm 4XX and 5XX errors on the API Gateway</h3>
<p>(Why do we want to set alarms on API Gateway even though we already have alarms on the Lambda side?)</p>
<ul>
<li>We want to set an alarm on 5XX error. We have to do it on the API gateway</li>
<li>Sometimes, Lambda successfully returns a response, however, it exceeds API Gateway’s 29s limit, it won’t trigger the alarm on the Lambda side</li>
<li>we want to set up alarms for 4xx response too. Because we can monitor a DDos attack if there are too many 4xx responses in a short period of time</li>
</ul>
<h2 id="evaluating-an-alarm">Evaluating an alarm</h2>
<p>see: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/AlarmThatSendsEmail.html#alarm-evaluation</p>
<p>When you create an alarm, you specify three settings:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">Period</code> is the length of time to evaluate the metric, in seconds.</li>
<li><code class="language-plaintext highlighter-rouge">Evaluation Periods</code> is the number of the most recent periods.</li>
<li><code class="language-plaintext highlighter-rouge">Datapoints</code> to Alarm is the number of data points within the Evaluation Periods that must be breaching to cause the alarm to go to the ALARM state.</li>
<li><code class="language-plaintext highlighter-rouge">Statistic</code> should use <code class="language-plaintext highlighter-rouge">Sum</code> in the following cases. <code class="language-plaintext highlighter-rouge">Minium</code> won’t work because it always equals to <code class="language-plaintext highlighter-rouge">0</code>.</li>
</ul>
<h2 id="with-sam">With SAM</h2>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">MyFunctionErrorsAlarm</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::CloudWatch::Alarm'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">ActionsEnabled</span><span class="pi">:</span> <span class="no">true</span>
<span class="na">AlarmDescription</span><span class="pi">:</span> <span class="s1">'</span><span class="s">My</span><span class="nv"> </span><span class="s">Function</span><span class="nv"> </span><span class="s">Errors'</span>
<span class="na">ComparisonOperator</span><span class="pi">:</span> <span class="s">GreaterThanOrEqualToThreshold</span>
<span class="na">Dimensions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">Name</span><span class="pi">:</span> <span class="s">FunctionName</span>
<span class="na">Value</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">${AWS::StackName}-v1"</span>
<span class="na">EvaluationPeriods</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">MetricName</span><span class="pi">:</span> <span class="s">Errors</span>
<span class="na">Namespace</span><span class="pi">:</span> <span class="s">AWS/Lambda</span>
<span class="na">Statistic</span><span class="pi">:</span> <span class="s">Sum</span>
<span class="na">Period</span><span class="pi">:</span> <span class="m">60</span>
<span class="na">Threshold</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">TreatMissingData</span><span class="pi">:</span> <span class="s">notBreaching</span>
<span class="na">AlarmActions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="kt">!Sub</span> <span class="s1">'</span><span class="s">arn:aws:sns:${AWS::Region}:${AWS::AccountId}:MyCompany_Cloudwatch_Alarms_Topic'</span>
<span class="na">MyApiGateway5XXErrorAlarm</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::CloudWatch::Alarm'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">ActionsEnabled</span><span class="pi">:</span> <span class="no">true</span>
<span class="na">AlarmDescription</span><span class="pi">:</span> <span class="s1">'</span><span class="s">My-Blah-api-v1</span><span class="nv"> </span><span class="s">ApiGateway</span><span class="nv"> </span><span class="s">5XXError'</span>
<span class="na">ComparisonOperator</span><span class="pi">:</span> <span class="s">GreaterThanOrEqualToThreshold</span>
<span class="na">Dimensions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">Name</span><span class="pi">:</span> <span class="s">ApiName</span>
<span class="na">Value</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">${AWS::StackName}-api-v1"</span>
<span class="na">EvaluationPeriods</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">MetricName</span><span class="pi">:</span> <span class="s">5XXError</span>
<span class="na">Namespace</span><span class="pi">:</span> <span class="s">AWS/ApiGateway</span>
<span class="na">Statistic</span><span class="pi">:</span> <span class="s">Sum</span>
<span class="na">Period</span><span class="pi">:</span> <span class="m">60</span>
<span class="na">Threshold</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">TreatMissingData</span><span class="pi">:</span> <span class="s">notBreaching</span>
<span class="na">AlarmActions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="kt">!Sub</span> <span class="s1">'</span><span class="s">arn:aws:sns:${AWS::Region}:${AWS::AccountId}:MyCompany_Cloudwatch_Alarms_Topic'</span>
<span class="err"> </span><span class="na">MyApiGateway4XXErrorAlarm</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::CloudWatch::Alarm'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">ActionsEnabled</span><span class="pi">:</span> <span class="no">true</span>
<span class="na">AlarmDescription</span><span class="pi">:</span> <span class="s1">'</span><span class="s">My-Blah-api-v1</span><span class="nv"> </span><span class="s">ApiGateway</span><span class="nv"> </span><span class="s">4XXError'</span>
<span class="na">ComparisonOperator</span><span class="pi">:</span> <span class="s">GreaterThanOrEqualToThreshold</span>
<span class="na">Dimensions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">Name</span><span class="pi">:</span> <span class="s">ApiName</span>
<span class="na">Value</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">${AWS::StackName}-api-v1"</span>
<span class="na">EvaluationPeriods</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">MetricName</span><span class="pi">:</span> <span class="s">4XXError</span>
<span class="na">Namespace</span><span class="pi">:</span> <span class="s">AWS/ApiGateway</span>
<span class="na">Statistic</span><span class="pi">:</span> <span class="s">Sum</span>
<span class="na">Period</span><span class="pi">:</span> <span class="m">60</span>
<span class="na">Threshold</span><span class="pi">:</span> <span class="m">20</span>
<span class="na">TreatMissingData</span><span class="pi">:</span> <span class="s">notBreaching</span>
<span class="na">AlarmActions</span><span class="pi">:</span>
<span class="pi">-</span> <span class="kt">!Sub</span> <span class="s1">'</span><span class="s">arn:aws:sns:${AWS::Region}:${AWS::AccountId}:MyCompany_Cloudwatch_Alarms_Topic'</span>
</code></pre></div></div>
<p>about <code class="language-plaintext highlighter-rouge">Dimensions</code></p>
<ul>
<li>current example is to pass in the function name (Lambda) to monitor</li>
<li>
<p>if you want to monitor on an API gateway, you can do this way</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">Name</span><span class="pi">:</span> <span class="s">ApiName</span>
<span class="na">Value</span><span class="pi">:</span> <span class="kt">!Sub</span> <span class="s2">"</span><span class="s">${AWS::StackName}-api-v1"</span>
</code></pre></div> </div>
</li>
</ul>
<h2 id="with-cdk">With CDK</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">private</span> <span class="kt">void</span> <span class="nf">buildCloudwatchAlarm</span><span class="o">(</span><span class="nc">Function</span> <span class="n">function</span><span class="o">,</span> <span class="nc">RestApi</span> <span class="n">api</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">var</span> <span class="n">internalServerErrorMetric</span> <span class="o">=</span> <span class="nc">MetricFilter</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"LambdaErrorLogMetric"</span><span class="o">)</span>
<span class="o">.</span><span class="na">metricName</span><span class="o">(</span><span class="s">"MyApiLambdaErrors"</span><span class="o">)</span>
<span class="o">.</span><span class="na">metricNamespace</span><span class="o">(</span><span class="s">"my-project/Lambda"</span><span class="o">)</span>
<span class="o">.</span><span class="na">filterPattern</span><span class="o">(</span><span class="nc">FilterPattern</span><span class="o">.</span><span class="na">anyTerm</span><span class="o">(</span><span class="s">"ERROR"</span><span class="o">))</span>
<span class="o">.</span><span class="na">logGroup</span><span class="o">(</span><span class="n">function</span><span class="o">.</span><span class="na">getLogGroup</span><span class="o">())</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="kt">var</span> <span class="n">alarms</span> <span class="o">=</span> <span class="nc">List</span><span class="o">.</span><span class="na">of</span><span class="o">(</span>
<span class="nc">Alarm</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"LambdaFailureAlarm"</span><span class="o">)</span>
<span class="o">.</span><span class="na">metric</span><span class="o">(</span><span class="n">function</span><span class="o">.</span><span class="na">metricErrors</span><span class="o">())</span>
<span class="o">.</span><span class="na">threshold</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">comparisonOperator</span><span class="o">(</span><span class="nc">ComparisonOperator</span><span class="o">.</span><span class="na">GREATER_THAN_OR_EQUAL_TO_THRESHOLD</span><span class="o">)</span>
<span class="o">.</span><span class="na">alarmDescription</span><span class="o">(</span><span class="s">"My Api lambda failure"</span><span class="o">)</span>
<span class="o">.</span><span class="na">evaluationPeriods</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">treatMissingData</span><span class="o">(</span><span class="nc">TreatMissingData</span><span class="o">.</span><span class="na">NOT_BREACHING</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">(),</span>
<span class="nc">Alarm</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"ApiGateway4XXAlarm"</span><span class="o">)</span>
<span class="o">.</span><span class="na">metric</span><span class="o">(</span><span class="n">api</span><span class="o">.</span><span class="na">metricClientError</span><span class="o">())</span>
<span class="o">.</span><span class="na">threshold</span><span class="o">(</span><span class="mi">20</span><span class="o">)</span>
<span class="o">.</span><span class="na">comparisonOperator</span><span class="o">(</span><span class="nc">ComparisonOperator</span><span class="o">.</span><span class="na">GREATER_THAN_OR_EQUAL_TO_THRESHOLD</span><span class="o">)</span>
<span class="o">.</span><span class="na">alarmDescription</span><span class="o">(</span><span class="s">"High number of Api Gateway 4xx failures"</span><span class="o">)</span>
<span class="o">.</span><span class="na">evaluationPeriods</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">treatMissingData</span><span class="o">(</span><span class="nc">TreatMissingData</span><span class="o">.</span><span class="na">NOT_BREACHING</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">(),</span>
<span class="nc">Alarm</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"ApiGateway5XXAlarm"</span><span class="o">)</span>
<span class="o">.</span><span class="na">metric</span><span class="o">(</span><span class="n">api</span><span class="o">.</span><span class="na">metricServerError</span><span class="o">())</span>
<span class="o">.</span><span class="na">threshold</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">comparisonOperator</span><span class="o">(</span><span class="nc">ComparisonOperator</span><span class="o">.</span><span class="na">GREATER_THAN_OR_EQUAL_TO_THRESHOLD</span><span class="o">)</span>
<span class="o">.</span><span class="na">alarmDescription</span><span class="o">(</span><span class="s">"My Api Gateway 5xx failures"</span><span class="o">)</span>
<span class="o">.</span><span class="na">evaluationPeriods</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">treatMissingData</span><span class="o">(</span><span class="nc">TreatMissingData</span><span class="o">.</span><span class="na">NOT_BREACHING</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">(),</span>
<span class="nc">Alarm</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"LambdaDurationAlarm"</span><span class="o">)</span>
<span class="o">.</span><span class="na">metric</span><span class="o">(</span><span class="n">function</span><span class="o">.</span><span class="na">metricDuration</span><span class="o">())</span>
<span class="o">.</span><span class="na">threshold</span><span class="o">(</span><span class="nc">Duration</span><span class="o">.</span><span class="na">seconds</span><span class="o">(</span><span class="mi">10</span><span class="o">).</span><span class="na">toMilliseconds</span><span class="o">())</span>
<span class="o">.</span><span class="na">comparisonOperator</span><span class="o">(</span><span class="nc">ComparisonOperator</span><span class="o">.</span><span class="na">GREATER_THAN_OR_EQUAL_TO_THRESHOLD</span><span class="o">)</span>
<span class="o">.</span><span class="na">alarmDescription</span><span class="o">(</span><span class="s">"High duration of My Api lambda"</span><span class="o">)</span>
<span class="o">.</span><span class="na">evaluationPeriods</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">treatMissingData</span><span class="o">(</span><span class="nc">TreatMissingData</span><span class="o">.</span><span class="na">NOT_BREACHING</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">(),</span>
<span class="nc">Alarm</span><span class="o">.</span><span class="na">Builder</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"LambdaErrorLogAlarm"</span><span class="o">)</span>
<span class="o">.</span><span class="na">metric</span><span class="o">(</span><span class="n">internalServerErrorMetric</span><span class="o">.</span><span class="na">metric</span><span class="o">())</span>
<span class="o">.</span><span class="na">threshold</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">comparisonOperator</span><span class="o">(</span><span class="nc">ComparisonOperator</span><span class="o">.</span><span class="na">GREATER_THAN_OR_EQUAL_TO_THRESHOLD</span><span class="o">)</span>
<span class="o">.</span><span class="na">alarmDescription</span><span class="o">(</span><span class="s">"My Api lambda errors logged"</span><span class="o">)</span>
<span class="o">.</span><span class="na">evaluationPeriods</span><span class="o">(</span><span class="mi">1</span><span class="o">)</span>
<span class="o">.</span><span class="na">treatMissingData</span><span class="o">(</span><span class="nc">TreatMissingData</span><span class="o">.</span><span class="na">NOT_BREACHING</span><span class="o">)</span>
<span class="o">.</span><span class="na">build</span><span class="o">()</span>
<span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="nc">DeployEnvironment</span><span class="o">.</span><span class="na">getAlarmArn</span><span class="o">()</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">ITopic</span> <span class="n">alarmTopic</span> <span class="o">=</span> <span class="nc">Topic</span><span class="o">.</span><span class="na">fromTopicArn</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"MyCompanyAlarmTopic"</span><span class="o">,</span> <span class="nc">DeployEnvironment</span><span class="o">.</span><span class="na">getAlarmArn</span><span class="o">());</span>
<span class="n">alarms</span><span class="o">.</span><span class="na">forEach</span><span class="o">(</span><span class="n">alarm</span> <span class="o">-></span> <span class="n">alarm</span><span class="o">.</span><span class="na">addAlarmAction</span><span class="o">(</span><span class="k">new</span> <span class="nc">SnsAction</span><span class="o">(</span><span class="n">alarmTopic</span><span class="o">)));</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>Set your metric</p>
<ul>
<li>your component/function. e.g., ApiGateway = <code class="language-plaintext highlighter-rouge">RestApi</code> or Lambda = <code class="language-plaintext highlighter-rouge">Function</code></li>
<li>they have their own metric, let your IDE help
<img src="https://user-images.githubusercontent.com/73862580/150748884-151169dd-f99f-488a-afe4-cc51505ba34c.png" alt="image" /></li>
</ul>
<p>evaluationPeriods + threshold</p>
<ul>
<li>during this period, how many occurrence will trigger this alarm</li>
<li>e.g., for <code class="language-plaintext highlighter-rouge">metricClientError</code>, we don’t want to know each user’s error. However, It’s good idea to monitor high amount of client error in short period of time. It could be a DDoS attack. Curently we set an alarm, when 20 client errors per minute. It may change to a higher number later.</li>
</ul>
<h2 id="notes">Notes</h2>
<ol>
<li>
<p>don’t try to name your alarm, it will pick up a name from AWS. So that we don’t have to maintain a naming convention.</p>
</li>
<li>
<p>An AWS tutorial for Create a CloudWatch alarm based on a static threshold: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ConsoleAlarms.html</p>
</li>
</ol>
<h2 id="references">References</h2>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioBetter monitoring your app.Debug a SQL performance issue (aka, how to read a query plan)2021-08-01T00:00:00+00:002021-08-01T00:00:00+00:00https://mossgreen.github.io/Debug-A-SQL-Performance_Issue<p>aka, how to read a query plan</p>
<h3 id="0-how-to-get-the-sql-query-from-jooq">0. how to get the sql query from JOOQ?</h3>
<ul>
<li>try to use it on your own stack. It’s enough, because you only want to know the query</li>
<li>never go to prod</li>
</ul>
<p>add it to your application.properties</p>
<div class="language-properties highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">quarkus.log.category."org.jooq"</span><span class="py">.level</span><span class="p">=</span><span class="s">DEBUG</span>
</code></pre></div></div>
<h3 id="1--query-plan">1. Query plan</h3>
<ul>
<li>The <code class="language-plaintext highlighter-rouge">EXPLAIN</code> command shows the execution plan of a statement and
<ul>
<li>how data from the tables are scanned</li>
<li>how the tables are joined, the join method, and</li>
<li>the estimated number of rows</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">EXPLAIN ANALYZE</code> executes and returns the actual time and number of rows</li>
<li>How to read the plan?
read the execution plan bottom-up and from the most to least indented</li>
<li>Readings
<ul>
<li>The cost is an estimation of the effort required to execute the query.
<ul>
<li>format (cost to retrieve the first row, cost to retrieve all rows)</li>
<li>a cost is an arbitrary unit of computation</li>
</ul>
</li>
<li>rows is the estimated number of rows this Index Scan will return</li>
<li>width is the estimated size in bytes of the returned rows</li>
</ul>
</li>
</ul>
<h3 id="2-a-real-life-case">2. a real life case</h3>
<p>// todo</p>
<p>result:</p>
<ol>
<li>Structure with query order (??)
<ul>
<li>sort – 6
<ul>
<li>nested loop – 3
<ul>
<li>seq scan xxxx_datasource – 1</li>
<li>index scan idx_xxxx_identifier – 2</li>
</ul>
</li>
<li>HashAggregate – 5
<ul>
<li>CTE scan on msmt – 4</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Loops
in Index Scan using <code class="language-plaintext highlighter-rouge">idx_xxxx_identifier</code> on the table loops=2, because we only query 2 records in data source 175,174. It may go up quickly if we have more ids</li>
</ol>
<h2 id="references">References</h2>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioaka, how to read a query planUse AWS X-Ray in Lambda2021-07-20T00:00:00+00:002021-07-20T00:00:00+00:00https://mossgreen.github.io/Use-AWS-X-RAY-in-Lambda<p>Identify performance bottlenecks</p>
<h2 id="jargons">Jargons</h2>
<h2 id="set-up-add-environmental-var">Set up, add environmental var</h2>
<p>update <code class="language-plaintext highlighter-rouge">.zshrc</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># cd ~</span>
<span class="c"># vim .zshrc</span>
<span class="nb">export </span><span class="nv">AWS_XRAY_CONTEXT_MISSING</span><span class="o">=</span><span class="s2">"LOG_ERROR"</span>
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="nv">$AWS_XRAY_CONTEXT_MISSING</span>
LOG_ERROR
</code></pre></div></div>
<h2 id="configuration">Configuration</h2>
<h3 id="1-maven">1. Maven</h3>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><dependency></span>
<span class="nt"><groupId></span>com.amazonaws<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>aws-xray-recorder-sdk-core<span class="nt"></artifactId></span>
<span class="nt"><version></span>1.2.1<span class="nt"></version></span>
<span class="err"><</span>/depe
</code></pre></div></div>
<h3 id="2-handle-an-exception-from-xray-class">2. Handle an exception from XRAY class</h3>
<ol>
<li>
<p>do <code class="language-plaintext highlighter-rouge">export AWS_XRAY_CONTEXT_MISSING=LOG_ERROR</code> in your terminal to fix your failing integration test</p>
</li>
<li>
<p>in <code class="language-plaintext highlighter-rouge">buildspec.yml</code>, fix for your CI/CD pipe line</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">env</span><span class="pi">:</span>
<span class="na">variables</span><span class="pi">:</span>
<span class="na">AWS_XRAY_CONTEXT_MISSING</span><span class="pi">:</span> <span class="s2">"</span><span class="s">LOG_ERROR"</span>
</code></pre></div> </div>
</li>
</ol>
<h3 id="3-tracingenabled">3. <code class="language-plaintext highlighter-rouge">TracingEnabled</code></h3>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Resources</span><span class="pi">:</span>
<span class="na">HelloWorldAPI</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::Serverless::Api</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">StageName</span><span class="pi">:</span> <span class="s">v1</span>
<span class="na">TracingEnabled</span><span class="pi">:</span> <span class="no">true</span>
</code></pre></div></div>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Resources</span><span class="pi">:</span>
<span class="na">HelloWorldAPIService</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::Serverless::Function'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">Timeout</span><span class="pi">:</span> <span class="m">900</span>
<span class="na">Environment</span><span class="pi">:</span>
<span class="na">Variables</span><span class="pi">:</span>
<span class="na">PARAM_NAME_DB_HOST</span><span class="pi">:</span> <span class="s2">"</span><span class="s">awsdb.com"</span>
<span class="na">PARAM_NAME_DB_USER</span><span class="pi">:</span> <span class="s2">"</span><span class="s">postgres"</span>
<span class="na">PARAM_NAME_DB_PASS</span><span class="pi">:</span> <span class="s2">"</span><span class="s">password"</span>
<span class="na">PARAM_NAME_DB_PORT</span><span class="pi">:</span> <span class="s2">"</span><span class="s">5432"</span>
<span class="na">AWS_XRAY_CONTEXT_MISSING</span><span class="pi">:</span> <span class="s">LOG_ERROR</span>
</code></pre></div></div>
<h2 id="add-segment">Add Segment</h2>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">myMethod</span><span class="o">(){</span>
<span class="nc">AWSXRay</span><span class="o">.</span><span class="na">beginSubsegment</span><span class="o">(</span><span class="s">"fetching user"</span><span class="o">);</span>
<span class="nc">User</span> <span class="n">user</span> <span class="o">=</span> <span class="n">userService</span><span class="o">.</span><span class="na">getUser</span><span class="o">(</span><span class="n">userId</span><span class="o">);</span>
<span class="nc">AWSXRay</span><span class="o">.</span><span class="na">endSubsegment</span><span class="o">();</span>
<span class="nc">AWSXRay</span><span class="o">.</span><span class="na">beginSubsegment</span><span class="o">(</span><span class="s">"fetching configs"</span><span class="o">);</span>
<span class="nc">Config</span> <span class="n">config</span> <span class="o">=</span> <span class="n">configService</span><span class="o">.</span><span class="na">getConfigs</span><span class="o">(</span><span class="n">userId</span><span class="o">);</span>
<span class="nc">AWSXRay</span><span class="o">.</span><span class="na">endSubsegment</span><span class="o">();</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="x-ray-vs-raygun">X-Ray vs RayGun</h2>
<p>// todo</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://docs.aws.amazon.com/xray/latest/devguide/xray-gettingstarted.html">Getting started with AWS X-Ray</a></li>
<li><a href="https://docs.aws.amazon.com/lambda/latest/dg/services-xray.html">Using AWS Lambda with AWS X-Ray</a></li>
</ul>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioIdentify performance bottlenecksConvert unit between metric and imperial in Java2021-06-21T00:00:00+00:002021-06-21T00:00:00+00:00https://mossgreen.github.io/Unit-Convertion-in-Java<p>Unit convertion, e.g., Metric to imperial</p>
<h2 id="jsrs">JSRs</h2>
<p>JSRs (Java Specification Requests)</p>
<ol>
<li>JSR-275 Units Specification</li>
<li>JSR-363 Units of Measurement API 1.0</li>
<li>JSR-385 Units of Measurement API 2.0 (CURRENT)</li>
</ol>
<h2 id="maven-packages">Maven packages</h2>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><dependency></span>
<span class="nt"><groupId></span>tech.units<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>indriya<span class="nt"></artifactId></span>
<span class="nt"><version></span>2.1.2<span class="nt"></version></span>
<span class="nt"></dependency></span>
</code></pre></div></div>
<h2 id="quantities">Quantities</h2>
<ul>
<li>What is Quantities</li>
<li>Initialise it</li>
<li>From Kilogram to gram</li>
<li>From Metric to imperial</li>
<li>CLDR: The Unicode CLDR provides key building blocks for software to support the world’s languages, with the largest and most extensive standard repository of locale data available. see: <a href="http://cldr.unicode.org/index">http://cldr.unicode.org/index</a></li>
</ul>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">Quantity</span><span class="o"><</span><span class="nc">Mass</span><span class="o">></span> <span class="n">kilogram</span> <span class="o">=</span> <span class="nc">Quantities</span><span class="o">.</span><span class="na">getQuantity</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="nc">Units</span><span class="o">.</span><span class="na">KILOGRAM</span><span class="o">);</span>
<span class="nc">Quantity</span><span class="o"><</span><span class="nc">Mass</span><span class="o">></span> <span class="n">gram</span> <span class="o">=</span> <span class="nc">Quantities</span><span class="o">.</span><span class="na">getQuantity</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="no">CLDR</span><span class="o">.</span><span class="na">GRAM</span><span class="o">);</span>
<span class="nc">Quantity</span><span class="o"><</span><span class="nc">Mass</span><span class="o">></span> <span class="n">pound</span> <span class="o">=</span> <span class="nc">Quantities</span><span class="o">.</span><span class="na">getQuantity</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="nc">USCustomary</span><span class="o">.</span><span class="na">POUND</span><span class="o">);</span>
<span class="nc">Quantity</span><span class="o"><</span><span class="nc">Mass</span><span class="o">></span> <span class="n">ounce</span> <span class="o">=</span> <span class="nc">Quantities</span><span class="o">.</span><span class="na">getQuantity</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="no">CLDR</span><span class="o">.</span><span class="na">OUNCE</span><span class="o">);</span>
<span class="nc">Quantity</span><span class="o"><</span><span class="nc">Mass</span><span class="o">></span> <span class="n">weight5</span> <span class="o">=</span> <span class="nc">Quantities</span><span class="o">.</span><span class="na">getQuantity</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="no">CLDR</span><span class="o">.</span><span class="na">OUNCE_TROY</span><span class="o">);</span>
<span class="nc">Quantity</span><span class="o"><</span><span class="nc">Mass</span><span class="o">></span> <span class="n">kilogramToGram</span> <span class="o">=</span> <span class="n">kilogram</span><span class="o">.</span><span class="na">to</span><span class="o">(</span><span class="nc">Units</span><span class="o">.</span><span class="na">GRAM</span><span class="o">);</span>
<span class="nc">Quantity</span><span class="o"><</span><span class="nc">Mass</span><span class="o">></span> <span class="n">kilogramToPound</span> <span class="o">=</span> <span class="n">kilogram</span><span class="o">.</span><span class="na">to</span><span class="o">(</span><span class="nc">USCustomary</span><span class="o">.</span><span class="na">POUND</span><span class="o">);</span>
<span class="nc">Quantity</span><span class="o"><</span><span class="nc">Length</span><span class="o">></span> <span class="n">centimetre</span> <span class="o">=</span> <span class="nc">Quantities</span><span class="o">.</span><span class="na">getQuantity</span><span class="o">(</span><span class="mi">214</span><span class="o">,</span> <span class="nc">MetricPrefix</span><span class="o">.</span><span class="na">CENTI</span><span class="o">(</span><span class="no">METRE</span><span class="o">));</span>
</code></pre></div></div>
<h2 id="references">References</h2>
<ul>
<li><a href="http://cldr.unicode.org/index">Unicode CLDR Project</a></li>
<li><a href="https://www.rapidtables.com/convert/temperature/fahrenheit-to-celsius.html">Rapid table convertion</a></li>
<li><a href="https://schneide.blog/tag/unit-api-2-0/">Migrating from JScience quantities to Unit API 2.0</a></li>
</ul>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioUnit convertion, e.g., Metric to imperialUse Embedded PSQL in Quarkus Integration Testing2021-05-20T00:00:00+00:002021-05-20T00:00:00+00:00https://mossgreen.github.io/Use-Embedded-PSQL-In-Quarkus<p>// todo</p>
<h2 id="jargons">Jargons</h2>
<h2 id="references">References</h2>Moss GUmossgu@outlook.comhttps://mossgreen.github.io// todoAWS Lambda with Java2021-04-06T00:00:00+00:002021-04-06T00:00:00+00:00https://mossgreen.github.io/AWS-Lambda-with-Java<p>some lambda related concepts</p>
<h2 id="jargons">Jargons</h2>
<ul>
<li>serverless</li>
<li>cold start</li>
</ul>
<h2 id="lambda-runtime">Lambda runtime</h2>
<h3 id="lambda-execution-environment">Lambda Execution Environment</h3>
<p><img src="https://user-images.githubusercontent.com/73862580/149485283-84d64ca2-a826-431a-b514-b4d69ddb5d87.png" alt="image" /></p>
<p>There is no “Main” method in code. Lambda Java Runtime will act as the server, like Tomcat.</p>
<h3 id="lambda-execution-environment-lifecycle">Lambda execution environment lifecycle</h3>
<p><img src="https://user-images.githubusercontent.com/73862580/149485798-82ff8eb2-20a7-4b8d-8b6d-d8e5cbf02149.png" alt="image" /></p>
<ol>
<li><code class="language-plaintext highlighter-rouge">Init</code>:
<ol>
<li>Lambda creates or unfreezes an execution environment with the configured resources</li>
<li>downloads the code for the function and all layers</li>
<li>initializes any extensions</li>
<li>initializes the runtime</li>
<li>run the function’s initialization code (static code, the code outside the main handler)</li>
<li>The Init phase happens either during the first invocation, or in advance of function invocations if you have enabled <code class="language-plaintext highlighter-rouge">provisioned concurrency</code></li>
<li>The Init phase is limited to 10 seconds. Lambda retries the Init phase at the time of the first function invocation.</li>
</ol>
</li>
<li><code class="language-plaintext highlighter-rouge">Invoke</code>
<ol>
<li>Lambda invokes the function handler</li>
<li>After the function runs to completion, Lambda prepares to handle another function invocation</li>
</ol>
</li>
<li><code class="language-plaintext highlighter-rouge">Shutdown</code>: This phase is triggered if the Lambda function does not receive any invocations for a period of time</li>
</ol>
<h2 id="lambda-function">Lambda Function</h2>
<p>In real use cases, the input to the Lambda function will be a JSON object that repre‐sents an event from some other component or system</p>
<h3 id="method-signatures">Method Signatures</h3>
<p>Valid Java Lambda methods must fit one of the following four signatures:</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">output-type handler-name(input-type input)</code></li>
<li><code class="language-plaintext highlighter-rouge">output-type handler-name(input-type input, Context context)</code></li>
<li><code class="language-plaintext highlighter-rouge">void handler-name(InputStream is, OutputStream os)</code></li>
<li><code class="language-plaintext highlighter-rouge">void handler-name(InputStream is, OutputStream os, Context context)</code></li>
</ul>
<p>where</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">output-type</code> can be void, a Java primitive, or a JSON-serializable type.</li>
<li><code class="language-plaintext highlighter-rouge">input-type</code> is a Java primitive, or a JSON-serializable type.</li>
<li><code class="language-plaintext highlighter-rouge">Context</code> refers to <code class="language-plaintext highlighter-rouge">com.amazonaws.services.lambda.runtime.Context</code>. It gives information about the current Lambda invocation. We can use this formation during the processing of a Lambda event</li>
<li><code class="language-plaintext highlighter-rouge">handler-name</code> can be any valid Java method name, and we refer to it in application’s configuration</li>
<li>Java Lambda methods can be either instance methods or static methods, but <strong>must be public</strong></li>
</ul>
<h3 id="events">Events</h3>
<ul>
<li>An event is a JSON object that contains information about what happened</li>
<li>Events are facts about a change in the system state, they are immutable, and the time when they happen is significant</li>
<li>The first parameter of every Lambda handler contains the event.</li>
<li>you determine the structure and contents of the event</li>
<li>
<p>When an AWS service invokes your function, the service defines the shape of the event</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>sam <span class="nb">local </span>generate-event apigateway aws-proxy
<span class="o">{</span>
<span class="s2">"body"</span>: <span class="s2">"eyJ0ZXN0IjoiYm9keSJ9"</span>,
<span class="s2">"resource"</span>: <span class="s2">"/{proxy+}"</span>,
<span class="s2">"path"</span>: <span class="s2">"/path/to/resource"</span>,
<span class="s2">"httpMethod"</span>: <span class="s2">"POST"</span>,
<span class="s2">"isBase64Encoded"</span>: <span class="nb">true</span>,
<span class="s2">"queryStringParameters"</span>: <span class="o">{</span>
<span class="s2">"foo"</span>: <span class="s2">"bar"</span>
<span class="o">}</span>,
...
<span class="o">}</span>
</code></pre></div> </div>
</li>
</ul>
<h3 id="context">Context</h3>
<ul>
<li><code class="language-plaintext highlighter-rouge">getRemainingTimeInMillis()</code> – Returns the number of milliseconds left before the execution times out.</li>
<li>``getFunctionName()` – Returns the name of the Lambda function.</li>
<li>``getFunctionVersion()` – Returns the version of the function.</li>
<li>``getInvokedFunctionArn()` – Returns the Amazon Resource Name (ARN) that’s used to invoke the function. Indicates if the invoker specified a version number or alias.</li>
<li>``getMemoryLimitInMB()` – Returns the amount of memory that’s allocated for the function.</li>
<li>``getAwsRequestId()` – Returns the identifier of the invocation request.</li>
<li>``getLogGroupName()` – Returns the log group for the function.</li>
<li>``getLogStreamName()` – Returns the log stream for the function instance.</li>
<li>``getIdentity()` – (mobile apps) Returns information about the Amazon Cognito identity that authorized the request.</li>
<li>``getClientContext()` – (mobile apps) Returns the client context that’s provided to Lambda by the client application.</li>
<li>``getLogger()` – Returns the logger object for the function.</li>
</ul>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><dependency></span>
<span class="nt"><groupId></span>com.amazonaws<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>aws-lambda-java-core<span class="nt"></artifactId></span>
<span class="nt"><version></span>1.2.0<span class="nt"></version></span>
<span class="nt"><scope></span>provided<span class="nt"></scope></span>
<span class="nt"></dependency></span>
</code></pre></div></div>
<h3 id="environment-variable">Environment Variable</h3>
<p>you can create two functions with the same code but different environment variables. One function connects to a test database, and the other connects to a production database. In this situation, you use environment variables to tell the function the hostname and other connection details for the database.</p>
<h4 id="retrieve-environment-variables">Retrieve environment variables</h4>
<p>Note: Use AWS Secrets Manager instead of environment variables to store database credentials</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">EnvVarLambda</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">handler</span><span class="o">(</span><span class="nc">Object</span> <span class="n">event</span><span class="o">)</span> <span class="o">{</span>
<span class="nc">String</span> <span class="n">databaseUrl</span> <span class="o">=</span> <span class="nc">System</span><span class="o">.</span><span class="na">getenv</span><span class="o">(</span><span class="s">"DATABASE_URL"</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">databaseUrl</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">||</span> <span class="n">databaseUrl</span><span class="o">.</span><span class="na">isEmpty</span><span class="o">())</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"DATABASE_URL is not set"</span><span class="o">);</span>
<span class="k">else</span>
<span class="nc">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"DATABASE_URL is set to: "</span> <span class="o">+</span> <span class="n">databaseUrl</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<h2 id="invoking-lambda-functions">Invoking Lambda Functions</h2>
<ul>
<li>You can invoke a function synchronously (and wait for the response), or asynchronously.</li>
<li>To invoke a function asynchronously, set InvocationType to Event.</li>
<li>For asynchronous invocation, Lambda adds events to a queue before sending them to your function. If your function does not have enough capacity to keep up with the queue, events may be lost. Occasionally, your function may receive the same event multiple times, even if no error occurs. To retain events that were not processed, configure your function with a dead-letter queue.</li>
</ul>
<table>
<thead>
<tr>
<th>Event Source Type</th>
<th>Event Sources</th>
</tr>
</thead>
<tbody>
<tr>
<td>Synchrinous</td>
<td>Api Gateway, CloudFront (lambda@Edge), Application Load Balancer, Cognito, Lex, Alexa, Kinesis Data Firehose</td>
</tr>
<tr>
<td>Asynchronous</td>
<td>S3, SNS, SES, CloudFormation, CloudWatch logs, CloudWatch events, CodeCommit, Config</td>
</tr>
<tr>
<td>Steam/Queue</td>
<td>Kinesis Data Stream, DynamoDb Streams, SQS</td>
</tr>
</tbody>
</table>
<p><img src="https://user-images.githubusercontent.com/73862580/149617457-b32f5d43-2e28-4745-ba6c-b3782ee55b8a.png" alt="image" /></p>
<h3 id="1-synchronous-invocation-eg-work-with-apigateway">1. Synchronous invocation, e.g., work with ApiGateway</h3>
<ul>
<li>When you invoke a function synchronously, Lambda runs the function and waits for a response</li>
<li>The AWS CLI and AWS SDK also automatically retry on client timeouts, throttling, and service errors</li>
</ul>
<p><img src="https://user-images.githubusercontent.com/73862580/149615710-b68db0a8-bab0-438f-bca4-cea7d4836b8b.png" alt="image" /></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// invoke
aws lambda invoke <span class="nt">--function-name</span> my-function <span class="nt">--payload</span> <span class="s1">'{ "key": "value" }'</span> response.json
// retrieve LogResult
aws lambda invoke <span class="nt">--function-name</span> my-function out <span class="nt">--log-type</span> Tail <span class="se">\</span>
<span class="nt">--query</span> <span class="s1">'LogResult'</span> <span class="nt">--output</span> text | <span class="nb">base64</span> <span class="nt">-d</span>
</code></pre></div></div>
<h4 id="apigateway-aws-proxy-event">ApiGateway aws-proxy event</h4>
<ul>
<li>the current version of HTTP APIs doesn’t support custom/Lambda authorizers, but instead you could implement this feature within your Lambda handler code.</li>
<li>The one we typically want from this list is the aws-proxy event, where API Gateway acts as a proxy server in front of a Lambda function,</li>
</ul>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>sam <span class="nb">local </span>generate-event apigateway
Commands:
authorizer Generates an Amazon API Gateway Authorizer Event
aws-proxy Generates an Amazon API Gateway AWS Proxy Event
<span class="nv">$ </span>sam <span class="nb">local </span>generate-event apigateway aws-proxy
<span class="o">{</span>
<span class="s2">"body"</span>: <span class="s2">"eyJ0ZXN0IjoiYm9keSJ9"</span>,
<span class="s2">"resource"</span>: <span class="s2">"/{proxy+}"</span>,
<span class="s2">"path"</span>: <span class="s2">"/path/to/resource"</span>,
<span class="s2">"httpMethod"</span>: <span class="s2">"POST"</span>,
<span class="s2">"isBase64Encoded"</span>: <span class="nb">true</span>,
<span class="s2">"queryStringParameters"</span>: <span class="o">{</span>
<span class="s2">"foo"</span>: <span class="s2">"bar"</span>
<span class="o">}</span>,
...
<span class="o">}</span>
</code></pre></div></div>
<h4 id="configuring-a-lambda-event-source">Configuring a lambda event source</h4>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">HelloAPILambda</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::Serverless:Function</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">Runtime</span><span class="pi">:</span> <span class="s">java8</span>
<span class="na">Handler</span><span class="pi">:</span> <span class="s">packageName.ClassNameAPI::handler</span>
<span class="na">CodeUri</span><span class="pi">:</span> <span class="s">target/lambda.zip</span>
<span class="na">Events</span><span class="pi">:</span>
<span class="na">MyApiGateway</span><span class="pi">:</span>
<span class="s">Type:api</span>
<span class="s">properties</span><span class="pi">:</span>
<span class="na">Path</span><span class="pi">:</span> <span class="s">/foo</span>
<span class="na">Method</span><span class="pi">:</span> <span class="s">get</span>
</code></pre></div></div>
<h3 id="2-asynchronise-work-with-sns">2. Asynchronise, work with SNS</h3>
<p><img src="https://user-images.githubusercontent.com/73862580/149616305-bc573b88-4899-4372-96af-7c596720e7f3.png" alt="image" /></p>
<ul>
<li>S3 or SNS invokes functions asynchronously to process events</li>
<li>For asynchronous invocation, Lambda queues the event, before passing it to your function</li>
<li>When Lambda queues the event, it immediately sends a success response to the service that generated the event</li>
<li>After the function processes the event, Lambda doesn’t return a response to the event-generating service</li>
</ul>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>aws lambda invoke <span class="se">\</span>
<span class="nt">--function-name</span> my-function <span class="se">\</span>
<span class="nt">--invocation-type</span> Event <span class="se">\</span>
<span class="nt">--cli-binary-format</span> raw-in-base64-out <span class="se">\</span>
<span class="nt">--payload</span> <span class="s1">'{ "key": "value" }'</span> response.json
</code></pre></div></div>
<h4 id="retry-logic">Retry logic</h4>
<ul>
<li>If the function returns an error, Lambda attempts to run it two more times:
<ul>
<li>with a one-minute wait between the first two attempts</li>
<li>two minutes between the second and third attempts</li>
</ul>
</li>
<li>If the function doesn’t have enough concurrency available to process all events, additional requests are throttled. For throttling errors (429) and system errors (500-series), Lambda returns the event to the queue and attempts to run the function again for up to 6 hours.
<ul>
<li>The retry interval increases exponentially from 1 second after the first attempt to a maximum of 5 minutes.</li>
<li>If the queue contains many entries, Lambda increases the retry interval and reduces the rate at which it reads events from the queue.</li>
</ul>
</li>
</ul>
<h4 id="handle-timeout-and-errors">handle timeout and errors</h4>
<p>Ensure that your function code gracefully handles duplicate events, and that you have enough concurrency available to handle all invocations</p>
<ul>
<li>events may deliverd multiple times occationally</li>
<li>If the function can’t keep up with incoming events, events might also be deleted from the queue without being sent to the function</li>
<li>When the queue is very long, new events might age out before Lambda has a chance to send them to your function. When an event expires or fails all processing attempts, Lambda discards it. You can configure error handling for a function to reduce the number of retries that Lambda performs, or to discard unprocessed events more quickly.</li>
</ul>
<h4 id="configuring-error-handling-for-asynchronous-invocation">Configuring error handling for asynchronous invocation</h4>
<p>Configure the following settings.</p>
<ul>
<li>Maximum age of event – The maximum amount of time Lambda retains an event in the asynchronous event queue, up to 6 hours.</li>
<li>Retry attempts – The number of times Lambda retries when the function returns an error, between 0 and 2.</li>
</ul>
<p>e.g. for SQS</p>
<ol>
<li>Set the queue’s visibility timeout to at least six times the function timeout value. This allows the function time to process each batch of records if the function execution is throttled while processing a previous batch.</li>
<li>Set the maxReceiveCount on the source queue’s redrive policy to at least 5. This improves the chances of messages being processed before reaching the DLQ.</li>
<li>Ensure idempotency to allow messages to be safely processed more than once.</li>
</ol>
<h4 id="on-failure-destination-dead-letter-queues">on-failure destination: Dead-letter queues</h4>
<p>configure your function with a dead-letter queue to save discarded events for further processing.</p>
<p>To reprocess events in a dead-letter queue, you can set it as an event source for your Lambda function. Alternatively, you can manually retrieve the events.</p>
<p>You can choose an Amazon SQS queue or Amazon SNS topic for your dead-letter queue.</p>
<ul>
<li>
<p>Amazon SQS queue – A queue holds failed events until they’re retrieved. Choose an Amazon SQS queue if you <strong>expect a single entity</strong>, such as a Lambda function or CloudWatch alarm, to process the failed event</p>
</li>
<li>
<p>Amazon SNS topic – A topic relays failed events to one or more destinations. Choose an Amazon SNS topic if you expect multiple entities to act on a failed event. For example, you can configure a topic to send events to an email address, a Lambda function, and/or an HTTP endpoint.</p>
</li>
</ul>
<h3 id="work-with-streams-aka-event-source-mappings">Work with streams, aka. Event source mappings</h3>
<p>You can use event source mappings to process items from a stream or queue in services that don’t invoke Lambda functions directly.</p>
<p>example: an event source mapping that reads from a Kinesis stream</p>
<p>For streams, an event source mapping creates an iterator for each shard in the stream, and processes items in each shard in order. You can configure the event source mapping to read only new items that appear in the stream, or to start with older items. Processed items aren’t removed from the stream, and other functions or consumers can process them.</p>
<ul>
<li>By default, if your function returns an error, the entire batch is reprocessed until the function succeeds, or until the items in the batch expire</li>
<li>To ensure in-order processing, Lambda pauses processing for the affected shard until the error is resolved</li>
<li>You can configure the event source mapping to discard old events, restrict the number of retries, or process multiple batches in parallel</li>
<li>If you process multiple batches in parallel, in-order processing is still guaranteed for each partition key, but multiple partition keys in the same shard are processed simultaneously.</li>
</ul>
<h2 id="classic-lambda-use-cases">Classic Lambda use cases</h2>
<p>Serverless applications generally fall into several common categories:</p>
<ol>
<li>Web applications</li>
<li>Web and mobile backends</li>
<li>Data processing: event-based processing tasks triggered by data changes in data stores, or streaming data ETL tasks with Amazon Kinesis and Lambda.</li>
<li>Parallelized computing tasks (Fan out?): splitting highly complex, long-lived computations to individual tasks across many Lambda function instances to process data more quickly in parallel.</li>
<li>Internet of Things (IoT) workloads</li>
</ol>
<p>Lambda acts as glue between the services, providing business logic to transform data as it moves between services.</p>
<h3 id="event-driven-vs-request-driven">event-driven vs request-driven</h3>
<p>For simpler applications, the difference between event-driven and request-driven applications may not be clear. As your applications develop more functionality and handle more traffic, this becomes more apparent.</p>
<ul>
<li>Request-driven applications typically use directed commands to coordinate downstream functions to complete an activity</li>
<li>Event-driven applications create events that are observable by other services and systems, but the event producer is unaware of which consumers, if any, are listening.</li>
</ul>
<h3 id="use-cases">use cases</h3>
<ol>
<li>Using service integrations and asynchronous processing</li>
</ol>
<p>A Lambda function consumes these messages from the queue, and updates the status in a DynamoDB table. Another API endpoint provides the status of the request by querying the DynamoDB table:</p>
<h2 id="lambda-quotas-and-limitations">Lambda Quotas and limitations</h2>
<h3 id="quotas">Quotas</h3>
<table>
<thead>
<tr>
<th>Resource</th>
<th>Default quota</th>
<th>Can be increased up to</th>
</tr>
</thead>
<tbody>
<tr>
<td>Concurrent executions</td>
<td>1000</td>
<td>tens of thousands</td>
</tr>
<tr>
<td>Storage for uploaded functions (.zip file archives) and layers</td>
<td>75 GB</td>
<td>Terabytes</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th>Resource</th>
<th>Quota</th>
</tr>
</thead>
<tbody>
<tr>
<td>Invocation payload (request and response)</td>
<td>- 6 MB (synchronous)<br /> - 256 KB (asynchronous)</td>
</tr>
<tr>
<td>Deployment .zip package</td>
<td>- 50 MB (zipped)<br /> - 250 MB (unzipped)</td>
</tr>
<tr>
<td>/tmp directory storage</td>
<td>512MB</td>
</tr>
</tbody>
</table>
<h3 id="limitations">Limitations</h3>
<ol>
<li>
<p>payload size
For an application moving a payload from API Gateway to Lambda to SQS, API Gateway supports payloads up to 10 Mb, while Lambda’s payload limit is 6 Mb and the SQS message size limit is 256 Kb. In this example, you could instead store the payload in an S3 bucket instead of uploading to API Gateway, and pass a reference token across the services. The token size is much smaller than any payload limit and may be a more efficient design for your workload, depending upon the use-case.</p>
</li>
<li>shared resources
if you have development resources in the same account as production workloads, quotas are shared across both. It’s possible for development activity to exhaust resources unintentionally that you may want to reserve only for production.
An effective way to solve this issue is to use multiple AWS accounts, dedicating workloads to their own specific account.</li>
<li>
<p>Controlling traffic flow for server-based resources</p>
<ul>
<li>Lambda can scale up quickly in response to traffic, it’s possible to overwhelm downstream services with data or connection requests.</li>
<li>If your serverless workload has the capacity to overwhelm those resources, use an SQS queue to decouple the Lambda function from the target. This allows the server-based resource to process messages from the queue at a steady rate. The queue also durably stores the requests if the downstream resource becomes unavailable.</li>
<li>RDS are connection-based, so they are intended to work with a few long-lived clients, such as web servers</li>
<li>The Amazon RDS Proxy service is built to solve the high-volume use-case. It pools the connections between the Lambda service and the downstream Amazon RDS database. This means that a scaling Lambda function is able to reuse connections via the proxy. As a result, the relational database is not overwhelmed with connections requests from individual Lambda functions. This does not require code changes in many cases. You only need to replace the database endpoint with the proxy endpoint in your Lambda function.</li>
</ul>
</li>
</ol>
<h2 id="references">References</h2>
<ul>
<li><a href="https://docs.aws.amazon.com/lambda/latest/operatorguide/event-driven-architectures.html">Event-driven architectures</a></li>
<li><a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-invocation.html">Invoking Lambda functions</a></li>
<li><a href="https://www.oreilly.com/library/view/programming-aws-lambda/9781492041047/">Programming AWS Lambda</a></li>
</ul>Moss GUmossgu@outlook.comhttps://mossgreen.github.iosome lambda related conceptsAWS CDK 1012021-03-21T00:00:00+00:002021-03-21T00:00:00+00:00https://mossgreen.github.io/AWS-CDK-101<p>Version control your infrastructure is not a dream</p>
<h2 id="jargons">Jargons</h2>
<ul>
<li><code class="language-plaintext highlighter-rouge">IaC</code> infrastructure as code, provisioning and managing your cloud resources by writing a template file that is both human readable, and machine consumable</li>
<li><strong>AWS CDK</strong> (AWS Cloud Development Kit) is a software development framework for defining cloud infrastructure in code and provisioning it through AWS CloudFormation.</li>
<li><strong>Constructs</strong>
<ul>
<li>Constructs are the basic building blocks of AWS CDK apps.</li>
<li>A construct represents a “cloud component” and encapsulates <strong>everything</strong> AWS CloudFormation needs to create the component</li>
<li>A construct can represent
<ul>
<li>a single resource, such as an Amazon S3 bucket</li>
<li>or a higher-level component consisting of multiple AWS resources</li>
</ul>
</li>
<li>Initialize a construct takes 3 parameters
<ul>
<li><strong>Scope</strong> the scope in which this construct is created, usually pass <code class="language-plaintext highlighter-rouge">this</code> means current scope</li>
<li><strong>id</strong> serves as a namespace, used to calculate the CloudFormation Logical ID</li>
<li><strong>Props</strong>, a set of properties. if all props elements are optional, you can leave out the props parameter completely. E.g., <code class="language-plaintext highlighter-rouge">lambda.Function</code> construct accepts properties like <code class="language-plaintext highlighter-rouge">runtime</code>, <code class="language-plaintext highlighter-rouge">code</code> and <code class="language-plaintext highlighter-rouge">handler</code></li>
</ul>
</li>
</ul>
</li>
<li>AWS Construct Library has 3 levels
<ol>
<li>Bottom level: CFN Resources. (<strong>AWS CloudFormation-only</strong>) (L1)
<ul>
<li>These constructs directly represent all resources available in AWS CloudFormation.</li>
<li>They are named CfnXyz, where Xyz is name of the resource</li>
<li>When you use Cfn resources, you must explicitly configure all resource properties, which requires a complete understanding of the details of the underlying AWS CloudFormation resource model.</li>
</ul>
</li>
<li>Higher level: AWS constructs, <strong>intent-based API</strong>.
<ul>
<li>provide the defaults, boilerplate, and glue logic you’d be writing yourself with a CFN Resource construct.</li>
</ul>
</li>
<li>even higher-level constructs, which we call <strong>patterns</strong>.
<ul>
<li>designed to help you complete common tasks in AWS, often involving multiple kinds of resources</li>
<li>e.g., The aws-apigateway.LambdaRestApi construct represents an Amazon API Gateway API that’s backed by an AWS Lambda function.</li>
</ul>
</li>
</ol>
</li>
<li><strong>Composition</strong>
<ul>
<li>Composition lets you define reusable components and share them like any other code.</li>
</ul>
</li>
<li><strong>Stack</strong>
<ul>
<li>The unit of deployment in the AWS CDK is called a stack.</li>
<li>All AWS resources defined within the scope of a stack, either directly or indirectly, are provisioned as a single unit.</li>
</ul>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MyFirstStack</span> <span class="kd">extends</span> <span class="nc">Stack</span> <span class="o">{</span>
<span class="kd">public</span> <span class="nf">MyFirstStack</span><span class="o">(</span><span class="kd">final</span> <span class="nc">Construct</span> <span class="n">scope</span><span class="o">,</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">(</span><span class="n">scope</span><span class="o">,</span> <span class="n">id</span><span class="o">,</span> <span class="kc">null</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="nf">MyFirstStack</span><span class="o">(</span><span class="kd">final</span> <span class="nc">Construct</span> <span class="n">scope</span><span class="o">,</span> <span class="kd">final</span> <span class="nc">String</span> <span class="n">id</span><span class="o">,</span> <span class="kd">final</span> <span class="nc">StackProps</span> <span class="n">props</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">super</span><span class="o">(</span><span class="n">scope</span><span class="o">,</span> <span class="n">id</span><span class="o">,</span> <span class="n">props</span><span class="o">);</span>
<span class="k">new</span> <span class="nf">Bucket</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="s">"MyFirstBucket"</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div> </div>
</li>
<li><strong>Nested stacks</strong>
<ul>
<li>When you apply template changes to update a top-level stack, CloudFormation updates the top-level stack and initiates an update to its nested stacks. CloudFormation updates the resources of modified nested stacks, but does not update the resources of unmodified nested stacks.</li>
<li>Furthermore, this stack will not be treated as an independent deployment artifact (won’t be listed in “cdk list” or deployable through “cdk deploy”), but rather only synthesized as a template and uploaded as an asset to S3.</li>
<li>parent stacks v.s nested stacks: Nested stacks are bound to their parent stack and are not treated as independent deployment artifacts; they are not listed by cdk list nor can they be deployed by cdk deploy.</li>
</ul>
</li>
<li><strong>App</strong>
<ul>
<li>To define the previous stack within the scope of an application, use the App construct.</li>
<li>It’s the only construct that can be used as a root for the construct tree</li>
<li>You would normally define an App instance in your program’s entrypoint, then define constructs where the app is used as the parent scope.</li>
<li>After all the child constructs are defined within the app, you should call app.synth() which will emit a “cloud assembly” from this app into the directory specified by outdir. Cloud assemblies includes artifacts such as CloudFormation templates and assets that are needed to deploy this app into the AWS cloud.</li>
</ul>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">App</span> <span class="n">app</span> <span class="o">=</span> <span class="k">new</span> <span class="nc">App</span><span class="o">();</span>
<span class="k">new</span> <span class="nf">MyFirstStack</span><span class="o">(</span><span class="n">app</span><span class="o">,</span> <span class="s">"hello-cdk"</span><span class="o">);</span>
<span class="n">app</span><span class="o">.</span><span class="na">synth</span><span class="o">();</span>
</code></pre></div> </div>
</li>
<li>App lifecycle
<ol>
<li>Construction (or Initialization)
<ul>
<li>Most of your app code is executed in this stage</li>
<li>all of the constructs (app, stacks, and their child constructs) are instantiated and the constructor chain is executed</li>
</ul>
</li>
<li>Preparation
<ul>
<li>All constructs that have implemented the <code class="language-plaintext highlighter-rouge">prepare</code> method</li>
<li>It’s rare to need to use the “prepare” hook, and generally <strong>not recommended</strong>.</li>
</ul>
</li>
<li>Validation
<ul>
<li>All constructs that have implemented the <code class="language-plaintext highlighter-rouge">validate</code> method</li>
</ul>
</li>
<li>Synthesis
<ul>
<li><strong>final stage of the execution</strong> of your AWS CDK app. <code class="language-plaintext highlighter-rouge">app.synth()</code></li>
<li>In most cases, you won’t need to implement the synthesize method</li>
</ul>
</li>
<li>Deployment
<ul>
<li>It uploads assets to Amazon S3 and Amazon ECR and then starts an AWS CloudFormation deployment to deploy the application and create the resources.</li>
</ul>
</li>
</ol>
</li>
<li><strong>Cloud assemblies</strong>
<ul>
<li>The call to app.synth() is what tells the AWS CDK to synthesize a cloud assembly from an app.</li>
<li>Typically you don’t interact directly with cloud assemblies.</li>
<li>They are files that include everything needed to deploy your app to a cloud environment. For example, it includes an AWS CloudFormation template for each stack in your app, and a copy of any file assets or Docker images that you reference in your app.</li>
</ul>
</li>
<li>Environments
<ul>
<li>Each Stack instance in your AWS CDK app is explicitly or implicitly associated with an environment (env).</li>
<li>An environment is the target AWS account and AWS Region into which the stack is intended to be deployed.</li>
<li>For production stacks, we <strong>recommend</strong> that you explicitly specify the environment for each stack in your app using the env property.</li>
</ul>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">envEU</span> <span class="o">=</span> <span class="p">{</span> <span class="na">account</span><span class="p">:</span> <span class="dl">'</span><span class="s1">2383838383</span><span class="dl">'</span><span class="p">,</span> <span class="na">region</span><span class="p">:</span> <span class="dl">'</span><span class="s1">eu-west-1</span><span class="dl">'</span> <span class="p">};</span>
<span class="kd">const</span> <span class="nx">envUSA</span> <span class="o">=</span> <span class="p">{</span> <span class="na">account</span><span class="p">:</span> <span class="dl">'</span><span class="s1">8373873873</span><span class="dl">'</span><span class="p">,</span> <span class="na">region</span><span class="p">:</span> <span class="dl">'</span><span class="s1">us-west-2</span><span class="dl">'</span> <span class="p">};</span>
<span class="k">new</span> <span class="nx">MyFirstStack</span><span class="p">(</span><span class="nx">app</span><span class="p">,</span> <span class="dl">'</span><span class="s1">first-stack-us</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">env</span><span class="p">:</span> <span class="nx">envUSA</span> <span class="p">});</span>
<span class="k">new</span> <span class="nx">MyFirstStack</span><span class="p">(</span><span class="nx">app</span><span class="p">,</span> <span class="dl">'</span><span class="s1">first-stack-eu</span><span class="dl">'</span><span class="p">,</span> <span class="p">{</span> <span class="na">env</span><span class="p">:</span> <span class="nx">envEU</span> <span class="p">});</span>
</code></pre></div> </div>
</li>
</ul>
<h2 id="cdk-pros-n-cons">CDK Pros n Cons</h2>
<h3 id="pros">Pros</h3>
<ul>
<li>FREE!!!</li>
<li>Support Java and Typescript</li>
<li>IaC (Infrastructure as Code)</li>
<li>Version Control your infrastructure</li>
<li>Tired of CloudFormation Yaml or AWS CLI</li>
<li>The benefit of Iac
<ul>
<li>Visibility, both resource and parameteres</li>
<li>Stability, version control, avoid breaking things</li>
<li>Scalability, write it once and reuse it many times, scale horizontally easy</li>
<li>Security, create one well secured architecture, reuse it often</li>
<li>Transactional, roll back gracefully on failure</li>
</ul>
</li>
</ul>
<h3 id="cons">Cons</h3>
<p>Limitations of <code class="language-plaintext highlighter-rouge">AWS CloudFormation</code></p>
<ul>
<li>Each AWS CloudFormation template can have at most:
<ul>
<li>500 resources</li>
<li>200 parameters</li>
<li>200 mappings</li>
<li>200 outputs</li>
</ul>
</li>
<li>AWS CloudFormation resource name max length 255 characters</li>
<li>AWS CloudFormation stack maximum 200</li>
</ul>
<h2 id="common-commands">Common Commands</h2>
<ol>
<li>
<p>Install <code class="language-plaintext highlighter-rouge">aws-cdk</code></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> npm <span class="nb">install</span> <span class="nt">-g</span> aws-cdk
npm update <span class="nt">-g</span> aws-cdk
cdk <span class="nt">--version</span>
</code></pre></div> </div>
</li>
<li>
<p>Useful commands</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">mvn package</code> compile and run tests</li>
<li><code class="language-plaintext highlighter-rouge">cdk ls</code> list all stacks in the app</li>
<li><code class="language-plaintext highlighter-rouge">cdk synth</code> emits the synthesized CloudFormation template</li>
<li><code class="language-plaintext highlighter-rouge">cdk deploy</code> deploy this stack to your default AWS account/region</li>
<li><code class="language-plaintext highlighter-rouge">cdk diff</code> compare deployed stack with current state</li>
<li><code class="language-plaintext highlighter-rouge">cdk docs</code> open CDK documentation</li>
</ul>
</li>
<li>
<p>First app</p>
</li>
</ol>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>cdk-workshop <span class="o">&&</span> <span class="nb">cd </span>cdk-workshop
cdk init sample-app <span class="nt">--language</span> java
cdk synth <span class="c"># generate an AWS CloudFormation template for each stack defined in your application.</span>
cdk bootstrap <span class="c"># install the bootstrap stack into an environment:</span>
mvn package
cdk deploy
</code></pre></div></div>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># To list all the stacks in an AWS CDK app</span>
cdk <span class="nb">ls</span>
</code></pre></div></div>
<h2 id="demos">Demos</h2>
<h3 id="create-a-static-website-on-s3">Create a static website on S3</h3>
<ul>
<li>https://dzone.com/articles/an-introduction-to-aws-cloud-development-kit-cdk</li>
<li>https://reflectoring.io/getting-started-with-aws-cdk/</li>
</ul>
<h2 id="cdk-pipelines-cicd">CDK pipelines CICD</h2>
<p>The CDK Pipelines construct makes that proccess easy and streamlined from within your existing CDK infrastructure design.</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://www.ernestchiang.com/zh/notes/aws/cdk/">Study notes: AWS Cloud Development Kit (AWS CDK)</a></li>
<li><a href="https://docs.aws.amazon.com/cdk/latest/guide/core_concepts.html">AWS CDK Concepts</a></li>
<li><a href="https://github.com/aws-samples/aws-cdk-examples">AWS CDK Examples</a></li>
<li><a href="https://docs.aws.amazon.com/cdk/latest/guide/home.html">AWS CDK Documentation</a></li>
</ul>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioVersion control your infrastructure is not a dreamPure React Study Notes2021-02-14T00:00:00+00:002021-02-14T00:00:00+00:00https://mossgreen.github.io/Pure-React-Study-Notes<p>Learn some React basics.</p>
<h2 id="jsx">JSX</h2>
<p>JSX hello world example</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">ReactDOM</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react-dom</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">function</span> <span class="nx">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">Hello</span> <span class="nx">World</span><span class="o">!<</span><span class="sr">/div></span><span class="se">)</span><span class="err">;
</span><span class="p">}</span>
<span class="nx">ReactDOM</span><span class="p">.</span><span class="nx">render</span><span class="p">(</span><span class="o"><</span><span class="nx">HelloWorld</span><span class="o">/></span><span class="p">,</span> <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">'</span><span class="s1">#root</span><span class="dl">'</span><span class="p">));</span>
</code></pre></div></div>
<h3 id="1-jsx-is-compiled-to-javascript-as-a-function-by-babel">1. JSX is compiled to JavaScript as a function by Babel</h3>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">SongName</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">'</span><span class="s1">song-name</span><span class="dl">'</span><span class="o">></span>
<span class="p">{</span><span class="nx">props</span><span class="p">.</span><span class="nx">song</span><span class="p">.</span><span class="nx">name</span><span class="p">}</span>
<span class="o"><</span><span class="sr">/span></span><span class="err">
</span> <span class="p">);</span>
<span class="p">}</span>
<span class="c1">// compiles to </span>
<span class="kd">function</span> <span class="nx">SongName</span><span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="nx">React</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span>
<span class="dl">'</span><span class="s1">span</span><span class="dl">'</span><span class="p">,</span>
<span class="p">{</span><span class="na">className</span><span class="p">:</span> <span class="dl">'</span><span class="s1">song-name</span><span class="dl">'</span> <span class="p">},</span>
<span class="nx">props</span><span class="p">.</span><span class="nx">song</span><span class="p">.</span><span class="nx">name</span>
<span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">React.createElement</code> function signature looks like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">React</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span> <span class="nx">string</span><span class="o">|</span><span class="nx">element</span><span class="p">,</span> <span class="p">[</span><span class="nx">propsObject</span><span class="p">],</span> <span class="p">[</span><span class="nx">children</span><span class="p">...]</span> <span class="p">)</span>
</code></pre></div></div>
<h3 id="2-wrap-jsx-return-statement-with-a-tag">2. Wrap JSX return statement with a Tag</h3>
<p>The following code won’t compile</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="o"><</span><span class="nx">Hello</span><span class="o">/></span> <span class="o"><</span><span class="nx">World</span><span class="o">/></span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Because it returns two things at once, which is wrong, looks like:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="nx">Hello</span><span class="p">,</span> <span class="kc">null</span><span class="p">)</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="nx">World</span><span class="p">,</span> <span class="kc">null</span><span class="p">));</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Conclusions:</p>
<ol>
<li>
<p>Wrap With <code class="language-plaintext highlighter-rouge"><div><MyStuff /></div></code>, works for most of the time</p>
</li>
<li>
<p>If <code class="language-plaintext highlighter-rouge"><div></code> is not an option, React’s answer is the <code class="language-plaintext highlighter-rouge">Fragment</code> (since React 16.2). After rendering, the <code class="language-plaintext highlighter-rouge">React.Fragment</code> component will “disappear”.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">function</span> <span class="nx">NameCells</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">React</span><span class="p">.</span><span class="nx">Fragment</span><span class="o">></span>
<span class="o"><</span><span class="nx">td</span><span class="o">></span><span class="nx">First</span> <span class="nx">Name</span><span class="o"><</span><span class="sr">/td></span><span class="err">
</span> <span class="o"><</span><span class="nx">td</span><span class="o">></span><span class="nx">Last</span> <span class="nx">Name</span><span class="o"><</span><span class="sr">/td></span><span class="err">
</span> <span class="o"><</span><span class="sr">/React.Fragment></span><span class="err">
</span> <span class="p">);</span>
<span class="p">}</span>
</code></pre></div> </div>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge"><></></code> syntax is the preferred way to write fragments</p>
</li>
</ol>
<h3 id="3-javascript-in-jsx">3. Javascript in JSX</h3>
<p>JS inside the braces must be an expression (not a statement). Or say, it produces a value.</p>
<p>Expression vs Statement</p>
<ul>
<li>
<p>Expression returns a value no matter what. E.g.,</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="mi">1</span><span class="o">+</span><span class="mi">1</span> <span class="c1">// return 2</span>
<span class="nx">thisIsAMethodCall</span><span class="p">()</span> <span class="c1">// return a value, null or sth</span>
<span class="nx">thisIsAMethodReference</span> <span class="c1">// return a reference</span>
</code></pre></div> </div>
</li>
<li>
<p>Statement does not produce values and can’t be used inside JSX</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">const</span> <span class="nx">a</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1">// no return value</span>
<span class="k">if</span><span class="p">(</span><span class="kc">true</span><span class="p">){</span><span class="nx">haha</span><span class="p">();}</span>
</code></pre></div> </div>
</li>
</ul>
<h3 id="4-passing-props-to-a-component">4. Passing Props to a component</h3>
<p>Like HTML elements have “attributes,” React components have “props”.
Props let you pass data to your components.</p>
<ol>
<li>
<p>Passing Props</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">function</span> <span class="nx">Dave</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">firstName</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Dave</span><span class="dl">"</span><span class="p">;</span> <span class="c1">// author of the book "Pure React"</span>
<span class="kd">const</span> <span class="nx">lastName</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Ceddia</span><span class="dl">"</span><span class="p">;</span><span class="c1">// a beautiful book</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">Person</span>
<span class="nx">className</span><span class="o">=</span><span class="dl">'</span><span class="s1">person</span><span class="dl">'</span>
<span class="nx">age</span><span class="o">=</span><span class="p">{</span><span class="mi">33</span><span class="p">}</span>
<span class="nx">name</span><span class="o">=</span><span class="p">{</span><span class="nx">firstName</span> <span class="o">+</span> <span class="dl">'</span><span class="s1"> </span><span class="dl">'</span> <span class="o">+</span> <span class="nx">lastName</span><span class="p">}</span> <span class="sr">/> </span><span class="se">)</span><span class="err">;
</span> <span class="p">}</span>
</code></pre></div> </div>
</li>
<li>
<p>Receiving props using ES6 destructuring</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">const</span> <span class="nx">Hello</span> <span class="o">=</span> <span class="p">(</span><span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">name</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">props</span><span class="p">;</span>
<span class="k">return</span> <span class="p">(</span> <span class="o"><</span><span class="nx">span</span><span class="o">></span><span class="nx">Hello</span><span class="p">,</span> <span class="p">{</span><span class="nx">name</span><span class="p">}</span><span class="o"><</span><span class="sr">/span> </span><span class="se">)</span><span class="sr">;</span><span class="err">
</span> <span class="p">}</span>
</code></pre></div> </div>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">const</span> <span class="nx">Hello</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">name</span> <span class="p">})</span> <span class="o">=></span> <span class="p">(</span> <span class="o"><</span><span class="nx">span</span><span class="o">></span><span class="nx">Hello</span><span class="p">,</span> <span class="p">{</span><span class="nx">name</span><span class="p">}</span><span class="o"><</span><span class="sr">/span> </span><span class="se">)</span><span class="err">;
</span></code></pre></div> </div>
</li>
<li>
<p>Updating props</p>
<p><strong>Props are read-only</strong>.</p>
<p>If a child needs to send the updated data to its parent, the parent can send down a function as a prop.
The child would call the function reference to notify the parent that sth has happened.</p>
</li>
<li>
<p>What to pass? How exactly should you pass?</p>
<p>should you pass an object and let the component extract what it needs?
Or should you pass the specific pieces of data that the component requires?</p>
<p><strong>Answer is passing the specific pieces</strong>.</p>
<ul>
<li>For reusability - If the child expects an object with a property , then it’s locked in to that structure.</li>
<li>For flexibility - The child component should have no knowledge of the inner structure of a parent object. It’s a good idea to keep the knowledge of data structures contained to as few places as possible to reduce the cost of change.</li>
</ul>
</li>
</ol>
<h3 id="5-proptypes">5. PropTypes</h3>
<ol>
<li>
<p>Use ESLint</p>
<p><strong>ESLint</strong> helps checking for things like missing <code class="language-plaintext highlighter-rouge">PropTypes</code> and that <code class="language-plaintext highlighter-rouge">props</code> are passed correctly.</p>
</li>
<li>
<p>Common types</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">array</span>
<span class="nx">PropTypes</span><span class="p">.</span><span class="nx">bool</span>
<span class="nx">PropTypes</span><span class="p">.</span><span class="nx">func</span>
<span class="nx">PropTypes</span><span class="p">.</span><span class="nx">number</span>
<span class="nx">PropTypes</span><span class="p">.</span><span class="nx">object</span>
<span class="nx">PropTypes</span><span class="p">.</span><span class="nx">string</span>
</code></pre></div> </div>
</li>
<li>
<p>node & element</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">PropTypes.node</code>
<ul>
<li>A <code class="language-plaintext highlighter-rouge">node</code> is anything that can be rendered, meaning numbers, strings, elements, or an array of those.</li>
<li>component to accept zero, one, or more children</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">PropTypes.element</code>
<ul>
<li>An <code class="language-plaintext highlighter-rouge">element</code> is a React element created with <code class="language-plaintext highlighter-rouge">JSX</code> or by calling <code class="language-plaintext highlighter-rouge">React.createElement</code></li>
<li>want to accept only a single child</li>
</ul>
</li>
</ul>
</li>
<li>
<p>property validator</p>
<ul>
<li><code class="language-plaintext highlighter-rouge">PropTypes.instanceOf(SpecificClass)</code></li>
<li><code class="language-plaintext highlighter-rouge">PropTypes.oneOf(['person', 'place', 1234])</code> limit to specific values</li>
<li><code class="language-plaintext highlighter-rouge">PropTypes.arrayOf(PropTypes.string)</code> it’s an array of a certain type
<ul>
<li>Would match: <code class="language-plaintext highlighter-rouge">['a', 'b', 'c']</code></li>
<li>Would not match: <code class="language-plaintext highlighter-rouge">['a', 'b', 42]</code></li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">PropTypes.objectOf(PropTypes.number)</code> properties are values of a certain type
<ul>
<li>Would match: <code class="language-plaintext highlighter-rouge">{age: 27, birthMonth: 9}</code></li>
<li>Would not match: <code class="language-plaintext highlighter-rouge">{age: 27, name: 'Joe'}</code></li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">PropTypes.shape({ name: PropTypes.string, age: PropTypes.number })</code> an object has a certain shape. The object passed to this prop is allowed to have extra properties too, but it must at least have the ones in the shape description.</li>
</ul>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">function</span> <span class="nx">Author</span><span class="p">({</span> <span class="nx">author</span> <span class="p">})</span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">{</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">handle</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">author</span><span class="p">;</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">author</span><span class="dl">"</span><span class="o">></span>
<span class="o"><</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">name</span><span class="dl">"</span><span class="o">></span><span class="p">{</span><span class="nx">name</span><span class="p">}</span><span class="o"><</span><span class="sr">/span</span><span class="err">>
</span> <span class="o"><</span><span class="nx">span</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">handle</span><span class="dl">"</span><span class="o">></span><span class="p">@{</span><span class="nx">handle</span><span class="p">}</span><span class="o"><</span><span class="sr">/span</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/span> </span><span class="se">)</span><span class="err">;
</span> <span class="p">}</span>
<span class="nx">Author</span><span class="p">.</span><span class="nx">propTypes</span> <span class="o">=</span> <span class="p">{</span>
<span class="na">author</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">shape</span><span class="p">({</span>
<span class="na">name</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">string</span><span class="p">.</span><span class="nx">isRequired</span><span class="p">,</span>
<span class="na">handle</span><span class="p">:</span> <span class="nx">PropTypes</span><span class="p">.</span><span class="nx">string</span><span class="p">.</span><span class="nx">isRequired</span>
<span class="p">}).</span><span class="nx">isRequired</span>
<span class="p">};</span>
</code></pre></div> </div>
</li>
<li>
<p>How explicit should you be?</p>
</li>
</ol>
<ul>
<li>follow the DRY (Don’t Repeat Yourself) principle.</li>
<li>If you go overboard with shape it could be a pain to maintain later.</li>
<li>If you have an explicit object shape required in one place, there’s little value in duplicating the shape in the parent component.</li>
</ul>
<h3 id="6-the-key-prop">6. The “key” Prop</h3>
<p>React uses <code class="language-plaintext highlighter-rouge">key</code> to tell components apart when <strong>reconciling</strong> differences during a re-render.</p>
<p>keys should be stable, permanent, and unique for each element in the array
- <strong>Stable</strong>: An element should always have the same key, regardless of its position in the array. This means <code class="language-plaintext highlighter-rouge">key={index}</code> is a bad choice.
- <strong>Permanent</strong>: An element’s key must not change between renders. This means <code class="language-plaintext highlighter-rouge">key={Math.random()}</code> or <code class="language-plaintext highlighter-rouge">key={UUID}</code> is a bad choice.
- <strong>Unique</strong>: No two elements should have the same key. If items don’t have unique id, try combining several fields.</p>
<h2 id="2-react-state">2. React State</h2>
<p><code class="language-plaintext highlighter-rouge">props</code> are read-only. You need <code class="language-plaintext highlighter-rouge">state</code> to keep track of data change.</p>
<p>React has two ways of adding state to components:</p>
<ul>
<li>maintain state in Class component</li>
<li>use hooks to add state directly to a function component</li>
</ul>
<h3 id="1-setstate-in-class-component">1. setState in Class Component</h3>
<p>Two ways of setState here: <code class="language-plaintext highlighter-rouge">setState</code> accepts an object, and <code class="language-plaintext highlighter-rouge">setState</code> accepts a function.</p>
<ol>
<li>
<p><code class="language-plaintext highlighter-rouge">setState</code> accepts an object.</p>
<p>The <code class="language-plaintext highlighter-rouge">setState</code> function will update the state and then re-render the component and all of its children.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">class</span> <span class="nx">CountingParent</span> <span class="kd">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">state</span> <span class="o">=</span> <span class="p">{</span> <span class="na">actionCount</span><span class="p">:</span> <span class="mi">0</span> <span class="p">};</span>
<span class="nx">handleAction</span> <span class="o">=</span> <span class="p">(</span><span class="nx">action</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span> <span class="na">actionCount</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">actionCount</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">});</span>
<span class="p">}</span>
<span class="c1">// sth else ...</span>
<span class="p">}</span>
</code></pre></div> </div>
</li>
<li>
<p>Functional <code class="language-plaintext highlighter-rouge">setState</code>.</p>
<p>You pass a function to <code class="language-plaintext highlighter-rouge">setState</code> instead of an object. The function receives the current state and props as arguments, and it is expected to return an object, which will be merged with the old state.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">((</span><span class="nx">state</span><span class="p">,</span> <span class="nx">props</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span> <span class="na">value</span><span class="p">:</span> <span class="nx">state</span><span class="p">.</span><span class="nx">value</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">}</span> <span class="p">}</span>
<span class="p">);</span>
</code></pre></div> </div>
</li>
<li>
<p>Prefer functinal setState</p>
<ul>
<li>it’s guaranteed to work correctly (in correct order)</li>
<li>functional <code class="language-plaintext highlighter-rouge">setState</code> are “pure” functions – that is, they only operate on their arguments, they don’t modify the arguments, and they return a new value.</li>
</ul>
</li>
</ol>
<h3 id="2-class-component-lifecycle">2. Class Component lifecycle</h3>
<p>Phases: Mount, Render, Commit and Unmount.</p>
<ol>
<li><strong>Mount</strong>
<ul>
<li>when the component is first added to the DOM.</li>
<li>Initialization and setup are done here.</li>
<li>These methods are called <strong>only once</strong>, when the component first mounts.
<ul>
<li>constructor</li>
<li><code class="language-plaintext highlighter-rouge">componentDidMount</code>
<ul>
<li>Called immediately after the first render.</li>
<li>The component’s children are already rendered at this point.</li>
<li>This is a good place to make AJAX requests to fetch any data you need.</li>
</ul>
</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">componentWillMount</code> <strong>deprecated</strong>. Use <code class="language-plaintext highlighter-rouge">componentDidMount</code> instead.</li>
</ul>
</li>
<li><strong>Rendering</strong> These are called, in order, before and after <strong>each render</strong>
<ul>
<li><code class="language-plaintext highlighter-rouge">componentWillReceiveProps(nextProps)</code> deprecated. Use <code class="language-plaintext highlighter-rouge">getDerivedStateFromProps</code> instead.</li>
<li><code class="language-plaintext highlighter-rouge">static getDerivedStateFromProps(nextProps, prevState)</code> This method must not have side effects. Don’t call setState here, but instead, return an object that represents the new state.</li>
<li><code class="language-plaintext highlighter-rouge">shouldComponentUpdate(nextProps, nextState)</code>: an opportunity to prevent rendering if you know that props and state have not changed.</li>
<li><code class="language-plaintext highlighter-rouge">componentWillUpdate(nextProps, nextState)</code> deprecated. Use <code class="language-plaintext highlighter-rouge">getSnapshotBeforeUpdate</code></li>
<li><code class="language-plaintext highlighter-rouge">render</code> between <code class="language-plaintext highlighter-rouge">componentWillUpdate</code> and <code class="language-plaintext highlighter-rouge">componentDidUpdate</code>. Despite its name, the render phase doesn’t change what you see on the page.</li>
<li><code class="language-plaintext highlighter-rouge">getSnapshotBeforeUpdate(prevProps, prevState)</code>: This is called after <code class="language-plaintext highlighter-rouge">render</code>, but before the changes are committed to the DOM. Use it to pass along anything you need to keep track of between DOM updates, e.g., tracking changes to scroll position.</li>
<li><code class="language-plaintext highlighter-rouge">componentDidUpdate(prevProps, prevState, snapshot)</code>: Render is done. DOM changes have been committed.</li>
</ul>
</li>
<li>
<p>Commit takes the output from render and updates the DOM to match.</p>
</li>
<li>Unmount happens when the component is being removed from the DOM.
<ul>
<li><code class="language-plaintext highlighter-rouge">componentWillUnmount</code>: The component is about to be unmounted.</li>
<li>Maybe its item was removed from a list, maybe the user navigated to another tab</li>
<li>this method will only get called if componentDidMount was called.</li>
</ul>
</li>
<li><strong>Error Handling</strong>
<ul>
<li><code class="language-plaintext highlighter-rouge">componentDidCatch</code>: This method is called when a child component or one of its children throws an error</li>
</ul>
</li>
</ol>
<h3 id="3-state-in-functions-aka-hooks">3. State in Functions, aka Hooks</h3>
<ul>
<li>
<p><strong>Class components</strong> have one big state object, and a function <code class="language-plaintext highlighter-rouge">this.setState()</code> to change the whole thing at once (plus it shallow-merges the new value).</p>
</li>
<li>
<p>In <strong>functional component</strong> there’s no state either component-wide setState function. we create pieces of state in a sort of ad-hoc way, we create a small function to update this piece of state. <strong>one value, one function</strong>.</p>
</li>
</ul>
<p>The useState hook takes the initial state as an argument and it returns an array with 2 elements: the current state, and a function to change the state.</p>
<p>If your state is a complex value like an object or array, you need to take care, when updating it, to copy in all the other parts that you don’t intend to change. The <code class="language-plaintext highlighter-rouge">...</code> spread operator is a big help for making copies of arrays and objects.</p>
<p>Rule of hooks</p>
<ol>
<li>Only call hooks at the top level of your function. Don’t put them in loops, conditionals, or nested functions.</li>
<li>Only call hooks from React function components, or from custom hooks. Don’t call them from outside a component.</li>
</ol>
<h3 id="4-thinking-in-state">4. Thinking in State</h3>
<ol>
<li>
<p>Component state is for storing UI state – things that affect the visual rendering of the page. If modifying a piece of data does not visually change the component, that data shouldn’t go into state.</p>
<p>Good to be in state:</p>
<ul>
<li>User-entered input (values of text boxes and other form fields)</li>
<li>Current or selected item (the current tab, the selected row)</li>
<li>Data from the server (a list of products, the number of “likes” on a page)</li>
<li>Open/closed state (modal open/closed, sidebar expanded/hidden)</li>
</ul>
<p>Not good to be in state:</p>
<ul>
<li>handles to timers and event handlers, should be stored on the component instance itself, store them in <code class="language-plaintext highlighter-rouge">this</code> object available in class components</li>
</ul>
</li>
<li>
<p>State can initialize values from the <code class="language-plaintext highlighter-rouge">prop</code> which the component will then control</p>
</li>
<li>
<p>Avoid copying <code class="language-plaintext highlighter-rouge">props</code> into <code class="language-plaintext highlighter-rouge">state</code>. It creates a second source of truth for your data, which usually leads to bugs. A component will receive fresh props from its parent every time it re-renders.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">// Don't do this:</span>
<span class="kd">class</span> <span class="nx">BadExample</span> <span class="kd">extends</span> <span class="nx">Component</span> <span class="p">{</span>
<span class="nx">state</span> <span class="o">=</span> <span class="p">{</span> <span class="na">data</span><span class="p">:</span> <span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">data</span> <span class="p">}</span>
<span class="p">}</span>
<span class="c1">// Do this instead:</span>
<span class="kd">class</span> <span class="nx">GoodExample</span> <span class="kd">extends</span> <span class="nx">Component</span> <span class="p">{</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span> <span class="o"><</span><span class="nx">div</span><span class="o">></span><span class="nx">The</span> <span class="nx">data</span><span class="p">:</span> <span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">props</span><span class="p">.</span><span class="nx">data</span><span class="p">}</span><span class="o"><</span><span class="sr">/div> </span><span class="se">)</span><span class="err">
</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre></div> </div>
</li>
<li>
<p>Try to keep the state in a parent component. Having fewer components containing state means fewer places to look when a bug appears.</p>
</li>
</ol>
<h3 id="5-setstate-is-asynchronous">5. setState Is Asynchronous</h3>
<p>If you call setState and immediately console.log(this.state) right afterwards, it will very likely print the old state instead of the one you just set.
each call to setState “queues” an update in the order they’re called, and when they’re executed, they receive the latest state as an argument instead of using a potentially-stale this.state.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Assume state is { count: 3 }</span>
<span class="c1">// Then call setState: this.setState({ count: 4 });</span>
<span class="c1">// Then try to print the "new" state: console.log(this.state);</span>
<span class="c1">// It'll likely print { count: 3 } // instead of { count: 4 }</span>
</code></pre></div></div>
<p>If you need to set the state and immediately act on that change, you can pass in a callback function as the second argument to setState, like this:</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">this</span><span class="p">.</span><span class="nx">setState</span><span class="p">({</span><span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Joe</span><span class="dl">'</span><span class="p">},</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// called after state has been updated </span>
<span class="c1">// and the component has been re-rendered </span>
<span class="c1">// this.state now contains { name: 'Joe' } </span>
<span class="p">});</span>
</code></pre></div></div>
<h3 id="6-thinking-declaratively-not-imperatively">6. Thinking declaratively, not imperatively</h3>
<p>It’s quite intuitive to pass pros down and send events up. However, some “event-based” things, may regard as imperative scenarios, e.g.,</p>
<ul>
<li>Open a modal dialog?</li>
<li>Or display a popup notification in the corner?</li>
<li>Or animate an icon in response to an event?</li>
</ul>
<ol>
<li>Expanding/Collapsing an Accordion control
<ul>
<li>Old way: Clicking a toggle button opens or closes the accordion by calling its toggle function. The Accordion knows whether it is open or closed.</li>
<li>
<p><strong>The declarative way</strong>: let the Accordion parent store the value in component’s state (not inside the Accordion) and decice whether open or close it. We tell the Accordion which way to render by passing <code class="language-plaintext highlighter-rouge">isOpen</code> as a prop. When <code class="language-plaintext highlighter-rouge">isOpen</code> is true, it renders as open. When <code class="language-plaintext highlighter-rouge">isOpen</code> is false, it renders as closed.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o"><</span><span class="nx">Accordion</span> <span class="nx">isOpen</span><span class="o">=</span><span class="p">{</span><span class="kc">true</span><span class="p">}</span><span class="sr">/</span><span class="err">>
</span></code></pre></div> </div>
</li>
<li>The biggest difference is that instead of the Accordion instinctively (and internally) knowing whether it is open or closed, it is told to be open or closed by whichever component renders the Accordion.</li>
</ul>
</li>
<li>Opening and Closing a Dialog
<ul>
<li>The old way: Clicking a button opens the modal. Clicking its Close button closes it.</li>
<li>
<p><strong>The declarative way</strong>: the Modal’s parent holds the state, either open or close. So, if it’s “open”, we render the Modal. If it’s “closed” we don’t render the modal. Moreover, we can pass an onClose callback to the Modal – this way the parent component gets to decide what happens when the user clicks Close.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="o"><</span><span class="nx">div</span><span class="o">></span> <span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">isModalOpen</span> <span class="o">&&</span>
<span class="o"><</span><span class="nx">Modal</span> <span class="nx">onClose</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">handleClose</span><span class="p">}</span><span class="sr">/></span><span class="err">}
</span> <span class="o"><</span><span class="sr">/div</span><span class="err">>
</span></code></pre></div> </div>
</li>
</ul>
</li>
<li>Notifications
<ul>
<li>The old way: When an event occurs (like an error), call a notification library to display a popup, like <code class="language-plaintext highlighter-rouge">toastr.error("Oh no!")</code>.</li>
<li><strong>The declarative way</strong>: Think of notifications as state. There can be 0 notifications, or 1, or 2… Store those in an array. Put a NotificationTray component somewhere near the root of the app, and pass it the messages to display. You can manage the array of messages in the root component’s state, and pass an addNotification prop down to components that need to be able to surface notifications.</li>
</ul>
</li>
<li>
<p>Animating a Change</p>
<p>Let’s say you have a badge with a counter showing the number of logged-in users. It gets this number from a prop. What if you want the badge to animate when the number changes?</p>
<ul>
<li>The old way: You might use jQuery to toggle a class that plays the animation, or use jQuery to animate the element directly.</li>
<li><strong>The declarative way</strong>: You can respond when props change by implementing the <code class="language-plaintext highlighter-rouge">componentDidUpdate</code> lifecycle method and comparing the old value to the new one. If the value changed, you can set the “animating” state to true. Then in render, when “animating” is true, set a CSS class that triggers the animation. When “animating” is false, don’t set that class.</li>
</ul>
</li>
</ol>
<h2 id="3-components-and-project-structures">3. Components and project structures</h2>
<h3 id="1-presentational-vs-container-components">1. Presentational vs Container components</h3>
<p>Architecturally, you can segment components into two kinds: <strong>Presentational</strong> (a.k.a “Dumb”) and <strong>Container</strong> (a.k.a. “Smart”).</p>
<p><strong>Presentational components are stateless</strong>.</p>
<ul>
<li>They simply accepts props and render some elements based on those props.</li>
<li>A stateless component will generally contain less logic, and will be easier to debug and test.</li>
<li>They are pure functions. They always return the same result for a given set of props, and they don’t change anything.</li>
<li>Ideally, most of your components will be presentational.</li>
<li>think about Child components. They accept data and render it, and if events need to be handled, they call back up to the parent.</li>
<li>Other kinds of common presentational components include buttons, navigation bars, links, images, etc.</li>
</ul>
<p><strong>Container components are stateful</strong>.</p>
<ul>
<li>They maintain state for themselves and any child components, and pass it down to them via props.</li>
<li>They usually pass down handler functions to children, and respond to callbacks by updating their internal state.</li>
<li>Container components are also responsible for asynchronous communication, such as AJAX calls to the server.</li>
<li>Think about Parent components.</li>
</ul>
<p>Presentational components can contain Container components, and Containers can contain Presentational components – there aren’t any strict rules for nesting.</p>
<ul>
<li>In an ideal world, you’d try to organize your app so that the components at a top level are containers.</li>
<li>In the real world this is difficult to achieve because you might have nested inputs that contain their own state, or more complicated requirements.</li>
</ul>
<h3 id="2-project-structures">2. Project structures</h3>
<p>// todo moss</p>
<h2 id="4-the-useeffect-hook">4. The useEffect hook</h2>
<p>With the useEffect hook, you can respond to lifecycle events directly inside function components. Within one function, you can do things with:</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">componentDidMount</code>,</li>
<li><code class="language-plaintext highlighter-rouge">componentDidUpdate</code>,</li>
<li><code class="language-plaintext highlighter-rouge">componentWillUnmount</code></li>
</ol>
<h3 id="1-useeffect-dependencies">1. useEffect dependencies</h3>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">fetch</span><span class="p">(</span><span class="s2">`/posts/</span><span class="p">${</span><span class="nx">blogPostId</span><span class="p">}</span><span class="s2">`</span><span class="p">)</span>
<span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="nx">content</span> <span class="o">=></span> <span class="nx">setContent</span><span class="p">(</span><span class="nx">content</span><span class="p">)</span> <span class="p">)</span>
<span class="p">},</span> <span class="p">[</span><span class="nx">blogPostId</span><span class="p">])</span>
</code></pre></div></div>
<ul>
<li>It <strong>always</strong> runs after the initial render, and there’s no way to turn that off. (this is similar to <code class="language-plaintext highlighter-rouge">componentDidMount</code>)</li>
<li>By default, with no array, your effects will execute on every render.</li>
<li>An empty array means this effect depends on nothing, it only run once.</li>
<li>The second argument of useEffect is a list of dependencies. This array should contain all the values that, if they change, should cause the effect to be recomputed.</li>
</ul>
<h3 id="2-unmount-and-cleanup">2. Unmount and cleanup</h3>
<p>Sometimes you need an effect cleanup:</p>
<ul>
<li>Effects that start a timer or interval, or</li>
<li>start a request that needs to be cancelled, or</li>
<li>add an event listener that needs to be removed</li>
</ul>
<p>Cleanup always happens when the component is unmounted,</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=></span> <span class="p">{</span>
<span class="k">return</span> <span class="p">()</span> <span class="o">=></span> <span class="nx">unsubscribeFromComments</span><span class="p">(</span><span class="nx">blogPostId</span><span class="p">);</span>
<span class="p">},</span> <span class="p">[</span><span class="nx">blogPostId</span><span class="p">])</span>
</code></pre></div></div>
<h3 id="3-something-useeffect-doesnt-work-well">3. Something useEffect doesn’t work well</h3>
<p>On making DOM changes that are visible to the user, an effect function will only fire after the browser is done with layout and paint – too late.</p>
<p><code class="language-plaintext highlighter-rouge">useLayoutEffect</code> runs the same time as <code class="language-plaintext highlighter-rouge">componentDidMount</code>, and runs <strong>synchronously</strong> between when browser has updated the DOM and before those changes are painted to the screen.</p>
<h2 id="5-the-context-api">5. The context API</h2>
<p>The <code class="language-plaintext highlighter-rouge">Context</code> is to cure the “prop drilling”, when one compnent needs to send data to a great-great-great-great… grandchild.</p>
<p>Prop drilling is a valid pattern and core to the way React works.
Prop drilling is annoying. Especially you need to pass more than one prop.
Prop drilling creates coupling between components, which makes components hard to reuse.</p>
<p>3 important pieces to the Context API:</p>
<ul>
<li>The <code class="language-plaintext highlighter-rouge">React.createContext</code> function creates the context</li>
<li>The <code class="language-plaintext highlighter-rouge">Provider</code> (returned by createContext) establishes the “electrical bus” running through a component subtree
<ul>
<li>The Provider accepts a value prop which can be whatever you want</li>
</ul>
</li>
<li>The <code class="language-plaintext highlighter-rouge">Consumer</code> (also returned by createContext) taps into the “electrical bus” to extract the data</li>
</ul>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react</span><span class="dl">"</span><span class="p">;</span>
<span class="k">import</span> <span class="nx">ReactDOM</span> <span class="k">from</span> <span class="dl">"</span><span class="s2">react-dom</span><span class="dl">"</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">UserContext</span> <span class="o">=</span> <span class="nx">React</span><span class="p">.</span><span class="nx">createContext</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">UserAvatar</span> <span class="o">=</span> <span class="p">({</span> <span class="nx">size</span> <span class="p">})</span> <span class="o">=></span> <span class="p">(</span>
<span class="o"><</span><span class="nx">UserContext</span><span class="p">.</span><span class="nx">Consumer</span><span class="o">></span>
<span class="p">{</span><span class="nx">user</span> <span class="o">=></span> <span class="p">(</span><span class="o"><</span><span class="nx">img</span> <span class="nx">src</span><span class="o">=</span><span class="p">{</span><span class="nx">user</span><span class="p">.</span><span class="nx">avatar</span><span class="p">}</span> <span class="sr">/></span><span class="se">)</span><span class="sr">}</span><span class="err">
</span> <span class="o"><</span><span class="sr">/UserContext.Consumer></span><span class="err">
</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">Nav</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">(</span>
<span class="o"><</span><span class="nx">div</span> <span class="nx">className</span><span class="o">=</span><span class="dl">"</span><span class="s2">nav</span><span class="dl">"</span><span class="o">></span>
<span class="o"><</span><span class="nx">UserAvatar</span> <span class="nx">size</span><span class="o">=</span><span class="dl">"</span><span class="s2">small</span><span class="dl">"</span> <span class="o">/></span>
<span class="o"><</span><span class="sr">/div></span><span class="err">
</span><span class="p">);</span>
<span class="c1">// Inside App, we make the context available using the Provider</span>
<span class="kd">class</span> <span class="nx">App</span> <span class="kd">extends</span> <span class="nx">React</span><span class="p">.</span><span class="nx">Component</span> <span class="p">{</span>
<span class="nx">state</span> <span class="o">=</span> <span class="p">{</span><span class="na">user</span><span class="p">:</span> <span class="p">{</span> <span class="na">avatar</span><span class="p">:</span><span class="dl">"</span><span class="s2">https://www.gravatar.com/avatar/5c3dd2d257ff0e14dbd2583485dbd44b</span><span class="dl">"</span><span class="p">}};</span>
<span class="nx">render</span><span class="p">()</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span>
<span class="o"><</span><span class="nx">UserContext</span><span class="p">.</span><span class="nx">Provider</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="k">this</span><span class="p">.</span><span class="nx">state</span><span class="p">.</span><span class="nx">user</span><span class="p">}</span><span class="o">></span>
<span class="o"><</span><span class="nx">Nav</span> <span class="o">/></span>
<span class="o"><</span><span class="nx">Body</span> <span class="o">/></span>
<span class="o"><</span><span class="sr">/UserContext.Provider></span><span class="err">
</span> <span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="4-react-form">4. React form</h2>
<h3 id="1-controlled-input-component">1. Controlled input component</h3>
<p>In controlled component, <strong>you</strong> are responsible for controlling their state. You need to pass in a value, and keep that value updated as the user types.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">InputExample</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
<span class="kd">const</span> <span class="p">[</span><span class="nx">text</span><span class="p">,</span> <span class="nx">setText</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="dl">''</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">handleChange</span> <span class="o">=</span> <span class="nx">event</span> <span class="o">=></span> <span class="p">{</span>
<span class="nx">setText</span><span class="p">(</span><span class="nx">event</span><span class="p">.</span><span class="nx">target</span><span class="p">.</span><span class="nx">value</span><span class="p">);</span>
<span class="p">};</span>
<span class="k">return</span> <span class="p">(</span><span class="o"><</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">text</span><span class="dl">"</span> <span class="nx">value</span><span class="o">=</span><span class="p">{</span><span class="nx">text</span><span class="p">}</span> <span class="nx">onChange</span><span class="o">=</span><span class="p">{</span><span class="nx">handleChange</span><span class="p">}</span> <span class="sr">/></span><span class="se">)</span><span class="err">;
</span><span class="p">}</span>
</code></pre></div></div>
<h3 id="2-uncontrolled-input-component">2. Uncontrolled input component</h3>
<p>When an input is uncontrolled, it manages its own internal state.</p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">EasyInput</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">(</span> <span class="o"><</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">text</span><span class="dl">"</span> <span class="o">/></span> <span class="p">);</span>
</code></pre></div></div>
<p>When you want to get a value out of it, you have two options.</p>
<ol>
<li>
<p>you can pass an <code class="language-plaintext highlighter-rouge">onChange</code> prop and respond to the events. The downside with this is that you can’t easily extract a value at will. You need to listen to the changes, and keep track of the “most recent value” somewhere, probably in state. So it doesn’t save much code over using a controlled input.</p>
</li>
<li>
<p>Alternatively, you can use a ref. A ref gives you access to the input’s underlying DOM node, so you can pull out its value directly.</p>
<ul>
<li>Note that <code class="language-plaintext highlighter-rouge">refs</code> can only be used to refer to regular elements (div, input, etc) and stateful (class) components.</li>
<li>Function components don’t have a backing instance so there’s no way to refer to them.</li>
</ul>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useRef</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">RefInput</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">input</span> <span class="o">=</span> <span class="nx">useRef</span><span class="p">();</span>
<span class="kd">const</span> <span class="nx">showValue</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span> <span class="nx">alert</span><span class="p">(</span><span class="s2">`Input contains: </span><span class="p">${</span><span class="nx">input</span><span class="p">.</span><span class="nx">current</span><span class="p">.</span><span class="nx">value</span><span class="p">}</span><span class="s2">`</span><span class="p">);</span> <span class="p">};</span>
<span class="k">return</span> <span class="p">(</span> <span class="o"><</span><span class="nx">div</span><span class="o">></span>
<span class="o"><</span><span class="nx">input</span> <span class="nx">type</span><span class="o">=</span><span class="dl">"</span><span class="s2">text</span><span class="dl">"</span> <span class="nx">ref</span><span class="o">=</span><span class="p">{</span><span class="nx">input</span><span class="p">}</span> <span class="sr">/</span><span class="err">>
</span> <span class="o"><</span><span class="nx">button</span> <span class="nx">onClick</span><span class="o">=</span><span class="p">{</span><span class="nx">showValue</span><span class="p">}</span><span class="o">></span>
<span class="nx">Alert</span> <span class="nx">the</span> <span class="nx">Value</span><span class="o">!</span>
<span class="o"><</span><span class="sr">/button</span><span class="err">>
</span> <span class="o"><</span><span class="sr">/div> </span><span class="se">)</span><span class="sr">; }</span><span class="err">;
</span></code></pre></div> </div>
</li>
</ol>
<h2 id="references">References</h2>
<ul>
<li><a href="https://daveceddia.com/archives">Dave Ceddia blog</a></li>
<li><a href="https://www.purereact.com">Dave Ceddia book - Pure React</a></li>
</ul>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioLearn some React basics.Quarkus API First Development2021-01-23T00:00:00+00:002021-01-23T00:00:00+00:00https://mossgreen.github.io/Quarkus-Api-First-Development<p>With Swagger Open API</p>
<h2 id="jargons">Jargons</h2>
<ul>
<li>API first development</li>
</ul>
<h2 id="steps">Steps</h2>
<h3 id="1-create-a-quarkus-project">1. Create a Quarkus project</h3>
<ol>
<li>from <code class="language-plaintext highlighter-rouge">https://code.quarkus.io/</code> with RestEasy etc. plugins</li>
<li>open project, remove existing controllers and tests</li>
</ol>
<h3 id="2-update-pom-to-include-swagger">2. Update Pom to include swagger</h3>
<ol>
<li>
<p>get demo file from <code class="language-plaintext highlighter-rouge">https://editor.swagger.io/</code>.</p>
<p>for the demo, we will replace <code class="language-plaintext highlighter-rouge">- "multipart/form-data"</code> with <code class="language-plaintext highlighter-rouge">- "application/json"</code></p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">swagger</span><span class="pi">:</span> <span class="s2">"</span><span class="s">2.0"</span>
<span class="na">info</span><span class="pi">:</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">This</span><span class="nv"> </span><span class="s">is</span><span class="nv"> </span><span class="s">a</span><span class="nv"> </span><span class="s">sample</span><span class="nv"> </span><span class="s">server</span><span class="nv"> </span><span class="s">Petstore</span><span class="nv"> </span><span class="s">server.</span><span class="nv"> </span><span class="s">You</span><span class="nv"> </span><span class="s">can</span><span class="nv"> </span><span class="s">find</span><span class="nv"> </span><span class="s">out</span><span class="nv"> </span><span class="s">more</span><span class="nv"> </span><span class="s">about</span><span class="nv"> </span><span class="s">Swagger</span><span class="nv"> </span><span class="s">at</span><span class="nv"> </span><span class="s">[http://swagger.io](http://swagger.io)</span><span class="nv"> </span><span class="s">or</span><span class="nv"> </span><span class="s">on</span><span class="nv"> </span><span class="s">[irc.freenode.net,</span><span class="nv"> </span><span class="s">#swagger](http://swagger.io/irc/).</span><span class="nv"> </span><span class="s">For</span><span class="nv"> </span><span class="s">this</span><span class="nv"> </span><span class="s">sample,</span><span class="nv"> </span><span class="s">you</span><span class="nv"> </span><span class="s">can</span><span class="nv"> </span><span class="s">use</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">api</span><span class="nv"> </span><span class="s">key</span><span class="nv"> </span><span class="s">`special-key`</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">test</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">authorization</span><span class="nv"> </span><span class="s">filters."</span>
<span class="na">version</span><span class="pi">:</span> <span class="s2">"</span><span class="s">1.0.0"</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Swagger</span><span class="nv"> </span><span class="s">Petstore"</span>
<span class="na">termsOfService</span><span class="pi">:</span> <span class="s2">"</span><span class="s">http://swagger.io/terms/"</span>
<span class="na">contact</span><span class="pi">:</span>
<span class="na">email</span><span class="pi">:</span> <span class="s2">"</span><span class="s">apiteam@swagger.io"</span>
<span class="na">license</span><span class="pi">:</span>
<span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Apache</span><span class="nv"> </span><span class="s">2.0"</span>
<span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">http://www.apache.org/licenses/LICENSE-2.0.html"</span>
<span class="na">host</span><span class="pi">:</span> <span class="s2">"</span><span class="s">petstore.swagger.io"</span>
<span class="na">basePath</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/v2"</span>
<span class="na">tags</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">pet"</span>
<span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Everything</span><span class="nv"> </span><span class="s">about</span><span class="nv"> </span><span class="s">your</span><span class="nv"> </span><span class="s">Pets"</span>
<span class="s">...</span>
</code></pre></div> </div>
</li>
<li>
<p>add swagger dependency</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="nt"><dependency></span>
<span class="nt"><groupId></span>io.swagger.core.v3<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>swagger-annotations<span class="nt"></artifactId></span>
<span class="nt"><version></span>2.1.4<span class="nt"></version></span>
<span class="nt"></dependency></span>
</code></pre></div> </div>
</li>
<li>
<p>update mvn profiles</p>
</li>
</ol>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><profile></span>
<span class="nt"><id></span>swagger-generation<span class="nt"></id></span>
<span class="nt"><activation></span>
<span class="nt"><file></span>
<span class="nt"><exists></span>swagger/swagger.yml<span class="nt"></exists></span>
<span class="nt"></file></span>
<span class="nt"></activation></span>
<span class="nt"><build></span>
<span class="nt"><plugins></span>
<span class="nt"><plugin></span>
<span class="nt"><groupId></span>org.jacoco<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>jacoco-maven-plugin<span class="nt"></artifactId></span>
<span class="nt"><version></span>0.8.5<span class="nt"></version></span>
<span class="nt"><configuration></span>
<span class="nt"><excludes></span>
<span class="nt"><exclude></span>**/model/*<span class="nt"></exclude></span>
<span class="nt"><exclude></span>**/dto/*<span class="nt"></exclude></span>
<span class="nt"><exclude></span>**/configuration/*<span class="nt"></exclude></span>
<span class="nt"><exclude></span>**/filter/*<span class="nt"></exclude></span>
<span class="nt"></excludes></span>
<span class="nt"></configuration></span>
<span class="nt"><executions></span>
<span class="nt"><execution></span>
<span class="nt"><goals></span>
<span class="nt"><goal></span>prepare-agent<span class="nt"></goal></span>
<span class="nt"></goals></span>
<span class="nt"></execution></span>
<span class="nt"><execution></span>
<span class="nt"><id></span>report<span class="nt"></id></span>
<span class="nt"><phase></span>prepare-package<span class="nt"></phase></span>
<span class="nt"><goals></span>
<span class="nt"><goal></span>report<span class="nt"></goal></span>
<span class="nt"></goals></span>
<span class="nt"></execution></span>
<span class="nt"></executions></span>
<span class="nt"></plugin></span>
<span class="nt"><plugin></span>
<span class="nt"><groupId></span>io.swagger.codegen.v3<span class="nt"></groupId></span>
<span class="nt"><artifactId></span>swagger-codegen-maven-plugin<span class="nt"></artifactId></span>
<span class="nt"><version></span>3.0.22<span class="nt"></version></span>
<span class="nt"><executions></span>
<span class="nt"><execution></span>
<span class="nt"><id></span>generate-api<span class="nt"></id></span>
<span class="nt"><phase></span>generate-sources<span class="nt"></phase></span>
<span class="nt"><goals></span>
<span class="nt"><goal></span>generate<span class="nt"></goal></span>
<span class="nt"></goals></span>
<span class="nt"><configuration></span>
<span class="nt"><inputSpec></span>${project.basedir}/swagger/swagger.yml<span class="nt"></inputSpec></span>
<span class="nt"><language></span>jaxrs-resteasy-eap<span class="nt"></language></span>
<span class="nt"><generateSupportingFiles></span>false<span class="nt"></generateSupportingFiles></span>
<span class="nt"><apiPackage></span>define.your.package.here<span class="nt"></apiPackage></span>
<span class="nt"><modelPackage></span>define.your.package.here<span class="nt"><modelPackage></span>
<span class="nt"><configOptions></span>
<span class="nt"><useTags></span>true<span class="nt"></useTags></span>
<span class="nt"><useSwaggerFeature></span>true<span class="nt"></useSwaggerFeature></span>
<span class="nt"><dateLibrary></span>java8<span class="nt"></dateLibrary></span>
<span class="nt"><java8></span>true<span class="nt"></java8></span>
<span class="nt"><interfaceOnly></span>true<span class="nt"></interfaceOnly></span>
<span class="nt"><bigDecimalAsString></span>true<span class="nt"></bigDecimalAsString></span>
<span class="nt"><sourceFolder></span>src/gen/java/main<span class="nt"></sourceFolder></span>
<span class="nt"></configOptions></span>
<span class="nt"></configuration></span>
<span class="nt"></execution></span>
<span class="nt"></executions></span>
<span class="nt"></plugin></span>
<span class="nt"></plugins></span>
<span class="nt"></build></span>
<span class="nt"></profile></span>
</code></pre></div></div>
<h3 id="3-create-swagger-file">3. Create Swagger file</h3>
<p>create a folder under the root, create a file in the folder, named <code class="language-plaintext highlighter-rouge">swagger.yml</code></p>
<h3 id="4-genereate-your-files">4. genereate your files</h3>
<p>do <code class="language-plaintext highlighter-rouge">mvn clean install</code>, you can see the generated files in <code class="language-plaintext highlighter-rouge">target/generated-sources/swagger/src/gen/java/main/io/swagger/api/PetApi.java</code></p>
<p>to use it, define you controller and implement this interface. It will prompt you to implement the methods defined in Swagger.</p>
<h2 id="references">References</h2>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioWith Swagger Open APIAWS CloudFormation 1012020-12-14T00:00:00+00:002020-12-14T00:00:00+00:00https://mossgreen.github.io/AWS-CloudFormation-101<p>Simplify infrastructure management</p>
<h2 id="jargons">Jargons</h2>
<ul>
<li>
<p>CloudFormation:
AWS CloudFormation is a service that helps you model and set up your AWS resources so that you can spend less time managing those resources and more time focusing on your applications that run in AWS.</p>
</li>
<li>template:
<ul>
<li>CloudFormation uses these templates as blueprints for building your AWS resources.</li>
<li>A template is a declaration of the AWS resources that make up a stack.</li>
</ul>
</li>
<li>
<p>CloudFormation functions</p>
</li>
<li>
<p>Stack: related resources as a single unit called a stack.</p>
</li>
<li>
<p>Change sets: a preview of changes that will be executed by stack operations to create, update, or remove resources.</p>
</li>
<li>
<p>StackSets: is a group of stacks you manage together that can replicate a group.</p>
</li>
<li>CloudFormation registry</li>
</ul>
<h2 id="cloudformation-template">CloudFormation Template</h2>
<ul>
<li>
<p><code class="language-plaintext highlighter-rouge">Template</code> includes six top-level sections: <code class="language-plaintext highlighter-rouge">AWSTemplateFormatVersion</code>, <code class="language-plaintext highlighter-rouge">Description</code>, <code class="language-plaintext highlighter-rouge">Parameters</code>, <code class="language-plaintext highlighter-rouge">Mappings</code>, <code class="language-plaintext highlighter-rouge">Resources</code>, and <code class="language-plaintext highlighter-rouge">Outputs</code>. Only the Resources section is required. Others are optional.</p>
</li>
<li>
<p>The <code class="language-plaintext highlighter-rouge">Resources</code> section contains the definitions of the AWS resources you want to create with the template. Each resource is listed separately and specifies the properties that are necessary for creating that particular resource.</p>
</li>
<li>
<p>You use the <code class="language-plaintext highlighter-rouge">Parameters</code> section to declare values that can be passed to the template when you create the stack.</p>
</li>
<li>
<p>A <code class="language-plaintext highlighter-rouge">parameter</code> is an effective way to specify sensitive information, such as user names and passwords, that you don’t want to store in the template itself.</p>
</li>
</ul>
<h3 id="resources">Resources</h3>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Resources</span><span class="pi">:</span>
<span class="na">HelloBucket</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::S3::Bucket</span>
</code></pre></div></div>
<ul>
<li>When CloudFormation creates the resource, it generates a physical name that is based on the combination of the logical name, the stack name, and a unique ID.</li>
<li>The Resources object contains a list of resource objects</li>
<li>A resource must have a <code class="language-plaintext highlighter-rouge">Type</code> attribute, format: <code class="language-plaintext highlighter-rouge">AWS::ProductIdentifier::ResourceType</code>, in this case: <code class="language-plaintext highlighter-rouge">Type: AWS::S3::Bucket</code></li>
<li>Logical ID: Use the logical name to reference the resource in other parts of the template.</li>
<li>Creating a bucket with default settings, don’t need more <code class="language-plaintext highlighter-rouge">Properties</code>, however</li>
<li>
<p>when you create a EC2, which requires more infomation other then default settings, use <code class="language-plaintext highlighter-rouge">Properties</code> attribute to specify, e.g.,</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">Resources</span><span class="pi">:</span>
<span class="na">HelloBucket</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::S3::Bucket</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">AccessControl</span><span class="pi">:</span> <span class="s">PublicRead</span>
<span class="na">WebsiteConfiguration</span><span class="pi">:</span>
<span class="na">IndexDocument</span><span class="pi">:</span> <span class="s">index.html</span>
<span class="na">ErrorDocument</span><span class="pi">:</span> <span class="s">error.html</span>
</code></pre></div> </div>
</li>
</ul>
<h3 id="parameters">Parameters</h3>
<p>Parameters enable you to input custom values to your template each time you create or update a stack, so that allows us to make our template reusable.
You pass parameters either in a JSON file or as a command-line argument.</p>
<ol>
<li>how to refer to input parameters</li>
<li>receiving user input using input parameters</li>
</ol>
<h4 id="defining-a-parameter-in-a-template">Defining a parameter in a template</h4>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Parameters</span><span class="pi">:</span>
<span class="na">KeyName</span><span class="pi">:</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">The EC2 Key Pair to allow SSH access to the instance</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::KeyPair::KeyName'</span>
</code></pre></div></div>
<h4 id="referencing-a-parameter">Referencing a parameter</h4>
<ul>
<li><code class="language-plaintext highlighter-rouge">Ref</code> function to refer to an identifying property of a resource.</li>
<li>You can reference parameters from the Resources and Outputs sections of the same template.</li>
</ul>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Parameters</span><span class="pi">:</span>
<span class="na">KeyName</span><span class="pi">:</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">The EC2 Key Pair to allow SSH access to the instance</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::KeyPair::KeyName'</span>
<span class="na">Resources</span><span class="pi">:</span>
<span class="na">Ec2Instance</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::Instance'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">SecurityGroups</span><span class="pi">:</span>
<span class="pi">-</span> <span class="kt">!Ref</span> <span class="s">InstanceSecurityGroup</span>
<span class="pi">-</span> <span class="s">MyExistingSecurityGroup</span>
<span class="na">KeyName</span><span class="pi">:</span> <span class="kt">!Ref</span> <span class="s">KeyName</span>
<span class="na">ImageId</span><span class="pi">:</span> <span class="s">ami-7a11e213</span>
<span class="na">InstanceSecurityGroup</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::SecurityGroup'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">GroupDescription</span><span class="pi">:</span> <span class="s">Enable SSH access via port </span><span class="m">22</span>
<span class="na">SecurityGroupIngress</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">IpProtocol</span><span class="pi">:</span> <span class="s">tcp</span>
<span class="na">FromPort</span><span class="pi">:</span> <span class="s1">'</span><span class="s">22'</span>
<span class="na">ToPort</span><span class="pi">:</span> <span class="s1">'</span><span class="s">22'</span>
<span class="na">CidrIp</span><span class="pi">:</span> <span class="s">0.0.0.0/0</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">SecurityGroups</code> property is a list of security groups, you can add a <code class="language-plaintext highlighter-rouge">Ref</code>, and also can have you existing group names</p>
<p>Ref vs Fn::GetAtt</p>
<ol>
<li>The <code class="language-plaintext highlighter-rouge">Ref</code> function is handy if the parameter or the value returned for a resource is exactly what you want</li>
<li>need other attributes of a resource
<ul>
<li>For example, if you want to create a CloudFront distribution with an S3 origin, you need to specify the bucket location by using a DNS-style address. A number of resources have additional attributes whose values you can use in your template. To get these attributes, you use the Fn::GetAtt function.</li>
</ul>
</li>
</ol>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Resources</span><span class="pi">:</span>
<span class="na">myBucket</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::S3::Bucket'</span>
<span class="na">myDistribution</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::CloudFront::Distribution'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">DistributionConfig</span><span class="pi">:</span>
<span class="na">Origins</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">DomainName</span><span class="pi">:</span> <span class="kt">!GetAtt</span>
<span class="pi">-</span> <span class="s">myBucket</span>
<span class="pi">-</span> <span class="s">DomainName</span>
<span class="na">Id</span><span class="pi">:</span> <span class="s">myS3Origin</span>
<span class="na">S3OriginConfig</span><span class="pi">:</span> <span class="pi">{}</span>
<span class="na">Enabled</span><span class="pi">:</span> <span class="s1">'</span><span class="s">true'</span>
<span class="na">DefaultCacheBehavior</span><span class="pi">:</span>
<span class="na">TargetOriginId</span><span class="pi">:</span> <span class="s">myS3Origin</span>
<span class="na">ForwardedValues</span><span class="pi">:</span>
<span class="na">QueryString</span><span class="pi">:</span> <span class="s1">'</span><span class="s">false'</span>
<span class="na">ViewerProtocolPolicy</span><span class="pi">:</span> <span class="s">allow-all</span>
</code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">Fn::GetAtt</code> function takes two parameters in an array</p>
<ol>
<li>the logical name of the resource <code class="language-plaintext highlighter-rouge">myBucket</code></li>
<li>the name of the attribute to be retrieved <code class="language-plaintext highlighter-rouge">DomainName</code></li>
</ol>
<h4 id="parameter-declarations-restrict-and-validate-user-input">parameter declarations, restrict and validate user input</h4>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Parameters</span><span class="pi">:</span>
<span class="na">KeyName</span><span class="pi">:</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">Name of an existing EC2 KeyPair to enable SSH access into the WordPress web server</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">AWS::EC2::KeyPair::KeyName</span>
<span class="na">WordPressUser</span><span class="pi">:</span>
<span class="na">Default</span><span class="pi">:</span> <span class="s">admin</span>
<span class="na">NoEcho</span><span class="pi">:</span> <span class="no">true</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">The WordPress database admin account user name</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">String</span>
<span class="na">MinLength</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">MaxLength</span><span class="pi">:</span> <span class="m">16</span>
<span class="na">AllowedPattern</span><span class="pi">:</span> <span class="s2">"</span><span class="s">[a-zA-Z][a-zA-Z0-9]*"</span>
</code></pre></div></div>
<ul>
<li>You declare parameters the <code class="language-plaintext highlighter-rouge">Parameters</code></li>
<li>A parameter contains a list of attributes and constraints</li>
<li>The only required attribute is <strong>Type</strong>, e.g., <code class="language-plaintext highlighter-rouge">Type: AWS::EC2::KeyPair::KeyName</code></li>
<li>no <code class="language-plaintext highlighter-rouge">Default</code> will throw exception if user failed to provide one <code class="language-plaintext highlighter-rouge">Parameters: [KeyName] must have values.</code></li>
</ul>
<p>type validations</p>
<ul>
<li>AWS-specific parameter type: CloudFormation validates</li>
<li>String type: MinLength, MaxLength, Default, AllowedValues, and AllowedPattern</li>
<li>Number type: MinValue, MaxValue, Default, and AllowedValues</li>
</ul>
<p><strong>Do not embed credentials in your templates!</strong></p>
<p>Rather than embedding sensitive information directly in your CloudFormation templates, we recommend you use dynamic parameters in the stack template to reference sensitive information that is stored and managed outside of CloudFormation, such as in the AWS Systems Manager Parameter Store or AWS Secrets Manager.</p>
<h3 id="mappings">Mappings</h3>
<ul>
<li>Mappings are similar to parameters, but are provided in a dictionary format.</li>
<li>Specify the right resource based on a conditional input, e.g., region dependent resource.</li>
<li>Maintaining mappings can be troublesome, so the best way of using them is to store constant values that are rarely changed</li>
<li>
<p>There are two template features that can help, the Mappings object and the AWS::Region pseudo parameter.</p>
<ol>
<li><code class="language-plaintext highlighter-rouge">Pseudo parameters</code> resolved by CloudFormation.
<ul>
<li>The <code class="language-plaintext highlighter-rouge">AWS::Region</code> pseudo parameter enables you to get the region where the stack is created.</li>
</ul>
</li>
<li><code class="language-plaintext highlighter-rouge">Mappings</code> enable you to use an input value as a condition that determines another value. Similar to <strong>a switch statement</strong></li>
</ol>
</li>
<li><code class="language-plaintext highlighter-rouge">Fn::FindInMap</code> function takes in 3 parameters
<ol>
<li>passing the name of the map,</li>
<li>the value used to find the mapped value,</li>
<li>and the label of the mapped value you want to return.</li>
</ol>
</li>
</ul>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Parameters</span><span class="pi">:</span>
<span class="na">KeyName</span><span class="pi">:</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">Name of an existing EC2 KeyPair to enable SSH access to the instance</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">String</span>
<span class="na">Mappings</span><span class="pi">:</span>
<span class="na">RegionMap</span><span class="pi">:</span>
<span class="na">us-east-1</span><span class="pi">:</span>
<span class="na">AMI</span><span class="pi">:</span> <span class="s">ami-76f0061f</span>
<span class="na">us-west-1</span><span class="pi">:</span>
<span class="na">AMI</span><span class="pi">:</span> <span class="s">ami-655a0a20</span>
<span class="na">eu-west-1</span><span class="pi">:</span>
<span class="na">AMI</span><span class="pi">:</span> <span class="s">ami-7fd4e10b</span>
<span class="na">ap-southeast-1</span><span class="pi">:</span>
<span class="na">AMI</span><span class="pi">:</span> <span class="s">ami-72621c20</span>
<span class="na">ap-northeast-1</span><span class="pi">:</span>
<span class="na">AMI</span><span class="pi">:</span> <span class="s">ami-8e08a38f</span>
<span class="na">Resources</span><span class="pi">:</span>
<span class="na">Ec2Instance</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::Instance'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">KeyName</span><span class="pi">:</span> <span class="kt">!Ref</span> <span class="s">KeyName</span>
<span class="na">ImageId</span><span class="pi">:</span> <span class="kt">!FindInMap</span>
<span class="pi">-</span> <span class="s">RegionMap</span>
<span class="pi">-</span> <span class="kt">!Ref</span> <span class="s1">'</span><span class="s">AWS::Region'</span>
<span class="pi">-</span> <span class="s">AMI</span>
<span class="na">UserData</span><span class="pi">:</span> <span class="kt">!Base64</span> <span class="s1">'</span><span class="s">80'</span>
</code></pre></div></div>
<h3 id="conditions">Conditions</h3>
<ul>
<li>While <code class="language-plaintext highlighter-rouge">Mappings</code> is like a swith statement, <code class="language-plaintext highlighter-rouge">Conditions</code> is like a if-else statement.</li>
<li>Conditions are declared in a separate block in the template and are referred to in the resource declaration.</li>
<li>You might use conditions when you want to reuse a template that can create resources in different contexts:
<ul>
<li>add an <code class="language-plaintext highlighter-rouge">EnvironmentType</code> input parameter, which accepts either <code class="language-plaintext highlighter-rouge">prod</code> or <code class="language-plaintext highlighter-rouge">test</code> as inputs</li>
<li>For the production environment, you might include Amazon EC2 instances with certain capabilities; however, for the test environment, you want to use reduced capabilities</li>
</ul>
</li>
<li>Within each condition, you can reference another condition, a parameter value, or a mapping.</li>
<li>Depending on the entity you want to conditionally create or configure, you must include statements in the following template sections:
<ul>
<li>Parameters: Define the inputs that you want your conditions to evaluate</li>
<li>Conditions: Define conditions by using the intrinsic condition functions.</li>
<li>Resources and Outputs</li>
</ul>
</li>
<li>
<p>defination</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">Conditions</span><span class="pi">:</span>
<span class="na">Logical ID</span><span class="pi">:</span>
<span class="s">Intrinsic function</span>
</code></pre></div> </div>
</li>
<li>Condition intrinsic functions
<ul>
<li>Fn::And</li>
<li>Fn::Equals</li>
<li>Fn::If</li>
<li>Fn::Not</li>
<li>Fn::Or</li>
</ul>
</li>
<li>
<p>Example</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="na">AWSTemplateFormatVersion</span><span class="pi">:</span> <span class="s">2010-09-09</span>
<span class="na">Parameters</span><span class="pi">:</span>
<span class="na">EnvType</span><span class="pi">:</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">Environment type.</span>
<span class="na">Default</span><span class="pi">:</span> <span class="s">test</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s">String</span>
<span class="na">AllowedValues</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">prod</span>
<span class="pi">-</span> <span class="s">test</span>
<span class="na">ConstraintDescription</span><span class="pi">:</span> <span class="s">must specify prod or test.</span>
<span class="na">Conditions</span><span class="pi">:</span>
<span class="na">CreateProdResources</span><span class="pi">:</span> <span class="kt">!Equals</span>
<span class="pi">-</span> <span class="kt">!Ref</span> <span class="s">EnvType</span>
<span class="pi">-</span> <span class="s">prod</span>
<span class="na">Resources</span><span class="pi">:</span>
<span class="na">EC2Instance</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::Instance'</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">ImageId</span><span class="pi">:</span> <span class="s">ami-0ff8a91507f77f867</span>
<span class="na">MountPoint</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::VolumeAttachment'</span>
<span class="na">Condition</span><span class="pi">:</span> <span class="s">CreateProdResources</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">InstanceId</span><span class="pi">:</span> <span class="kt">!Ref</span> <span class="s">EC2Instance</span>
<span class="na">VolumeId</span><span class="pi">:</span> <span class="kt">!Ref</span> <span class="s">NewVolume</span>
<span class="na">Device</span><span class="pi">:</span> <span class="s">/dev/sdh</span>
<span class="na">NewVolume</span><span class="pi">:</span>
<span class="na">Type</span><span class="pi">:</span> <span class="s1">'</span><span class="s">AWS::EC2::Volume'</span>
<span class="na">Condition</span><span class="pi">:</span> <span class="s">CreateProdResources</span>
<span class="na">Properties</span><span class="pi">:</span>
<span class="na">Size</span><span class="pi">:</span> <span class="m">100</span>
<span class="na">AvailabilityZone</span><span class="pi">:</span> <span class="kt">!GetAtt</span>
<span class="pi">-</span> <span class="s">EC2Instance</span>
<span class="pi">-</span> <span class="s">AvailabilityZone</span>
</code></pre></div> </div>
</li>
</ul>
<h3 id="output-vs-fnjoin">Output vs Fn::Join</h3>
<ul>
<li>Outputs are the values we export from the stack after its creation.</li>
<li>
<p>Outputs can retrieve the physical name or ID of the resource or its attributes.</p>
</li>
<li><code class="language-plaintext highlighter-rouge">Fn::Join</code>
<ul>
<li>function takes two parameters, a delimiter that separates the values you want to concatenate and</li>
<li>an array of values in the order that you want them to appear.</li>
<li>
<p>e.g., the Fn::Join function specifies an empty string as the delimiter and HTTP:, the value of the WebServerPort parameter, and a / character as the values to concatenate. If WebServerPort had a value of 8888, the Target property: <code class="language-plaintext highlighter-rouge">HTTP:8888/</code></p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">HealthCheck</span><span class="pi">:</span>
<span class="na">Target</span><span class="pi">:</span> <span class="kt">!Join</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">'</span>
<span class="pi">-</span> <span class="pi">-</span> <span class="s1">'</span><span class="s">HTTP:'</span>
<span class="pi">-</span> <span class="kt">!Ref</span> <span class="s">WebServerPort</span>
<span class="pi">-</span> <span class="s">/</span>
</code></pre></div> </div>
</li>
<li>
<p><code class="language-plaintext highlighter-rouge">Fn::Join</code> function is also useful for declaring output values for the stack. An output is a convenient way to capture important information about your resources or input parameters.</p>
<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">Outputs</span><span class="pi">:</span>
<span class="na">InstallURL</span><span class="pi">:</span>
<span class="na">Value</span><span class="pi">:</span> <span class="kt">!Join</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">'</span>
<span class="pi">-</span> <span class="pi">-</span> <span class="s1">'</span><span class="s">http://'</span>
<span class="pi">-</span> <span class="kt">!GetAtt</span>
<span class="pi">-</span> <span class="s">ElasticLoadBalancer</span>
<span class="pi">-</span> <span class="s">DNSName</span>
<span class="pi">-</span> <span class="s">/wp-admin/install.php</span>
<span class="na">Description</span><span class="pi">:</span> <span class="s">Installation URL of the WordPress website</span>
<span class="na">WebsiteURL</span><span class="pi">:</span>
<span class="na">Value</span><span class="pi">:</span> <span class="kt">!Join</span>
<span class="pi">-</span> <span class="s1">'</span><span class="s">'</span>
<span class="pi">-</span> <span class="pi">-</span> <span class="s1">'</span><span class="s">http://'</span>
<span class="pi">-</span> <span class="kt">!GetAtt</span>
<span class="pi">-</span> <span class="s">ElasticLoadBalancer</span>
<span class="pi">-</span> <span class="s">DNSName</span>
</code></pre></div> </div>
<p>out put: <code class="language-plaintext highlighter-rouge">http://mywptests-elasticl-1gb51l6sl8y5v-206169572.us-east-2.elb.amazonaws.com/wp-admin/install.php</code></p>
</li>
</ul>
</li>
</ul>
<h2 id="aws-pseudo-parameters">AWS pseudo parameters</h2>
<p>They are obtained from AWS itself.</p>
<ul>
<li>AWS::AccountId
<ul>
<li>use it when we are using an IAM principal</li>
<li>it is dangerous to expose your AWS account ID, we should always stick to using AWS pseudo parameters when we specify this kind of sensitive information.</li>
</ul>
</li>
<li>
<p>AWS::NotificationARNs</p>
</li>
<li>AWS::NoValue
<ul>
<li>equivalent of the null value.</li>
</ul>
</li>
<li>AWS::Region
<ul>
<li>best practice to use this pseudo parameter, even if you don’t plan to deploy multi-regional applications</li>
<li><code class="language-plaintext highlighter-rouge">awslogs-region: !Ref "AWS::Region"</code>: create a CloudWatch log group in the same region where the stack resources were provisioned</li>
</ul>
</li>
<li>AWS::StackId</li>
<li>AWS::StackName</li>
<li>AWS::URLSuffix
<ul>
<li>needed for specifying AWS URLs. In 99% of cases, it’s going to be <code class="language-plaintext highlighter-rouge">amazonaws.com</code></li>
</ul>
</li>
<li>AWS::Partition
<ul>
<li>When we need to define an ARN of the resource manually</li>
</ul>
</li>
</ul>
<h2 id="cloudformation-vs-sam">CloudFormation vs SAM</h2>
<p>SAM template is designed to be used with serverless applications and services.</p>
<ul>
<li>AWS::Serverless::API: Creates an API gateway and related resources</li>
<li>AWS::Serverless::Application: Creates a serverless application</li>
<li>AWS::Serverless::Function: Creates a Lambda function and related resources</li>
<li>AWS::Serverless::HttpApi: Creates an HTTP API gateway and related resources</li>
<li>AWS::Serverless::LayerVersion: Creates a Lambda layer</li>
<li>AWS::Serverless::SimpleTable: Creates a simplified DynamoDB table (only a primary key without a sort key)</li>
</ul>
<h2 id="references">References</h2>
<ul>
<li><a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/gettingstarted.templatebasics.html#gettingstarted.templatebasics.parameters">Learn template basics</a></li>
</ul>Moss GUmossgu@outlook.comhttps://mossgreen.github.ioSimplify infrastructure management