<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Wilson KOMLAN's blog page]]></title><description><![CDATA[Softaware developer, Cloud developer, AWS developer, AWS architect, Java developer, full-stack developer, React developer, Web development, Gatsby website developer]]></description><link>https://blog.wilsonkomlan.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 13 Sep 2026 04:32:49 GMT</lastBuildDate><atom:link href="https://blog.wilsonkomlan.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Securing REST APIs with Amazon Cognito: A Step-by-Step Guide]]></title><description><![CDATA[Security in internet-facing or local applications is one of the most challenging parts of the software development life cycle. This post will provide a quick step-by-step guide to implementing access management for the previous REST API using Amazon ...]]></description><link>https://blog.wilsonkomlan.com/securing-rest-apis-with-amazon-cognito-a-step-by-step-guide</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/securing-rest-apis-with-amazon-cognito-a-step-by-step-guide</guid><category><![CDATA[APIs]]></category><category><![CDATA[Cognito]]></category><category><![CDATA[AWS]]></category><category><![CDATA[API Gateway]]></category><category><![CDATA[Amazon Cognito]]></category><category><![CDATA[REST API]]></category><category><![CDATA[Security]]></category><category><![CDATA[authentication]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Wed, 28 Aug 2024 21:52:09 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724881658526/964cc4d6-e227-452f-bb11-a5b2f530f205.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Security in internet-facing or local applications is one of the most challenging parts of the software development life cycle. This post will provide a quick step-by-step guide to implementing access management for <a target="_blank" href="https://blog.wilsonkomlan.com/step-by-step-guide-to-using-lambda-proxy-integrations-in-amazon-api-gateway">the previous REST API</a> using <a target="_blank" href="https://aws.amazon.com/cognito/">Amazon Cognito</a>.</p>
<h1 id="heading-prerequisites">Prerequisites</h1>
<p>You need to have an <a target="_blank" href="https://console.aws.amazon.com/console/home"><strong>AWS account</strong></a>. If you are new to AWS, they offer a 12-month free tier account where you can explore many services as a developer.</p>
<h2 id="heading-create-an-amazon-cognito-user-pool"><strong>Create an Amazon Cognito User Pool</strong></h2>
<p>Please refer to <a target="_blank" href="https://blog.wilsonkomlan.com/how-to-secure-spring-boot-rest-api-endpoints-with-amazon-cognito">this article</a> in the <strong><em>Create Amazon Cognito User Pool</em></strong> section to create a Cognito User Pool, note the <strong>Cognito User Pool ID</strong> and the App <strong>Client ID</strong>, and then continue with the following section.</p>
<h1 id="heading-enable-endpoint-access-management-in-api-gateway">Enable endpoint access management in API Gateway</h1>
<p>As you can see, any frontend or API caller can send requests to <a target="_blank" href="https://blog.wilsonkomlan.com/step-by-step-guide-to-using-lambda-proxy-integrations-in-amazon-api-gateway">these REST API endpoints</a> without including an access token in the request header. We will implement a JWT token authorizer with the Amazon Cognito User Pool created earlier.</p>
<p>Let us open the API Gateway created in <a target="_blank" href="https://blog.wilsonkomlan.com/step-by-step-guide-to-using-lambda-proxy-integrations-in-amazon-api-gateway">this article</a>.</p>
<ul>
<li>Select a method (<strong><em>POST</em></strong> for instance (1)) then, in the <strong>Route details</strong> section, click on the <strong><em>Attach authorization</em></strong> button (2).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724797615137/52598d9c-147c-4e3d-949d-bd89809bc3a1.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong>Authorization</strong> page, ensure the method is still selected and click the <strong><em>Create and attach an authorizer</em></strong> button (1).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724797982787/9a96589b-581f-4763-899c-cc681660db95.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong>Create authorizer</strong> page, choose the <strong>Authorizer type</strong>: <strong><em>JWT</em></strong> (1), and provide the Authorizer settings: <strong><em>Name</em></strong>: <em>CRUD-API-COGNITO-AUTH</em> (2), <strong><em>Identity source</em></strong>: <em>$request.header.Authorization</em> (3), <strong><em>Issuer URL</em></strong>: <code>https://cognito-idp.[zoneId].amazonaws.com/[userPoolId]</code> (4). For the <strong><em>Audience</em></strong> field, first click on the <strong><em>Add Audience</em></strong> button, then provide the <strong><em>Client ID</em></strong> (5) noted while creating the Amazon Cognito User Pool. Click the <strong><em>Create and attach</em></strong> button to attach the newly created authorizer to the API route method.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724798028722/d2cc4bdf-f458-427c-99f6-f59c690a3e8d.png" alt class="image--center mx-auto" /></p>
<ul>
<li>To attach an existing authorizer to a method, select the method, then in the <strong>Route details</strong> section, click the <strong><em>Attach authorization</em></strong> button. Choose the <strong><em>existing authorizer</em></strong> (1) and click the <strong><em>Attach authorizer</em></strong> button (2).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1724801382892/6254ec05-8a28-486d-bd54-8330a67555cd.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-test-and-wrap-up">Test and Wrap-Up</h3>
<p>Follow the <strong>Test and Recap</strong> section of <a target="_blank" href="https://blog.wilsonkomlan.com/step-by-step-guide-to-using-lambda-proxy-integrations-in-amazon-api-gateway">this article</a> and the <strong>Test the Rest API</strong> section of <a target="_blank" href="https://blog.wilsonkomlan.com/how-to-secure-spring-boot-rest-api-endpoints-with-amazon-cognito">this article</a> to test what we have implemented.</p>
<p>This guide walks through implementing access management for a REST API using Amazon Cognito. Instructions include creating a Cognito User Pool, enabling endpoint access management in API Gateway, and configuring JWT token authorizers for secure token-based access. Follow these steps to protect your API endpoints effectively.</p>
<p>Thanks for reading 😊. Your suggestions and comments are welcome. Akpé kaka 🙏!</p>
]]></content:encoded></item><item><title><![CDATA[Step-by-Step Guide to Using Lambda Proxy Integrations in Amazon API Gateway]]></title><description><![CDATA[In this post, we will create a REST API endpoint with GET and POST methods for the previous backend using Amazon API Gateway's HTTP API.
Prerequisites
All you need is just an AWS account: no worries, if you are new to AWS, AWS offers you a 12-month f...]]></description><link>https://blog.wilsonkomlan.com/step-by-step-guide-to-using-lambda-proxy-integrations-in-amazon-api-gateway</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/step-by-step-guide-to-using-lambda-proxy-integrations-in-amazon-api-gateway</guid><category><![CDATA[APIs]]></category><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[aws-apigateway]]></category><category><![CDATA[Microservices]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[backend]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Sun, 14 Jul 2024 13:45:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1720964606489/0b5de7e2-8a80-40da-89a2-0892982afdf0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this post, we will create a REST API endpoint with GET and POST methods for <a target="_blank" href="https://blog.wilsonkomlan.com/create-a-fast-nodejs-serverless-backend-using-aws-lambda-and-dynamodb">the previous backend</a> using Amazon API Gateway's HTTP API.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>All you need is just an <a target="_blank" href="https://console.aws.amazon.com/console/home">AWS account</a>: no worries, if you are new to AWS, AWS offers you a 12-month free tier account where you can play with lots of services as a developer (isn't it cool? 😜)</p>
<h3 id="heading-step-by-step-guide-to-creating-a-lambda-integration-http-api">Step-by-step guide to creating a Lambda integration HTTP API</h3>
<p><a target="_blank" href="https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html">Amazon API Gateway</a> is an AWS service that helps you create and secure REST and HTTP APIs at any scale.</p>
<p>The following steps will show you how to create an HTTP API and set up a POST method for an API resource.</p>
<p>Let's use the <a target="_blank" href="https://us-east-1.console.aws.amazon.com/apigateway/main/apis?api=unselected&amp;region=us-east-1&amp;routes=0vkpr6p">AWS console</a> to create the API Gateway.</p>
<ul>
<li>On the API Gateway dashboard menu, select <strong><em>APIs</em></strong> (1) and then click on the <strong><em>Create API</em></strong> (2) button.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720880445937/dab838d8-8b1d-45db-82ad-bb9c4766cf07.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong>Create API page</strong>, click on the <strong><em>Build</em></strong> button (1) under <strong><em>HTTP API</em></strong> section.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720880845816/1d191464-e428-40ef-ae41-fb688f2f0a22.png" alt class="image--center mx-auto" /></p>
<ul>
<li>In the <strong>Create an API</strong> step, select <strong><em>Lambda</em></strong> (1) in the <strong>Create and configure integrations</strong> section, then choose <em>us-east-1</em> as the <strong><em>AWS Region</em></strong> (2). Select the ***Lambda function:***<em>arn:aws:lambda:us-east-1:xxx:function:sample-crud-func</em> (3) we created in <a target="_blank" href="https://blog.wilsonkomlan.com/create-a-fast-nodejs-serverless-backend-using-aws-lambda-and-dynamodb">this post</a>. Then, give the <em>API name: sample-crud-api</em> (4), and click <strong><em>Next</em></strong> (5).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720880395200/9be900ad-96ee-43b3-9e07-927e32b915f6.png" alt class="image--center mx-auto" /></p>
<ul>
<li>In the <strong>Configure routes</strong> step, select <em>POST</em> as the <strong><em>Method</em></strong> (1), type <em>/api/items</em> as the <strong><em>Resource path</em></strong> (2), select <em>sample-crud-func</em> as the <strong><em>Integration target</em></strong> (3) and then click <strong><em>Next</em></strong> (4).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720882135107/780aafd9-798d-4a9c-8ade-058fde0d3abc.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Provide the <strong><em>Stage name</em></strong>*: dev* (1) and then click <strong><em>Next</em></strong> (2) in the <strong>Configure stages</strong> step.</p>
</li>
<li><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720884013458/012a60e5-87cd-4277-ab05-dcc881fce71d.png" alt class="image--center mx-auto" /></p>
</li>
<li><p>The last step is to review what we provided in the previous steps and click <strong><em>Create</em></strong> (1).</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720884551543/319c0fde-4be8-44cd-b515-8f736cb581cf.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-setting-up-the-http-get-method-for-an-existing-api-gateway-lambda-integration">Setting up the HTTP GET method for an existing API Gateway Lambda integration</h3>
<ul>
<li>Select the API we created early (<em>sample-crud-func</em>), on the <strong>API Gateway</strong> menu, choose <strong><em>Routes</em></strong> menu (1), then click <strong><em>Create</em></strong> (2).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720913039975/c9b411ea-6aea-48f9-8b8d-403d1ff1c114.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong>Create a route</strong> page, under the <strong><em>Route and method</em></strong> section, choose the <strong><em>GET</em></strong> method (1) and provide the route path: <em>/api/items</em> (2). Then, click on the <strong><em>Create</em></strong> button (3).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720913611641/cba4361c-557e-4f08-a65c-9bd2ca59d65e.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong>Routes page</strong>, under the <em>/api/items</em> tree, choose the <strong><em>GET</em></strong> method (1). In the <strong>Route details</strong> section, click on <strong><em>Attach integration</em></strong> (2).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720915444632/8c0ffbb5-c866-4dfc-a6f2-3de445534f41.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Select the <strong>Integrations</strong> menu (1). In the <strong>Attach integrations to routes</strong> tab, choose <strong><em>GET</em></strong> (2) under the <em>/api/items</em> tree. In the <strong>Integration details for route</strong> section, choose the Lambda function: <em>sample-crud-funcxxx</em> (3), then click on the <strong>Attach integration</strong> button (4).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720913205174/6866c02d-1afe-42bf-96e0-87bb1836b7c5.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-update-the-lambda-function-to-handle-the-api-http-methods">Update the Lambda function to handle the API HTTP methods</h3>
<p>Let's update <a target="_blank" href="https://blog.wilsonkomlan.com/create-a-fast-nodejs-serverless-backend-using-aws-lambda-and-dynamodb">this lambda function</a> to handle the GET and POST requests we created above.</p>
<p>As of the time we are writing this article, the version of the <a target="_blank" href="https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html#http-api-develop-integrations-lambda.proxy-format">event payload format</a> that API Gateway sends to Lambda is 2.0.</p>
<p>We will use the <strong><em>routeKey</em></strong> attribute value from the event payload to get the request route path. This will help direct traffic to the corresponding Lambda CRUD methods. Additionally, we will use the <strong><em>queryStringParameters</em></strong> attribute value to get request parameters.</p>
<p>The i<a target="_blank" href="https://github.com/wilkom2009/sample-crud-func/blob/main/index.mjs">ndex.mjs</a> file's handler function becomes this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720952737164/d78909d7-0ab9-482f-9acf-512da9a57fcd.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>An environment variable called <em>TABLE</em> is created to handle the DynamoDB table's name. We retrieve its value into the TABLE_NAME variable in <strong>line 4</strong>: <code>const TABLE_NAME = process.env.TABLE;</code>. More information about Lambda environment variables can be found <a target="_blank" href="https://docs.aws.amazon.com/lambda/latest/dg/configuration-envvars-retrieve.html">here</a>.</p>
</li>
<li><p>In <strong>line 5</strong>, we get the <em>routeKey</em> value, which is the API request's path from the API Gateway. This value will be used in <strong>line 14</strong> to call the suitable action implemented in the Lambda function.</p>
</li>
<li><p>This pattern is called <a target="_blank" href="https://docs.aws.amazon.com/lambda/latest/operatorguide/monolith.html">Lambda monolith</a>: using a single backend Lambda function to dispatch incoming traffic to multiple implemented actions. It's used for simplicity and is more suitable for small applications or monolith applications migrated to AWS Lambda. Take a look at <a target="_blank" href="https://docs.aws.amazon.com/lambda/latest/operatorguide/monolith.html">this documentation</a> for the recommendation.</p>
</li>
</ul>
<h3 id="heading-recap-and-test">Recap and test</h3>
<ul>
<li>Let's go back to the API Gateway and choose the <em>sample-crud-apixxx</em>, then choose the <strong><em>Stages</em></strong> menu (1) and <strong><em>dev</em></strong> stage (2) on the <strong>Stages</strong> page. In the <strong>Stages details</strong> section, copy the <strong><em>Invoke URL</em></strong> value (3).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720957430745/bfdfeb4e-5e43-4d34-a8ab-02ee25a62ee9.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Open Postman, choose the POST method, paste the URL, and append <em>/api/items.</em></p>
</li>
<li><p>Select the <strong>Body</strong> tab, and past the payload data (3) then click <strong><em>Send</em></strong> (4) to get the result (5) if everything is ok.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1720960053635/96c9a3c3-be0c-4a1e-b784-400a3247afb6.png" alt class="image--center mx-auto" /></p>
<p>In this post, we provided a step-by-step guide to creating an API Gateway HTTP API with Lambda proxy integrations, highlighting the Lambda monolith pattern. You can find the source code for the Lambda function <a target="_blank" href="https://github.com/wilkom2009/sample-crud-func/tree/main">here</a>.</p>
<p>Thanks for reading 😊. Your suggestions and comments are welcome. Akpé kaka 🙏!</p>
]]></content:encoded></item><item><title><![CDATA[Create a Fast Node.js Serverless Backend Using AWS Lambda and DynamoDB]]></title><description><![CDATA[In this article, we'll build a simple CRUD JavaScript-based backend with AWS. We'll use Lambda and DynamoDB to show how you can quickly create a secure and robust app backend.
Prerequisites
To follow this tutorial, you need an AWS account. Thankfully...]]></description><link>https://blog.wilsonkomlan.com/create-a-fast-nodejs-serverless-backend-using-aws-lambda-and-dynamodb</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/create-a-fast-nodejs-serverless-backend-using-aws-lambda-and-dynamodb</guid><category><![CDATA[lambda]]></category><category><![CDATA[AWS]]></category><category><![CDATA[aws lambda]]></category><category><![CDATA[DynamoDB]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[NoSQL]]></category><category><![CDATA[backend]]></category><category><![CDATA[serverless]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Sat, 15 Jun 2024 04:22:07 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718424293322/a3b80d5a-7e7e-4364-9593-7156628331e4.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In this article, we'll build a simple CRUD JavaScript-based backend with AWS. We'll use Lambda and DynamoDB to show how you can quickly create a secure and robust app backend.</p>
<h3 id="heading-prerequisites">Prerequisites</h3>
<p>To follow this tutorial, you need an <a target="_blank" href="https://console.aws.amazon.com/console/home">AWS account</a>. Thankfully, AWS offers a twelve-months free tier plan (isn't that cool? 😜).</p>
<h3 id="heading-setting-up-the-lambda-function">Setting up the Lambda function</h3>
<p>We'll use the <a target="_blank" href="https://us-east-1.console.aws.amazon.com/lambda/home?region=us-east-1#/functions">AWS console</a> to create the Lambda function.</p>
<ul>
<li>Choose your preferred region (1), type <strong><em>Lambda</em></strong> in the search field near <strong>Services</strong> (2), then click on <strong><em>Lambda</em></strong> under <strong>Services</strong> in the result list (3).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718141486999/317311fe-ac0e-4319-b6c7-476cca07141f.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong>Lambda</strong> dashboard, from the menu list on the left side, click on the <strong><em>Functions</em></strong> menu item (1), then click <strong><em>Create function</em></strong> (2).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718142792106/137411a1-45fe-42e7-b62f-7c0661e40464.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong>Create function</strong> page, select <strong><em>Author from scratch</em></strong> (1), enter the <strong><em>Function name</em></strong>: <em>sample-crud-func</em> (2), choose the <strong><em>Runtime</em></strong>: <em>Node.js 20.x</em> (3), then under <strong><em>Change default execution role</em></strong>, select <em>Create a new role with basic Lambda permissions</em> (4). Finally, click on the <strong><em>Create function</em></strong> button at the bottom.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718144619495/74b6663b-2e8e-4748-b846-88ea12b22af5.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>Once the function is ready, open the <strong><em>sample-crud-func</em></strong> function and test it.</p>
<ul>
<li>Select the <strong><em>Test</em></strong> tab (1), then as the <em>Test event action</em>, choose the <strong><em>Create new event</em></strong> option (2). Provide the <strong><em>Event name</em></strong>: <em>test</em> (3), then click the <strong><em>Test</em></strong> button.</li>
</ul>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718408009397/3ea0c1b2-3d36-4e8e-968f-d967aef0c315.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-creating-the-dynamodb-table">Creating the DynamoDB table</h3>
<p>The basic Lambda function is now ready. Before we add more logic to it, let's create the <a target="_blank" href="https://aws.amazon.com/dynamodb/">DynamoDB</a> table for data storage.</p>
<p>DynamoDB is a fully managed, serverless NoSQL database service provided by AWS for modern applications. There are no upfront costs to launch DynamoDB, and you only pay for what you use.</p>
<ul>
<li><p>Go to the DynamoDB <a target="_blank" href="https://us-east-1.console.aws.amazon.com/dynamodbv2/home?region=us-east-1#dashboard">page</a>, and choose the <strong><em>region</em></strong>. Here, we select us-east-1: N. Virginia (1). In the page menu, select <strong><em>Tables</em></strong> (2), then click on <strong><em>Create table</em></strong> button(3).</p>
<p>  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718415423611/fbdfa4b5-c0ee-43ed-ad36-e71f2df7c2e0.png" alt class="image--center mx-auto" /></p>
</li>
</ul>
<ul>
<li>Provide the <strong><em>Table name</em></strong> (<em>sampleCrudTable</em>), type the <strong><em>Partition key</em></strong> (<em>pk</em>), and then the <strong><em>Sort key</em></strong> (<em>sk</em>). To keep things simple, use the default options and click <strong><em>Create table</em></strong> at the bottom of the page.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718411033570/3c4c4ed6-fb31-4444-8ac6-fd561e8136ed.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-grant-lambda-access-to-the-dynamodb-table">Grant Lambda access to the DynamoDB table</h3>
<ul>
<li>Let's open the <em>sample-crud-func</em> Lambda function, go to the <strong><em>Configuration</em></strong> (1) tab then in the <em>Execution role section</em>, click on <strong><em>Role name</em></strong> (2) to open the created named role.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718414548036/6be68291-c32d-43a8-bac9-ca385dff3adf.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <em>sample-crud-xxx-role-xxx</em> (1) <strong>role</strong> page, open the <strong><em>Permissions</em></strong> tab (2), then click on the <strong><em>AWSLambdaBasicExecutionRole-xxx</em></strong> <strong>policy name</strong> (3).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718416186958/412e8102-1ed1-4f6f-90e9-5d452034b149.png" alt class="image--center mx-auto" /></p>
<ul>
<li>On the <strong><em>AWSLambdaBasicExecutionRole-xxx</em> policy</strong> page, open the Permissions tab (1), then click on Edit (2).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718416872935/580b6bc6-94a1-455b-b99d-1461ea2de88c.png" alt class="image--center mx-auto" /></p>
<ul>
<li><p>In the <strong><em>Edit policy</em></strong> editor, add the below permission to the permissions list:</p>
<pre><code class="lang-json">          {
              <span class="hljs-attr">"Effect"</span>: <span class="hljs-string">"Allow"</span>,
              <span class="hljs-attr">"Action"</span>: [
                  <span class="hljs-string">"dynamodb:PartiQLInsert"</span>,
                  <span class="hljs-string">"dynamodb:PartiQLUpdate"</span>,
                  <span class="hljs-string">"dynamodb:PartiQLDelete"</span>,
                  <span class="hljs-string">"dynamodb:PartiQLSelect"</span>
              ],
              <span class="hljs-attr">"Resource"</span>: [
                  <span class="hljs-string">"arn:aws:dynamodb:us-east-1:xxx:table/sampleCrudTable"</span>
              ]
          }
</code></pre>
</li>
<li><p>Note: Remember to replace xxx with your AWS account number.</p>
</li>
<li><p>Finally, the Policy editor should look like this:</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718418108359/0a7801e7-7930-44bd-834d-19fbe5646f7f.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Click on <strong><em>Next</em></strong>, then <strong><em>Save changes</em></strong> to grant the CRUD <a target="_blank" href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-gettingstarted.html">PartiQL</a> for DynamoDB statements permissions to the Lambda function.</li>
</ul>
<h3 id="heading-perform-a-crud-operation">Perform a CRUD operation</h3>
<ul>
<li>Head back to the Lambda function we created, open the <strong><em>code</em></strong> tab, and replace the content of the <strong><em>index.mjs</em></strong> file with the following code:</li>
</ul>
<pre><code class="lang-json">import { DynamoDBClient } from <span class="hljs-string">"@aws-sdk/client-dynamodb"</span>;
import {
  DynamoDBDocumentClient,
  ExecuteStatementCommand,
} from <span class="hljs-string">"@aws-sdk/lib-dynamodb"</span>;

const client = new DynamoDBClient({});
const docClient = DynamoDBDocumentClient.from(client);

const ITEM_PK = <span class="hljs-string">"ITEM"</span>;

<span class="hljs-comment">//-------SAVE ITEM FUNCTION-----------</span>
const saveItem = async (tableName, data) =&gt; {
  const SK = ITEM_PK + <span class="hljs-attr">"#"</span> + data?.label; <span class="hljs-comment">//format PK#label =&gt; manage default label sorting</span>

  let result;
  try {
    const command = new ExecuteStatementCommand({
      Statement: `INSERT INTO ${tableName} value {'pk':?,'sk':?,'label':?, 'category':?, 'price':?}`,
      Parameters: [ITEM_PK, SK, data?.label, data?.category, data?.price],
    });

    result = await docClient.send(command);
  } catch (e) {
    console.error(JSON.stringify(e));
    return e;
  }

  return result;
};

export const handler = async (event) =&gt; {
  const tableName=<span class="hljs-attr">"sampleCrudTable"</span>;

  <span class="hljs-comment">//Call save Item</span>
  await saveItem(tableName, event)
    .then((res) =&gt; {
      console.log(JSON.stringify(res))
    })
    .catch((e) =&gt; {
      console.log(JSON.stringify(e.errorMessage));
    });

  const response = {
    statusCode: <span class="hljs-number">200</span>,
    body: JSON.stringify('Hello from Lambda!'),
  };
  return response;
};
</code></pre>
<ul>
<li>To test the function, open the <strong><em>Test</em></strong> tab, replace the <strong><em>Event JSON</em></strong> editor (1) content with the following code then click <strong><em>Test</em></strong> (2).</li>
</ul>
<pre><code class="lang-json">{
  <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Paquet de Crayons de couleurs"</span>,
  <span class="hljs-attr">"price"</span>: <span class="hljs-number">30</span>,
  <span class="hljs-attr">"category"</span>: {
    <span class="hljs-attr">"id"</span>: <span class="hljs-number">1</span>,
    <span class="hljs-attr">"label"</span>: <span class="hljs-string">"Fourniture scolaire"</span>
  }
}
</code></pre>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718420064390/93ea2eed-9163-496d-b94c-f9f0f587e50d.png" alt class="image--center mx-auto" /></p>
<ul>
<li>Open the DynamoDB table, select <strong><em>Explore items</em></strong> (1) from the left menu, choose the <strong><em>sampleCrudTable</em></strong> table (2), and then click <strong><em>Run</em></strong> (3). You should see the created data (4).</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718421072081/5a6a8642-0125-4c02-b599-d41536e9145b.png" alt class="image--center mx-auto" /></p>
<p>In this article, we guided you through building a simple CRUD backend using AWS Lambda and DynamoDB. You learned how to set up a Lambda function, create a DynamoDB table, grant necessary permissions, and perform CRUD operations using JavaScript.</p>
<p>In the next articles, we'll learn how to secure and protect this backend using <a target="_blank" href="https://aws.amazon.com/es/api-gateway/">API Gateway</a> and <a target="_blank" href="https://aws.amazon.com/pm/cognito">Amazon Cognito</a>.</p>
<p>Please subscribe and share. Thanks!</p>
]]></content:encoded></item><item><title><![CDATA[Spring Boot CRUD API, Amazon RDS for MySQL, AWS Secrets Manager - example]]></title><description><![CDATA[There are many articles on how to build a real-world Spring Boot CRUD REST API or Application with MySQL as a Relational Database. In this post, we are not only going to show how to create a Spring Boot CRUD operations API, but we will also dive deep...]]></description><link>https://blog.wilsonkomlan.com/spring-boot-crud-api-amazon-rds-for-mysql-aws-secrets-manager-example</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/spring-boot-crud-api-amazon-rds-for-mysql-aws-secrets-manager-example</guid><category><![CDATA[Beginner Developers]]></category><category><![CDATA[Java]]></category><category><![CDATA[AWS]]></category><category><![CDATA[MySQL]]></category><category><![CDATA[Springboot]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Sat, 11 Jun 2022 12:04:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950880589/eeelwKD_b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are many articles on how to build a real-world Spring Boot CRUD REST API or Application with MySQL as a Relational Database. In this post, we are not only going to show how to create a Spring Boot CRUD operations API, but we will also dive deeper into using a remote MySQL DB provided by <a target="_blank" href="https://aws.amazon.com/rds/">Amazon RDS</a>. To top it off, we'll see how to securely manage database credentials through <a target="_blank" href="https://aws.amazon.com/secrets-manager/">AWS Secrets Manager</a>.</p>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>1. Have an <a target="_blank" href="https://console.aws.amazon.com/console/home">AWS account</a></p>
<p>2. Know how to configure AWS credentials on the local machine</p>
<p>3. Be familiar with the Spring Boot project</p>
<h2 id="heading-create-mysql-db-instance-using-amazon-rds">Create MySQL DB instance using Amazon RDS</h2>
<p>In this section, you will step-by-step create a MySQL DB instance using the AWS Management Console. At the end of this section you will have an online database ready to use :muscle:.</p>
<p>1. Go to <a target="_blank" href="https://console.aws.amazon.com/console/home">AWS Management Console</a> and sign in.</p>
<p>2. Choose the AWS Region you want and type <em>RDS</em> in the <strong>Search for services</strong> ... search bar and select it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950648381/j69jUp0SZ.png" alt="AWS Management Console" /></p>
<p>3. <a target="_blank" href="https://console.aws.amazon.com/rds/">RDS console</a> will open. In the navigation pane, choose <strong>Databases</strong> then <strong>Create database</strong> on the top-right of the <strong>Databases</strong> table to open the below page :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950650464/2daMUvJDQ.png" alt="Amazon RDS console : create database page" /></p>
<p>4. <strong>Choose a database creation method</strong> : <em>Standard create</em></p>
<p>5. <strong>Engine options</strong> : <em>MySQL</em></p>
<p>6. <strong>Templates</strong> : <em>Free tier</em></p>
<p>7. <strong>DB instance identifier</strong> : <em>mydemodb</em></p>
<p>8. <strong>Master username</strong> : <em>admin</em></p>
<p>9. <strong>Master password</strong> &amp; <strong>Confirm password</strong> : <em>adminadmin</em></p>
<p>10. <strong>DB instance class</strong> : <em>db.t2.micro</em></p>
<p>11. <strong>Public access</strong> : <em>Yes</em></p>
<p>12. Click <strong>Additional configuration</strong> -&gt; <strong>Initial database name</strong> : <em>demodb</em></p>
<blockquote>
<p><em>Step 12 will make RDS create a database named</em> <strong><em>demodb</em></strong></p>
</blockquote>
<p>13. Leave all other options as is and then click <strong>Create database</strong></p>
<p>Once the database is created, click on mydemodb in the <strong>Databases</strong> list to view its summary. We can use it at this point with basic information such as: <em>endpoint, port, principal user name, principal password and database</em>.</p>
<h2 id="heading-create-aws-secrets-to-protect-db-credentials">Create AWS Secrets to protect DB credentials</h2>
<p>We have created the MySQL database, now, to avoid hard coding its credentials in our Spring Boot project, we'll use AWS proven service that helps easily rotate, manage, and retrieve database credentials, API keys, and other secrets through their lifecycle : <a target="_blank" href="https://aws.amazon.com/secrets-manager/">AWS Secrets Manager</a>.</p>
<p>1. Once more, sign in to the AWS Management Console and open the Amazon Secrets Manager console <a target="_blank" href="https://console.aws.amazon.com/secretsmanager/">here</a> then make sure you choose the same AWS Region as that of the MySQL database</p>
<p>2. In the navigation pane, choose <strong>Secrets</strong> then <strong>Store a new secret</strong> on the top-right of the <strong>Secrets</strong> table to open the below page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950652389/VFd3mo8P6.png" alt="AWS Secrets Manager console : store a new secret" /></p>
<p>3. <strong>Secret type</strong> : <em>Credentials for Amazon RDS database</em></p>
<p>4. <strong>User name</strong> : <em>admin</em></p>
<p>5. <strong>Password</strong> : <em>adminadmin</em></p>
<blockquote>
<p><em>For steps 4 and 5, use the same username and password as the database</em>.</p>
</blockquote>
<p>6. <strong>Database</strong> : choose <em>mydemodb</em> DB instance and click <strong>Next</strong></p>
<p>7. <strong>Secret name</strong> : <em>demodb/dev</em>, leave default options and click <strong>Next</strong></p>
<p>8. Leave all the default options again and click <strong>Next</strong> to go to the <strong>Review</strong> page.</p>
<p>9. Click <strong>Store</strong></p>
<p>10. Once the Secret is created, click on it to preview its details.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950654073/-VPAMGIJz.png" alt="AWS Secret details" /></p>
<h2 id="heading-create-a-programmatic-iam-user">Create a programmatic IAM user</h2>
<blockquote>
<p><strong><em>Note*</em></strong>: If you have already configured AWS credentials on your machine locally, please skip this entire section and go to<em> **</em>Create Spring Boot<em>**</em>.*</p>
</blockquote>
<p>In order to user AWS Secrets we've created, we need an AWS IAM user with <strong><em>AdministratorAccess</em></strong> policy. Please follow <a target="_blank" href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config">these steps</a> to create an Admin IAM User and configure your local machine.</p>
<h2 id="heading-create-a-spring-boot-project">Create a Spring Boot Project</h2>
<p>For this lab, clone the project <a target="_blank" href="https://github.com/wilkom2009/docker-demo2.git">here</a> and open it in your IDE, then follow the explanations.</p>
<p>1. Let's explore some core dependencies necessary for the project in the <em>pom.xml</em> file :</p>
<pre><code class="lang-xml"><span class="hljs-comment">&lt;!-- Spring Boot JPA dependency --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>         
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-data-jpa<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-comment">&lt;!-- MySQL dependency --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>mysql<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>mysql-connector-java<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>runtime<span class="hljs-tag">&lt;/<span class="hljs-name">scope</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
<span class="hljs-comment">&lt;!-- AWS Secrets Manager dependency --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>com.amazonaws<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>aws-java-sdk-secretsmanager<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>1.11.355 <span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
<p>2. The <strong>SecretValue</strong> Java class in <em>utils</em> package <strong>SecretValue.java</strong> class aims to map the Secret value key/value data (DB credentials) retrieved from AWS Secrets Manager into a java object for use in the data source.</p>
<pre><code class="lang-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecretValue</span> </span>{
    <span class="hljs-keyword">private</span> String username;
    <span class="hljs-keyword">private</span> String password;
    <span class="hljs-keyword">private</span> String engine;
    <span class="hljs-keyword">private</span> String host;
    <span class="hljs-keyword">private</span> String port;
    <span class="hljs-keyword">private</span> String dbname;
    <span class="hljs-keyword">private</span> String dbInstanceIdentifier;

    <span class="hljs-comment">// Add Getters &amp; Setters</span>
}
</code></pre>
<p>3. The <strong>JavaConfig.java</strong> class In this class, the retrieval of the secret value we created in AWS Secrets Manager is implemented.</p>
<div class="gist-block embed-wrapper" data-gist-show-loading="false" data-id="d16f0e62d7f01170d04f2a0b95106bb8"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a href="https://gist.github.com/wilkom2009/d16f0e62d7f01170d04f2a0b95106bb8" class="embed-card">https://gist.github.com/wilkom2009/d16f0e62d7f01170d04f2a0b95106bb8</a></div><p> </p>
<blockquote>
<p>Line 41: the secret name created in AWS Secrets Manager</p>
<p>Line 42: the AWS Region where the secret is created</p>
</blockquote>
<h2 id="heading-test-the-rest-api">Test the REST API</h2>
<p>Our REST API is ready, in this section, we'll test it with Postman.</p>
<p>1. Build the project</p>
<ul>
<li><p>At the root of the project, run the following command line: <code>mvn clean package</code></p>
</li>
<li><p>If everything is configured correctly, the result should look like this:</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950655651/ReRIj5E-p.png" alt="Build success" /></p>
<p>2. Run the project Please run the API and make the following API call:</p>
<ul>
<li><p>Open Postman</p>
</li>
<li><p>Make a POST request : localhost:8080/api/team/2022</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950657287/bfXP7WsPb.png" alt="POST request - API" /></p>
<ul>
<li>Make a GET request : localhost:8080/api/team/2022</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654950659023/uU1MwkrPY.png" alt="GET request - API" /></p>
<p>Congratulations! You are almost at the end of the project.</p>
<h2 id="heading-bonus-deploy-the-crud-rest-api-on-aws-fargate">Bonus: Deploy the CRUD REST API on AWS Fargate</h2>
<p>As in production, we need to deploy our REST API, I suggest you try creating a docker container for the API, pushing it to the Docker hub, and deploying it to Amazon ECS using the AWS Fargate deployment option. Please follow these simple steps outlined in this <a target="_blank" href="https://dev.to/aws-builders/how-to-easily-deploy-a-spring-boot-application-on-aws-fargate-38nh">article.</a>.</p>
<blockquote>
<p><strong><em>Note*</em></strong>: To allow ECS Task to access the AWS Secrets Manager service, make sure you have<em> **</em>AmazonECSTaskExecutionRolePolicy<strong><em> </em>and<em> </em></strong>SecretsManagerReadWrite<strong><em> </em>as Permissions policies for the<em> </em></strong>Task role<em>**</em>.*</p>
</blockquote>
<h2 id="heading-cleanups">Cleanups</h2>
<p>After testing the REST API locally and remotely, sign in to the AWS Management Console and perform cleanups:</p>
<ul>
<li><p>Delete the IAM user we created in the IAM console if needed</p>
</li>
<li><p>Delete the Secret in the AWS Secrets Manager console</p>
</li>
<li><p>Delete the MySQL database in the RDS console.</p>
</li>
</ul>
<p>In this post, we showed how to create a Spring Boot CRUD REST API and how to manage Spring Boot MySQL connection. We also saw how to use AWS Secrets Manager in Spring Boot to protect database credentials in your REST API code. Your suggestions are welcome. Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[How to Easily Deploy a Spring Boot Application on AWS Fargate]]></title><description><![CDATA[Before entering the AWS Cloud world, as a Java developer, it was often difficult for me to get Java-based applications online for my clients. 
Fortunately, I found out later that AWS provides many proven, fully managed services for deploying Java-bas...]]></description><link>https://blog.wilsonkomlan.com/how-to-easily-deploy-a-spring-boot-application-on-aws-fargate</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/how-to-easily-deploy-a-spring-boot-application-on-aws-fargate</guid><category><![CDATA[Beginner Developers]]></category><category><![CDATA[AWS]]></category><category><![CDATA[Java]]></category><category><![CDATA[Docker]]></category><category><![CDATA[Springboot]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Sat, 04 Jun 2022 02:39:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654312277050/XEOIBtiXF.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before entering the AWS Cloud world, as a Java developer, it was often difficult for me to get Java-based applications online for my clients. 
Fortunately, I found out later that AWS provides many proven, fully managed services for deploying Java-based applications such as <a target="_blank" href="https://aws.amazon.com/ec2/">EC2</a>, <a target="_blank" href="https://aws.amazon.com/elasticbeanstalk/">Elastic Beanstalk</a>, <a target="_blank" href="https://aws.amazon.com/ecs/">Amazon ECS</a>, etc.</p>
<p>In this post, we will show how to quickly deploy a Spring Boot Application on Amazon ECS with <a target="_blank" href="https://aws.amazon.com/fargate/">AWS Fargate</a> deployment option. <a target="_blank" href="https://aws.amazon.com/fargate/">AWS Fargate</a> is a Serverless compute engine that can be used to launch and run containers without having to provision or manage EC2 instances. </p>
<p>In the next lines, we will :</p>
<ul>
<li><p>See how to create a Spring Boot REST API Docker image</p>
</li>
<li><p>Go through how to push a containerized API on the docker repository and deploy this containerized API on AWS</p>
</li>
<li><p>Create an ECS Cluster</p>
</li>
<li><p>Create a Fargate compatible Task Definition</p>
</li>
<li><p>Run the configured Task to make the application available online</p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ol>
<li><p>Have a <a target="_blank" href="https://hub.docker.com/repository/">Docker repository</a> account</p>
</li>
<li><p><a target="_blank" href="https://docs.docker.com/get-docker/">Install Docker Desktop</a> on your local machine</p>
</li>
<li><p>Have an <a target="_blank" href="https://console.aws.amazon.com/console/home">AWS account</a></p>
</li>
</ol>
<h2 id="heading-create-a-spring-boot-rest-api">Create a Spring Boot REST API</h2>
<p>Through this section, instead of creating a Spring Boot Web application, we will create a Spring Boot Rest API for simplicity. Notice that the deployment process is the same even for Spring Boot Web App and Spring Boot REST API. 
For demonstration purposes, you can clone the Git hub repository <a target="_blank" href="https://github.com/wilkom2009/docker-demo2">here</a> and open it in your favorite IDE.</p>
<h2 id="heading-create-a-docker-container-image-for-the-spring-boot-application">Create a Docker container image for the Spring Boot Application</h2>
<h3 id="heading-1-create-a-docker-file">1. Create a Docker file</h3>
<p>In the project root, create a docker file named: <strong>Dockerfile</strong> (with no file extension). Paste the below content:</p>
<pre><code class="lang-java">FROM openjdk:<span class="hljs-number">11</span>
COPY ./target/docker-demo-<span class="hljs-number">0.0</span>.<span class="hljs-number">1</span>-SNAPSHOT.jar docker-demo- 
<span class="hljs-number">0.0</span>.<span class="hljs-number">1</span>-SNAPSHOT.jar
CMD [<span class="hljs-string">"java"</span>,<span class="hljs-string">"-jar"</span>,<span class="hljs-string">"docker-demo-0.0.1-SNAPSHOT.jar"</span>]
EXPOSE <span class="hljs-number">8080</span>
</code></pre>
<blockquote>
<p>Line 1: Instruction to build docker image from openjdk:11 image</p>
<p>Line 2: Instruction to copy the jar file into the Docker container file system while building</p>
<p>Line 3: is a java command to launch the jar file while executing the container</p>
<p>Line 4:  informs Docker that the container listens on 8080 port at runtime.</p>
</blockquote>
<h3 id="heading-2-build-the-docker-image">2. Build the Docker image</h3>
<p>Open the terminal and execute the following docker command in the project root:</p>
<pre><code class="lang-bash">docker image build -t docker-demo .
</code></pre>
<p>You should have a result like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310567355/UaY_T7kB-Q.png" alt="Terminal : docker build success" /></p>
<h3 id="heading-3-test-the-docker-image-locally">3. Test the docker image locally</h3>
<p>Open the terminal and execute the following command:</p>
<pre><code class="lang-bash">docker container run --name dockerDemoApp -p 8080:8080 -d 
docker-demo
</code></pre>
<p>Go to Docker Desktop, you should see this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310568876/2q8QmA4ay.png" alt="Docker desktop" /></p>
<p>You can then paste this link <code>http://localhost:8080/api/</code> in the browser to get the following result :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310570393/EkGxueQQz.png" alt="Web browser showing get response" /></p>
<h3 id="heading-4-push-docker-image-into-docker-hub-repository">4. Push Docker image into Docker hub repository</h3>
<p>In order to push the Docker local image into the Docker hub repository, you just need to execute the following command line:</p>
<pre><code class="lang-bash">docker push xxx/docker-demo-app:latest
</code></pre>
<blockquote>
<p>Make sure to replace xxx with your user name.</p>
</blockquote>
<h2 id="heading-deploy-the-spring-boot-rest-api-on-aws-fargate">Deploy the Spring Boot REST API on AWS Fargate</h2>
<p>In this section, we will work step by step to finally get the REST API online.</p>
<h3 id="heading-1-create-amazon-ecs-cluster">1. Create Amazon ECS Cluster</h3>
<ul>
<li>Sign in to the <a target="_blank" href="https://console.aws.amazon.com/console/home">AWS Console</a>, and type ECS in the Search bar.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310572068/16zzchZO4.png" alt="Amazon ECS Cluster page" /></p>
<p>Click on <strong>Create Cluster</strong></p>
<ul>
<li><p>Step 1: On <strong>Select cluster template</strong> step, select <strong>Networking only</strong> option and click on <strong>Next Step</strong></p>
</li>
<li><p>Step 2: Provide the <strong>Cluster name</strong> : <em>Demo-cluster</em>, check <strong>Create VPC</strong> option, leave all other default options and click on <strong>Create</strong>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310573722/mqZBYnxNc.png" alt="Amazon ECS Cluster config" /></p>
<ul>
<li>Click on <strong>View Cluster</strong>, and the Demo-cluster details should look like this:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310575947/rR0ISyAxd.png" alt="Amazon ECS Cluster view" /></p>
<h3 id="heading-2-create-a-task-definition">2. Create a Task Definition</h3>
<p>On the left side, click <strong>Task Definitions</strong> and <strong>Create new Task Definition</strong> to access the Create new Task Definition page.</p>
<h4 id="heading-a-step-1-select-launch-type-compatibility">a. Step 1: Select launch type compatibility</h4>
<ul>
<li>Select <strong>FARGATE</strong> then click on <strong>Next Step</strong></li>
</ul>
<h4 id="heading-b-step-2-configure-task-and-container-definitions">b. Step 2: Configure task and container definitions</h4>
<ul>
<li>Type the <strong>Task definition name</strong> : <em>docker-demo-task</em></li>
<li>Leave <strong>Task role</strong> as is (an IAM role for ECS Task definition will be created on your behalf ) </li>
<li>Select <em>Linux</em> as <strong>Operating system family</strong></li>
<li><strong>Task execution role</strong>, leave <em>Create new role</em> option</li>
<li><strong>Task memory (GB)</strong> : 1GB</li>
<li><strong>Task CPU (vCPU)</strong> : <em>0.5vCPU</em></li>
<li>Click on <strong>Add Container</strong>, and the information below:</li>
</ul>
<p>-- <strong>Container name</strong> : <em>dockerDemoApp</em></p>
<p>-- <strong>Image</strong> : <em>xxx/docker-demo-app:latest</em>, the Docker hub image repository (xxx : your Docker hub user name)</p>
<p>-- <strong>Memory Limits (MiB)</strong> : Soft limit : <em>128</em></p>
<p>-- <strong>Port mappings</strong> : <em>80 -&gt; tcp</em> and <em>8080 -&gt; tcp</em>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310577663/5XiHPoCtq.png" alt="ECS Container config" />
-- Click on <strong>Add</strong> to navigate back to <strong>Create new Task Definition</strong> page</p>
<ul>
<li><p>Leave all other options and click on <strong>Create</strong></p>
</li>
<li><p>Click on <strong>View task definition</strong> to see the created task definition details.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310579437/-I3j2tAst.png" alt="Amazon ECS Task definition detail" /></p>
<h3 id="heading-3-run-the-task-definition">3. Run the Task Definition</h3>
<p>In this last section, we are going to run our Docker container image.</p>
<h4 id="heading-step-1">Step 1</h4>
<p>In the <strong>Task Definition: docker-demo-task:1</strong> page, click on <strong>Actions</strong> then <strong>Run Task</strong>, the <strong>Run Task</strong> page will open.</p>
<h4 id="heading-step-2">Step 2</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310581282/sbbXWoCRU.png" alt="Amazon ECS Run Task" /></p>
<ul>
<li><strong>Launch type</strong> : <em>FARGATE</em></li>
<li><strong>Operating system family</strong> : <em>Linux</em></li>
<li><strong>Task Definition</strong> : <strong>Familly</strong> -&gt; <em>docker-demo-task</em> / <strong>Revision</strong> -&gt; <em>1</em></li>
<li><strong>Platform version</strong> : <em>LATEST</em></li>
<li><strong>Cluster</strong> : <em>Demo-cluster</em></li>
<li><strong>Number of tasks</strong> : <em>1</em></li>
<li><strong>Cluster VPC</strong> : select your VPC</li>
<li><strong>Subnets</strong> : Choose un subnet</li>
<li><strong>Security groups</strong> : click on <strong>Edit</strong> to modify the default security group as follow :</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310583002/T5neoluco.png" alt="ECS running Task security group config" />
-- <strong>Assigned security groups</strong> : <em>Create new security group</em></p>
<p>-- <strong>Security group name</strong> : <em>docker-demo-sg</em></p>
<p>-- <strong>Inbound rules for security group</strong>: Choose <em>All Traffic</em> <strong>Type</strong> and <em>Anywhere</em> <strong>Source</strong></p>
<p>-- Click on <strong>Save</strong>, and you will be redirected to the <strong>Run Task</strong> page.</p>
<ul>
<li><p><strong>Auto-assign public IP</strong> : <em>ENABLED</em></p>
</li>
<li><p>Leave all other default options and click on <strong>Run Task</strong>.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310584709/vyhQ6TDHf.png" alt="Amazon ECS Task running" /></p>
<h2 id="heading-access-spring-boot-rest-api-via-public-address">Access Spring Boot REST API via public address</h2>
<p>Now that the deployed API's container is running, let's try to access it through a public IP address.</p>
<h4 id="heading-step-1-task-details">Step 1: Task details</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310586610/cqyFFyDuH.png" alt="Amazon ECS Task click" /></p>
<ul>
<li><p>In the <strong>Demo-cluster</strong> details page, go to <strong>Tasks</strong> tab. </p>
</li>
<li><p>In the listed tasks, click on the <strong>Task</strong> whose <strong>Task definition</strong> column is <em>docker-demo-task:1</em>, and the Task details page should open.</p>
</li>
</ul>
<h4 id="heading-step-2-task-public-ip-address">Step 2: Task public IP address</h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310588551/XNGBnIFM7.png" alt="Amazon ECS Task definition running" /></p>
<ul>
<li><p>In the Task details page, copy the Public IP address</p>
</li>
<li><p>Open a browser or Postman, paste the IP address, and append the port and /api/ to see the magic happen!</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654310590159/E7gJxHYsx.png" alt="Web browser showing Get response" /></p>
<h3 id="heading-4-clean-up">4. Clean up</h3>
<ul>
<li>In the Task Details page, click on <strong>Stop</strong></li>
<li>In the Demo-cluster page, click on <strong>Delete Cluster</strong> then follow the instructions to delete the Cluster</li>
</ul>
<h2 id="heading-in-summary">In Summary</h2>
<p>Through this post, we saw how to easily and quickly deploy a Spring Boot Application on AWS using AWS Fargate by creating a Spring Boot REST API Docker container image, pushing it on the Docker hub repository, creating and configuring Amazon ECS Cluster and Task definition witch helped us to deploy and run our REST API container image on AWS Cloud.
Thanks for the reading.</p>
]]></content:encoded></item><item><title><![CDATA[How to secure Spring boot REST API endpoints with Amazon Cognito]]></title><description><![CDATA[Hello! For Java backend developers, with Spring security there are many ways to secure Spring boot Rest APIs. 
Usually, implementing Spring boot bearer token functionality for Rest API requires many lines of code, hours, and the need for user managem...]]></description><link>https://blog.wilsonkomlan.com/how-to-secure-spring-boot-rest-api-endpoints-with-amazon-cognito</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/how-to-secure-spring-boot-rest-api-endpoints-with-amazon-cognito</guid><category><![CDATA[AWS]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[oauth]]></category><category><![CDATA[JWT]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Thu, 02 Jun 2022 12:03:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171947393/ivbwZipZi.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello! For Java backend developers, with <a target="_blank" href="https://docs.spring.io/spring-security/reference/getting-spring-security.html">Spring security</a> there are many ways to secure <a target="_blank" href="https://spring.io/projects/spring-boot">Spring boot</a> Rest APIs. </p>
<p>Usually, implementing Spring boot bearer token functionality for Rest API requires many lines of code, hours, and the need for user management. However, using Spring boot AWS authentication thanks to <a target="_blank" href="https://aws.amazon.com/cognito/">Amazon Cognito</a>, things become very simple and very very fast. We no longer need to manage users, <a target="_blank" href="https://aws.amazon.com/cognito/">Amazon Cognito user pool</a> takes care of that. Cognito also allows us to share users between many Rest APIs and front-ends (web, mobile).</p>
<h2 id="heading-create-amazon-cognito-user-pool">Create Amazon Cognito User Pool</h2>
<ol>
<li><p>Sign in into <a target="_blank" href="https://console.aws.amazon.com/console/home">Amazon console</a>, and then search for: Cognito.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171929153/d8fExVqG0.png" alt="Amazon Cognito page" /></p>
</li>
<li><p>Click on <strong>Create User Pool</strong>. </p>
</li>
<li><p>In the <em>Configure sign-in experience</em> step, check <strong>User name</strong>, <strong>Email</strong>, and <strong>Allow users to sign in with a preferred user name</strong> options then click on <strong>Next</strong>.</p>
</li>
<li><p>In the <em>Configure security requirements</em> step, leave all the default options except <strong>MFA enforcement</strong> where you should choose <strong>No MFA</strong> instead of <strong>Require MFA - Recommended</strong>, then click on <strong>Next</strong>.</p>
</li>
<li><p>Step 3 : <em>Configure sign-up experience</em>, leave all default options, and click on <strong>Next</strong>.</p>
</li>
<li><p>Step 4: <em>Configure message delivery</em>, choose <strong>Send email with Cognito</strong> for <strong>Email provider</strong> and leave all other default options then click on <strong>Next</strong>.</p>
</li>
<li><p>Step 5: <em>Integrate your app</em>, provide the <strong>User pool name</strong> : <em><strong>Demo-user-pool</strong></em>, <strong>App client name</strong>: <em><strong>Dockerdemo-app</strong></em>, leave other default options, and click Next.</p>
</li>
<li><p>Step 6: Review and click on <strong>Create User Pool</strong>. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171930965/zsB8dbonW.png" alt="Amazon Cognito Demo user pool" /></p>
</li>
<li><p>In the details page of the created user pool, click on <strong>App Integration</strong> tab -&gt; <strong>Actions</strong> -&gt; <strong>Create Cognito Domain</strong> and provide the domain name then click <strong>Create Cognito Domain</strong>. </p>
</li>
<li><p>Again, in the <strong>App Integration</strong> tab, navigate to the  <strong>App client list</strong> section and click on <strong>Dockerdemo-app</strong> to preview its details.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171932767/t4RfmA84O.png" alt="Amazon Cognito app client details" /></p>
</li>
<li><p>In the <strong>App client</strong> details, scroll down to the <strong>Pinpoint analytics</strong> section and click on <strong>Edit</strong>, the <strong>Edit Hosted UI</strong> page will open.</p>
</li>
<li><p>In the <strong>Edit Hosted UI</strong> page, provide the <strong>Allowed callback URLs</strong> : https://example.com, check <strong>Cognito user pool</strong> in the <strong>Identity providers</strong> section, check all <strong>OpenID Connect scopes</strong> options then click <strong>Save changes</strong>.</p>
</li>
<li><p>Back to the <strong>App client</strong> details, the Pinpoint analytics section should look like the image below:
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171934649/MxE3f5Odr.png" alt="Amazon Cognito App client hosted UI" /></p>
</li>
<li><p>Make sure to save the Cognito domain from the <strong>Domain</strong> section, and the <strong>Client ID</strong> for the created client App from the  <strong>App client list</strong> section.</p>
</li>
</ol>
<h2 id="heading-create-spring-boot-rest-api">Create Spring boot Rest API</h2>
<p>In this section, we will create a spring boot Rest API. For demonstration purposes, you can clone the Git hub repository <a target="_blank" href="https://github.com/wilkom2009/docker-demo.git">here</a> and open it in your favorite IDE.</p>
<p>The idea here is to implement Spring Security Rest API authentication with <a target="_blank" href="https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/index.html">OAuth 2.0 JWT Bearer Tokens</a>. 
Instead of implementing the <a target="_blank" href="https://wilkom2009.hashnode.dev/java-fullstack-backend-rest-api-spring-security-and-jwt-a">JWT authentication tokens generation mechanism</a>,  we will use Amazon Cognito to manage it.</p>
<ol>
<li><p>Provide the needed dependencies in the <strong>pom.xml</strong> file for Spring Security OAuth 2.0 support</p>
<pre><code class="lang-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

 <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>             
     <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
     <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-oauth2-resource- 
server<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
 <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre>
</li>
<li><p>In the <strong>application.yaml</strong> file, specify the Authorization Server:</p>
<pre><code class="lang-yml"> <span class="hljs-attr">spring:</span>
   <span class="hljs-attr">security:</span>
     <span class="hljs-attr">oauth2:</span>
       <span class="hljs-attr">resourceserver:</span>
         <span class="hljs-attr">jwt:</span>
           <span class="hljs-attr">issuer-uri:</span> <span class="hljs-string">https://cognito-idp.[AWS</span> <span class="hljs-string">REGION].amazonaws.com/[USER_POOL_ID]</span>
</code></pre>
</li>
<li><p>Create a security configuration file.</p>
<pre><code class="lang-java"> <span class="hljs-keyword">package</span> com.wilkom.dockerdemo.security;

 <span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
 <span class="hljs-keyword">import</span> org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 <span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.builders.HttpSecurity;
 <span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 <span class="hljs-keyword">import</span> org.springframework.security.web.SecurityFilterChain;

 <span class="hljs-meta">@EnableWebSecurity</span> <span class="hljs-comment">// Enable Spring Security’s web </span>
   <span class="hljs-comment">//security support</span>
 <span class="hljs-meta">@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)</span> <span class="hljs-comment">// To configure method-level security</span>
 <span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SecurityConfig</span> </span>{

     <span class="hljs-meta">@Bean</span>
     <span class="hljs-function"><span class="hljs-keyword">public</span> SecurityFilterChain <span class="hljs-title">filterChain</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception </span>{

         http.cors().and().csrf().disable()
             .authorizeRequests(expressionInterceptUrlRegistry -&gt; expressionInterceptUrlRegistry
                     .anyRequest().authenticated())
             .oauth2ResourceServer().jwt();
         <span class="hljs-keyword">return</span> http.build();
     }
 }
</code></pre>
<blockquote>
<p>In the configuration class above, we have made each endpoint accessible only by OAuth 2.0 authenticated requests. That's all we have to do in our API Rest backend.</p>
</blockquote>
</li>
</ol>
<h2 id="heading-test-the-rest-api">Test the Rest API</h2>
<p>We will use Postman to test our Rest API.</p>
<p>1. Signup user into the Amazon Cognito</p>
<ul>
<li><p>Open Postman and provide values from Amazon Cognito User provider settings:
  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171936396/rhR-gcYPp.png" alt="Postman Authorization Token generation" /></p>
<blockquote>
<p>2/ Callback URL: https://example.com (make sure to provide the exact callback URL you set in the Cognito)</p>
<p>3/ Auth URL: https://xxxxx.auth.us-east-1.amazoncognito.com/login (remember to append /login)</p>
<p>4/ Access Token URL : https://xxxxx.auth.us-east-1.amazoncognito.com/oauth2/token (remember to append /oauth2/token)</p>
<p>5/ Client ID : Dockerdemo-app <strong>App Client ID</strong></p>
</blockquote>
</li>
<li><p>Then click on <strong>Get New Access Token</strong> at the bottom, and the Sign-in screen will open, click on Sign up link at the bottom the get the signup screen as follow:
  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171938189/I8P4xDST2.png" alt="Cognito Sign up screen" /></p>
<blockquote>
<p>Enter the user name, valid email and password then click on Sign-up.</p>
</blockquote>
</li>
<li><p>The verification code screen should appear, open the valid email box to get the verification code:
  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171940080/58oMgYt5X.png" alt="Cognito verification code screen" /></p>
</li>
<li><p>If the code verification is successful, a token will be generated, click on <strong>Use Token</strong>:
  <img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171941949/kcT5ysh7Y.png" alt="Postman token generated" /></p>
</li>
</ul>
<p>2. Make API call</p>
<ul>
<li><p>Now, you can run the Spring boot app.</p>
</li>
<li><p>Go to Postman, enter a GET endpoint URL, </p>
</li>
</ul>
<pre><code class="lang-bash">localhost:8080/api/
</code></pre>
<ul>
<li>Make sure the token is in use in the Authorization OAuth 2.0 tab and click on <strong>Send</strong>:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1654171943868/nU_lFrscD.png" alt="Postman Get request successful" /></p>
<blockquote>
<p>PS: In a real project, the Signup and Sign-in processes will be implemented in the front-end apps, please see <a target="_blank" href="https://aws.amazon.com/cognito/getting-started/">this guide</a> to do so.</p>
</blockquote>
<p>As you can see, Amazon Cognito is an amazing AWS service that simplifies Spring boot backend Rest API user management.</p>
<p>Thanks for reading.</p>
]]></content:encoded></item><item><title><![CDATA[Java Full Stack Spring boot & React app: Backend REST API / 4 - Exception handling]]></title><description><![CDATA[Hello,
In this previous tutorial, we secured our backend RESTful API using Spring Security and JWT. Now we are going to handle errors/exceptions in the RESTful API.
Problem
Until now, all eventual error messages thrown in our RESTful API are not user...]]></description><link>https://blog.wilsonkomlan.com/java-full-stack-spring-boot-and-react-app-backend-rest-api-4-exception-handling</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/java-full-stack-spring-boot-and-react-app-backend-rest-api-4-exception-handling</guid><category><![CDATA[Java]]></category><category><![CDATA[Spring]]></category><category><![CDATA[REST API]]></category><category><![CDATA[React]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Mon, 16 Aug 2021 22:59:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1629141076999/F0rShmeb2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello,</p>
<p>In <a target="_blank" href="https://wilkom2009.hashnode.dev/java-fullstack-backend-rest-api-spring-security-and-jwt-b">this previous tutorial</a>, we secured our backend RESTful API using Spring Security and JWT. Now we are going to handle errors/exceptions in the RESTful API.</p>
<h1 id="problem">Problem</h1>
<p>Until now, all eventual error messages thrown in our RESTful API are not user-friendly. For example, when you try to log in with invalid credentials, you should have a similar message in Postman:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629144745136/5kgoed6AD.png" alt="image.png" /></p>
<p>In the following lines, we'll use one of the smart solutions <a target="_blank" href="https://spring.io/">Spring</a> provides to make the API throw understandable error messages.</p>
<h1 id="solution-spring-global-exception-handling">Solution: Spring Global Exception Handling</h1>
<h3 id="1-exceptionresponsejava">1 - ExceptionResponse.java</h3>
<p>This java class will be the custom error message class to return by the API when an error occurs. Create it in the <em>com.codeurinfo.easytransapi.exception</em> package.</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi.exception;

<span class="hljs-keyword">import</span> com.fasterxml.jackson.<span class="hljs-keyword">annotation</span>.JsonFormat;
<span class="hljs-keyword">import</span> java.time.LocalDateTime;
<span class="hljs-keyword">import</span> org.springframework.http.HttpStatus;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ExceptionResponse</span> </span>{

  <span class="hljs-keyword">private</span> HttpStatus status;

  <span class="hljs-meta">@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = <span class="hljs-meta-string">"dd-MM-yyyy hh:mm:ss"</span>)</span>
  <span class="hljs-keyword">private</span> LocalDateTime timestamp;

  <span class="hljs-keyword">private</span> String message;
  <span class="hljs-keyword">private</span> String description;

  <span class="hljs-keyword">public</span> ExceptionResponse() {
    <span class="hljs-keyword">this</span>.timestamp = LocalDateTime.now();
  }

  <span class="hljs-keyword">public</span> ExceptionResponse(HttpStatus status) {
    <span class="hljs-keyword">this</span>();
    <span class="hljs-keyword">this</span>.status = status;
    <span class="hljs-keyword">this</span>.message = <span class="hljs-string">"An error occured"</span>;
  }

  <span class="hljs-keyword">public</span> ExceptionResponse(String message) {
    <span class="hljs-keyword">this</span>();
    <span class="hljs-keyword">this</span>.message = message;
  }

  <span class="hljs-keyword">public</span> ExceptionResponse(HttpStatus status, String message, Throwable ex) {
    <span class="hljs-keyword">this</span>();
    <span class="hljs-keyword">this</span>.status = status;
    <span class="hljs-keyword">this</span>.message = message;
    <span class="hljs-keyword">this</span>.description = ex.getLocalizedMessage();
  }

  <span class="hljs-keyword">public</span> LocalDateTime getTimestamp() {
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.timestamp;
  }

  <span class="hljs-keyword">public</span> void setTimestamp(LocalDateTime timestamp) {
    <span class="hljs-keyword">this</span>.timestamp = timestamp;
  }

 <span class="hljs-comment">// getters and setters</span>

}
</code></pre><h3 id="2-globalcontrollerexceptionhandlerjava">2 - GlobalControllerExceptionHandler.java</h3>
<p>Let's create this class in <em>com.codeurinfo.easytransapi.exception</em> package to handle all the errors in the RESTful API.</p>
<pre><code><span class="hljs-selector-tag">package</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.exception</span>;

<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">io</span><span class="hljs-selector-class">.jsonwebtoken</span><span class="hljs-selector-class">.ExpiredJwtException</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.dao</span><span class="hljs-selector-class">.DataIntegrityViolationException</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.http</span><span class="hljs-selector-class">.HttpStatus</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.security</span><span class="hljs-selector-class">.access</span><span class="hljs-selector-class">.AccessDeniedException</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.web</span><span class="hljs-selector-class">.bind</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.ExceptionHandler</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.web</span><span class="hljs-selector-class">.bind</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.ResponseStatus</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.web</span><span class="hljs-selector-class">.bind</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.RestControllerAdvice</span>;

<span class="hljs-keyword">@RestControllerAdvice</span>
public class GlobalControllerExceptionHandler {

  <span class="hljs-keyword">@ExceptionHandler</span>({ <span class="hljs-selector-tag">DataIntegrityViolationException</span><span class="hljs-selector-class">.class</span> })
  <span class="hljs-keyword">@ResponseStatus</span>(value = HttpStatus.CONFLICT)
  public ExceptionResponse handleDIVException(
    DataIntegrityViolationException e
  ) {
    <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">new</span> <span class="hljs-selector-tag">ExceptionResponse</span>(
      <span class="hljs-selector-tag">HttpStatus</span><span class="hljs-selector-class">.CONFLICT</span>,
      "<span class="hljs-selector-tag">Data</span> <span class="hljs-selector-tag">integrity</span> <span class="hljs-selector-tag">error</span>.",
      <span class="hljs-selector-tag">e</span>
    );
  }

  <span class="hljs-keyword">@ExceptionHandler</span>({ <span class="hljs-selector-tag">Exception</span><span class="hljs-selector-class">.class</span> })
  <span class="hljs-keyword">@ResponseStatus</span>(value = HttpStatus.INTERNAL_SERVER_ERROR)
  public ExceptionResponse handleException(Exception e) {
    <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">new</span> <span class="hljs-selector-tag">ExceptionResponse</span>(
      <span class="hljs-selector-tag">HttpStatus</span><span class="hljs-selector-class">.INTERNAL_SERVER_ERROR</span>,
      <span class="hljs-selector-tag">e</span><span class="hljs-selector-class">.getLocalizedMessage</span>(),
      <span class="hljs-selector-tag">e</span>
    );
  }

  <span class="hljs-keyword">@ExceptionHandler</span>({ <span class="hljs-selector-tag">AccessDeniedException</span><span class="hljs-selector-class">.class</span> })
  <span class="hljs-keyword">@ResponseStatus</span>(value = HttpStatus.FORBIDDEN)
  public ExceptionResponse handleForbiddenException(AccessDeniedException e) {
    <span class="hljs-selector-tag">return</span> <span class="hljs-selector-tag">new</span> <span class="hljs-selector-tag">ExceptionResponse</span>(
      <span class="hljs-selector-tag">HttpStatus</span><span class="hljs-selector-class">.FORBIDDEN</span>,
      <span class="hljs-selector-tag">e</span><span class="hljs-selector-class">.getLocalizedMessage</span>(),
      <span class="hljs-selector-tag">e</span>
    );
  }


}
</code></pre><ul>
<li><p>Spring <a target="_blank" href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RestControllerAdvice.html">@RestControllerAdvice</a> annotation is used on a global class to make all its methods annotated with <a target="_blank" href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html">@ExceptionHandler</a> be accessible across all the controllers in the RESTful API.</p>
</li>
<li><p><a target="_blank" href="https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/ExceptionHandler.html">@ExceptionHandler</a> annotation is used upon methods to handle specific Exceptions.</p>
</li>
<li><p>Thus, we use <em>@ExceptionHandler({ DataIntegrityViolationException.class })</em> on the <strong>handleDIVException</strong> method to handle all DataIntegrityViolation Exceptions occurred in @RepositoryRestResource annotated repository interfaces.</p>
</li>
<li><p><em>@ResponseStatus</em> is used to send the corresponding HTTP status code for the JSON response.</p>
</li>
<li><p>For unknown exceptions handling, we use <em>@ExceptionHandler({ Exception.class })</em> on the <strong>handleException</strong> method and provide a <em>HttpStatus.INTERNAL_SERVER_ERROR</em> status code to return.</p>
</li>
<li><p>Similarly, we use <em>@ExceptionHandler({ AccessDeniedException.class })</em> and provide <em>HttpStatus.FORBIDDEN</em> on the <strong>handleForbiddenException</strong> method  to handle URL access denied exception.</p>
</li>
</ul>
<h3 id="3-tests">3 - Tests</h3>
<p>1 - Log in with bad credentials</p>
<ul>
<li>POST request : <em>http://localhost:8000/api/auth/login</em></li>
<li>Body: </li>
</ul>
<pre><code>{
    <span class="hljs-attr">"userName"</span>: <span class="hljs-string">"user"</span>,
    <span class="hljs-attr">"password"</span>: <span class="hljs-string">"user1"</span>
}
</code></pre><ul>
<li>Response</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629152330015/klCsSU88E.png" alt="image.png" /></p>
<p>2 - Try to access an unauthorized resource</p>
<p>Suppose you logged in with <em>user/user</em> good credentials, following our API logic, a user with username <strong>user</strong> is not allowed to make a <strong>routeByName</strong> search request</p>
<ul>
<li>POST request: <em>http://localhost:8000/api/routes/search/routesByName?name=Rex-Adidogome</em></li>
<li>Provide Authorization token value (token generated when log in was successful)</li>
<li>Response</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1629152812140/YWP3-AczB.png" alt="image.png" /></p>
<p>In the next post, we'll add new features to our EasyTrans app. Hope you learned something new. If so, don't forget to hit the Like button and subscribe to this blog to be up to date with new posts.</p>
]]></content:encoded></item><item><title><![CDATA[Java FullStack Spring boot & React app: Backend REST API / 3 - Securing the REST API with Spring Security & JWT (b)]]></title><description><![CDATA[Hello,
We added some security features to our REST API in previous post thanks to Spring Security and JWT. In this tutorial, we'll be validating token and secure the API endpoints.
Overview
Here are what we'll be doing in this post:

JWT token valida...]]></description><link>https://blog.wilsonkomlan.com/java-fullstack-backend-rest-api-spring-security-and-jwt-b</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/java-fullstack-backend-rest-api-spring-security-and-jwt-b</guid><category><![CDATA[Java]]></category><category><![CDATA[full stack]]></category><category><![CDATA[REST API]]></category><category><![CDATA[JWT]]></category><category><![CDATA[Springboot]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Sat, 24 Jul 2021 03:27:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627069425379/WsqIM4fR8.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello,</p>
<p>We added some security features to our REST API in <a target="_blank" href="https://wilkom2009.hashnode.dev/java-fullstack-backend-rest-api-spring-security-and-jwt-a">previous post</a> thanks to <a target="_blank" href="https://spring.io/projects/spring-security">Spring Security</a> and <a target="_blank" href="https://jwt.io/">JWT</a>. In this tutorial, we'll be validating token and secure the API endpoints.</p>
<h2 id="overview">Overview</h2>
<p>Here are what we'll be doing in this post:</p>
<ul>
<li><p>JWT token validation</p>
</li>
<li><p>How to grant/deny access to Spring Data REST Repository method</p>
</li>
</ul>
<h2 id="jwt-token-validation">JWT Token validation</h2>
<p>In order to catch and validate token coming from a client, we have to create a request Filter class extending the Spring Web Filter <em>OncePerRequestFilter</em> class. For any incoming request, this Filter class will be executed. It checks if the request has a valid JWT token. If it has a valid JWT Token, then it sets the authentication in context to specify that the current user is authenticated.</p>
<p>Create a class, <em>AuthRequestFilter.java</em> in <em>security.filter</em> package.</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi2.security.filter;

<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi2.security.UserDetailsImpl;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi2.security.UserDetailsServiceImpl;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi2.security.util.JwtUtil;
<span class="hljs-keyword">import</span> java.io.IOException;
<span class="hljs-keyword">import</span> javax.servlet.FilterChain;
<span class="hljs-keyword">import</span> javax.servlet.ServletException;
<span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest;
<span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
<span class="hljs-keyword">import</span> org.springframework.security.core.context.SecurityContextHolder;
<span class="hljs-keyword">import</span> org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;
<span class="hljs-keyword">import</span> org.springframework.web.filter.OncePerRequestFilter;

<span class="hljs-meta">@Component</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthRequestFilter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">OncePerRequestFilter</span> </span>{

  <span class="hljs-meta">@Autowired</span>
  <span class="hljs-keyword">private</span> UserDetailsServiceImpl userDetailsService;

  <span class="hljs-meta">@Autowired</span>
  <span class="hljs-keyword">private</span> JwtUtil jwtUtil;

  <span class="hljs-meta">@Override</span>
  <span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doFilterInternal</span><span class="hljs-params">(
    HttpServletRequest request,
    HttpServletResponse response,
    FilterChain chain
  )</span>
    <span class="hljs-keyword">throws</span> ServletException, IOException </span>{
    <span class="hljs-keyword">final</span> String authorizationHeader = request.getHeader(<span class="hljs-string">"Authorization"</span>);

    String username = <span class="hljs-keyword">null</span>;
    String jwt = <span class="hljs-keyword">null</span>;

    <span class="hljs-keyword">if</span> (
      authorizationHeader != <span class="hljs-keyword">null</span> &amp;&amp; authorizationHeader.startsWith(<span class="hljs-string">"Bearer "</span>)
    ) {
      <span class="hljs-comment">// get the jwt token</span>
      jwt = authorizationHeader.substring(<span class="hljs-number">7</span>);<span class="hljs-comment">// authorizationHeader is like "Bearer jwttoken", so 7 caracters before jwttoken</span>
      username = jwtUtil.extractUsername(jwt);<span class="hljs-comment">// get username for the given token</span>
    }

    <span class="hljs-keyword">if</span> (
      username != <span class="hljs-keyword">null</span> &amp;&amp;
      SecurityContextHolder.getContext().getAuthentication() == <span class="hljs-keyword">null</span>
    ) {
      UserDetailsImpl userDetails =
        (UserDetailsImpl) <span class="hljs-keyword">this</span>.userDetailsService.loadUserByUsername(username);

      <span class="hljs-keyword">if</span> (jwtUtil.validateToken(jwt, userDetails)) {
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = <span class="hljs-keyword">new</span> UsernamePasswordAuthenticationToken(
          userDetails,
          <span class="hljs-keyword">null</span>,
          userDetails.getAuthorities()
        );
        usernamePasswordAuthenticationToken.setDetails(
          <span class="hljs-keyword">new</span> WebAuthenticationDetailsSource().buildDetails(request)
        );
        SecurityContextHolder
          .getContext()
          .setAuthentication(usernamePasswordAuthenticationToken);
      }
    }
    chain.doFilter(request, response);
  }
}
</code></pre><p>Then, let's add this Filter to the <strong><em>SecurityConfig.java</em></strong> class in the <em>configure</em> method like this:</p>
<pre><code><span class="hljs-variable">@Override</span>
  protected void configure(HttpSecurity http) throws Exception {
    <span class="hljs-selector-tag">http</span>
      <span class="hljs-selector-class">.csrf</span>()
      <span class="hljs-selector-class">.disable</span>()
      <span class="hljs-selector-class">.authorizeRequests</span>()
      <span class="hljs-selector-class">.antMatchers</span>(<span class="hljs-string">"/api/auth/**"</span>)<span class="hljs-selector-class">.permitAll</span>() <span class="hljs-comment">// Grant access to every /api/auth based url</span>
      <span class="hljs-selector-class">.anyRequest</span>()<span class="hljs-selector-class">.authenticated</span>() <span class="hljs-comment">// All other based url wil be allowed if authenticated</span>
      <span class="hljs-selector-class">.and</span>()
      <span class="hljs-selector-class">.sessionManagement</span>()
      <span class="hljs-selector-class">.sessionCreationPolicy</span>(SessionCreationPolicy.STATELESS);<span class="hljs-comment">//Force server not to never create an HttpSession</span>
    <span class="hljs-selector-tag">http</span><span class="hljs-selector-class">.addFilterBefore</span>(
      authRequestFilter,
      UsernamePasswordAuthenticationFilter.class
    );
  }
</code></pre><p>Reminder: You must first declare <em>authRequestFilter</em> as a variable in the <em>SecurityConfig.java</em> class</p>
<pre><code><span class="hljs-variable">@Autowired</span>
  private AuthRequestFilter authRequestFilter;
</code></pre><p> At this point, our REST API is almost secured. Let's run and test it in Postman.</p>
<p>1 . Make a simple GET request</p>
<pre><code><span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:9000/api/routes</span>
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627080067870/Hf1vL4dlY.png" alt="image.png" /></p>
<p>As you can see, we have an Access Denied error.</p>
<p>2 . Make a login POST request </p>
<pre><code><span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:9000/api/auth/login</span>
</code></pre><p>Remember to use the same credentials you set up for users in the preload <em>DatabaseLoader.java</em>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627080544103/At7kZOgLc.png" alt="image.png" />
If a valid username/password is provided, a JWT token is returned.</p>
<p>3 . Try a simple GET request again</p>
<pre><code><span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:9000/api/routes</span>
</code></pre><ul>
<li>Before execute the GET request in Postman, copy the JWT token returned in step 2</li>
<li>Open Header tab, add a <strong>key</strong> : <strong>Authorization</strong>, type the <strong>value</strong>: <strong>Bearer yourCopiedToken</strong></li>
<li>Execute the request, you might have a good result as below. 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627081509159/CUBqI3Ogs.png" alt="image.png" /></li>
</ul>
<p>From now on, you must add the Authorization key and value in the Header tab before executing any other request apart from the login </p>
<p>4 . Make a POST request to save a route</p>
<pre><code><span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:8000/api/routes</span>
</code></pre><ul>
<li>Open the Header tab and Authorization key and value as proceed in step 3</li>
<li>Open the Body tab to add your payload data</li>
</ul>
<pre><code>{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Rex-Adidogome"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"Grand marche - Rex"</span>,
    <span class="hljs-attr">"terminus"</span>: <span class="hljs-string">"Adidogome"</span>
}
</code></pre><ul>
<li>Then execute to have a result as below:</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627082389431/jQN9EiT1d.png" alt="image.png" /></p>
<p>Congratulations! You configured Spring Security and JWT to secure a REST API so that only authenticated consumers can access endpoints for requests.</p>
<p>But ... in the real world, every logged-in user should have the ability to access some endpoints while others no. Let's strengthen our API security.</p>
<h2 id="spring-security-method-level-security">Spring Security: method level security</h2>
<p>Remember, we added <em> @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)</em> annotation to the <em>SecurityConfig.java</em> class. This annotation enables  method level security.</p>
<p>In the <em>RouteRepository.java</em> class, suppose we want only ROLE_ADMIN users to have the ability to access the <em>findRoutesByName</em> method.</p>
<p>Add <em> @PreAuthorize("hasRole('ROLE_ADMIN')")</em> annotation to that method to grant access to ROLE_ADMIN users. Updated code of RouteRepository.java:</p>
<pre><code><span class="hljs-selector-tag">package</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.repository</span>;

<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.model</span><span class="hljs-selector-class">.Route</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.util</span><span class="hljs-selector-class">.Optional</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.jpa</span><span class="hljs-selector-class">.repository</span><span class="hljs-selector-class">.JpaRepository</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.repository</span><span class="hljs-selector-class">.query</span><span class="hljs-selector-class">.Param</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.rest</span><span class="hljs-selector-class">.core</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.RepositoryRestResource</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.rest</span><span class="hljs-selector-class">.core</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.RestResource</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.security</span><span class="hljs-selector-class">.access</span><span class="hljs-selector-class">.prepost</span><span class="hljs-selector-class">.PreAuthorize</span>;

<span class="hljs-keyword">@RepositoryRestResource</span>
public interface RouteRepository extends JpaRepository&lt;Route, Long&gt; {

  <span class="hljs-keyword">@PreAuthorize</span>("hasRole('ROLE_ADMIN')")
  @RestResource(path = <span class="hljs-string">"routesByName"</span>)
  Optional&lt;Route&gt; findRoutesByName(@Param(<span class="hljs-string">"name"</span>) String name);
}
</code></pre><p>Let's test the API again.</p>
<p>1 . Make sure you preloaded two different users, one with the ROLE_ADMIN and the other no.</p>
<p>2 . Make a POST request to log in with the admin user credentials, then copy the token</p>
<p>3 . Try to make a POST request to save route, GET request to search route, etc. using the Authorization token in Header tab, you should have successful responses.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627085107758/_x06HU8-w.png" alt="image.png" /></p>
<p>4 .  Now login with the simple user (who had no ROLE_ADMIN role) credentials and copy the token</p>
<p>5 .  Using Authorization token in Header tab, all POST and GET methods should be successful except the GET request for search route!</p>
<pre><code>http://localhost:<span class="hljs-number">9000</span>/api/routes/<span class="hljs-keyword">search</span>/routesByName?<span class="hljs-type">name</span>=Rex-Adidogome
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627084887931/YoQGOdfkX.png" alt="image.png" /></p>
<p>We got a Forbidden error stating that the logged-in user is not allowed to query this method.</p>
<p>In the next post, we will be adding new features to our EasyTrans app. Hope you learned something new. If so, don't forget to hit the Like button and subscribe to this blog to be up to date with new posts.</p>
]]></content:encoded></item><item><title><![CDATA[Java FullStack Spring boot & React app: Backend REST API / 3 - Securing the REST API with Spring Security & JWT (a)]]></title><description><![CDATA[Welcome back!
In the previous tutorial, we have set up the CRUD operations in our REST API. In this tutorial we're going to secure the REST API using Spring security and Json Web Token a.k.a JWT. Reminder : this tutorial is part of series covering a ...]]></description><link>https://blog.wilsonkomlan.com/java-fullstack-backend-rest-api-spring-security-and-jwt-a</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/java-fullstack-backend-rest-api-spring-security-and-jwt-a</guid><category><![CDATA[Springboot]]></category><category><![CDATA[Java]]></category><category><![CDATA[full stack]]></category><category><![CDATA[JWT]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Sat, 24 Jul 2021 00:45:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1627063037235/3uSu3aZfIM.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome back!</p>
<p>In the <a target="_blank" href="https://wilkom2009.hashnode.dev/java-fullstack-spring-boot-and-react-app-backend-rest-api-2">previous tutorial</a>, we have set up the CRUD operations in our REST API. In this tutorial we're going to secure the REST API using <a target="_blank" href="https://spring.io/projects/spring-security">Spring security</a> and <a target="_blank" href="https://jwt.io/">Json Web Token a.k.a JWT</a>. Reminder : this tutorial is part of <a target="_blank" href="https://wilkom2009.hashnode.dev/project-introduction">series</a> covering a full-stack app development.</p>
<h2 id="what-well-cover-here">What we'll cover here</h2>
<ul>
<li>How to customize Spring security to fetch users from database</li>
<li>How to implement JWT token management in Spring boot REST API</li>
<li>How to expose a REST POST API /login to generate a JWT token</li>
</ul>
<h2 id="user-entity-and-repository">User entity and repository</h2>
<p>We are going to create an enum class to manage static roles for simplicity purpose. Let's create a package: <em>security.model</em>, then, in the model package create <em>ERole.java</em> class as follow:</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi.security.model;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">enum</span> <span class="hljs-title">ERole</span> </span>{
  ROLE_ADMIN,
  ROLE_USER,
}
</code></pre><p>Here, we have two roles: ROLE_ADMIN for administrator role and ROLE_USER for a simple user role. you can add more roles as needed.</p>
<p>Once roles class coded, we gonna create a custom user class in the same package as ERole.java, we'll annotated it as an entity.</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi.security.model;


<span class="hljs-keyword">import</span> java.util.Objects;
<span class="hljs-keyword">import</span> java.util.Set;

<span class="hljs-keyword">import</span> javax.persistence.ElementCollection;
<span class="hljs-keyword">import</span> javax.persistence.Entity;
<span class="hljs-keyword">import</span> javax.persistence.EnumType;
<span class="hljs-keyword">import</span> javax.persistence.Enumerated;
<span class="hljs-keyword">import</span> javax.persistence.GeneratedValue;
<span class="hljs-keyword">import</span> javax.persistence.GenerationType;
<span class="hljs-keyword">import</span> javax.persistence.Id;
<span class="hljs-keyword">import</span> javax.persistence.Table;

<span class="hljs-meta">@Entity</span>
<span class="hljs-meta">@Table(name = <span class="hljs-meta-string">"users"</span>)</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> </span>{

  <span class="hljs-meta">@Id</span>
  <span class="hljs-meta">@GeneratedValue(strategy = GenerationType.AUTO)</span>
  <span class="hljs-keyword">private</span> <span class="hljs-built_in">Long</span> id;

  <span class="hljs-keyword">private</span> String userName;
  <span class="hljs-keyword">private</span> String password;
  <span class="hljs-keyword">private</span> String name;
  <span class="hljs-meta">@ElementCollection</span> (targetClass = ERole.<span class="hljs-keyword">class</span>)
  <span class="hljs-meta">@Enumerated(EnumType.STRING)</span>
  <span class="hljs-keyword">private</span> Set&lt;ERole&gt; roles;

  <span class="hljs-keyword">public</span> User() {}

  <span class="hljs-keyword">public</span> User(
    String userName,
    String password,
    String name,
    Set&lt;ERole&gt; roles
  ) {
    <span class="hljs-keyword">this</span>.userName = userName;
    <span class="hljs-keyword">this</span>.password = password;
    <span class="hljs-keyword">this</span>.name = name;
    <span class="hljs-keyword">this</span>.roles = roles;
  }
<span class="hljs-comment">/**
   * getters and setters
   */</span>
</code></pre><p><em>@ElementCollection</em> is used to map the ERole.java enum list which is not an entity while <em>@Enumerated(EnumType.STRING)</em>, especially ( <em> EnumType.STRING </em> ) tells JPA to persist Enum names instead of their index numbers in the DB.</p>
<p>Now, let's create the repository to manage the <em>User.class</em> in a new package : <em>security.repository</em> .</p>
<pre><code><span class="hljs-selector-tag">package</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.security</span><span class="hljs-selector-class">.repository</span>;

<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.security</span><span class="hljs-selector-class">.model</span><span class="hljs-selector-class">.User</span>;

<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.util</span><span class="hljs-selector-class">.Optional</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.jpa</span><span class="hljs-selector-class">.repository</span><span class="hljs-selector-class">.JpaRepository</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.rest</span><span class="hljs-selector-class">.core</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.RepositoryRestResource</span>;

<span class="hljs-keyword">@RepositoryRestResource</span>
public interface UserRepository extends JpaRepository&lt;User, Long&gt; {
  <span class="hljs-selector-tag">Optional</span>&lt;<span class="hljs-selector-tag">User</span>&gt; <span class="hljs-selector-tag">findByUserName</span>(<span class="hljs-selector-tag">String</span> <span class="hljs-selector-tag">userName</span>);
}
</code></pre><p><em>findByUserName</em> is a query method to fetch user by a given userName. You can read more about <a target="_blank" href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods">Spring Data JPA query methods here</a>.</p>
<p>User entity is now ready to be used, in the following sections, we are going to implement very interesting spring security features.</p>
<h2 id="dependency-management">Dependency management</h2>
<p>Open the pom.xml file and add following dependencies:</p>
<pre><code><span class="hljs-comment">&lt;!-- Spring security --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.springframework.boot<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>spring-boot-starter-security<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- JWT  --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.jsonwebtoken<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jjwt<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>0.9.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>

        <span class="hljs-comment">&lt;!-- very important while using java 11 and above --&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>javax.xml.bind<span class="hljs-tag">&lt;/<span class="hljs-name">groupId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">artifactId</span>&gt;</span>jaxb-api<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">version</span>&gt;</span>2.3.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">dependency</span>&gt;</span>
</code></pre><h3 id="customize-spring-security-to-fetch-user-from-db-h2-database">Customize Spring security to fetch user from DB (H2 database)</h3>
<p>In order to use custom user management in Spring Security, we must first implement Spring security core <strong><em>UserDetails</em></strong> interface to map our custom User detail class to Spring security User class and then implement Spring security core <strong><em>UserDetailsService</em></strong> interface so that Spring can query users from the DB.</p>
<p>Within security package, create a class named UserDetailsImpl.java :</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi.security;

<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.model.User;
<span class="hljs-keyword">import</span> com.fasterxml.jackson.<span class="hljs-keyword">annotation</span>.JsonIgnore;
<span class="hljs-keyword">import</span> java.util.Collection;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.Objects;
<span class="hljs-keyword">import</span> java.util.stream.Collectors;
<span class="hljs-keyword">import</span> org.springframework.security.core.GrantedAuthority;
<span class="hljs-keyword">import</span> org.springframework.security.core.authority.SimpleGrantedAuthority;
<span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetails;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserDetailsImpl</span> <span class="hljs-title">implements</span> <span class="hljs-title">UserDetails</span> </span>{

  <span class="hljs-keyword">private</span> <span class="hljs-built_in">Long</span> id;

  <span class="hljs-keyword">private</span> String username;

  <span class="hljs-meta">@JsonIgnore</span>
  <span class="hljs-keyword">private</span> String password;

  <span class="hljs-keyword">private</span> Collection&lt;? extends GrantedAuthority&gt; authorities;

  <span class="hljs-keyword">public</span> UserDetailsImpl(
    <span class="hljs-built_in">Long</span> id,
    String username,
    String password,
    Collection&lt;? extends GrantedAuthority&gt; authorities
  ) {
    <span class="hljs-keyword">this</span>.id = id;
    <span class="hljs-keyword">this</span>.username = username;
    <span class="hljs-keyword">this</span>.password = password;
    <span class="hljs-keyword">this</span>.authorities = authorities;
  }

  <span class="hljs-comment">/**
   * Static method to expose UserDetailsImpl object created by given user
   * <span class="hljs-doctag">@param</span> user
   * <span class="hljs-doctag">@return</span> UserDetailsImpl object
   */</span>
  <span class="hljs-keyword">public</span> static UserDetailsImpl build(User user) {
    <span class="hljs-comment">// Map user roles list to Spring Security GrantedAuthority list</span>
    List&lt;GrantedAuthority&gt; authorities = List
      .copyOf(user.getRoles())
      .stream()
      .map(role -&gt; new SimpleGrantedAuthority(role.name()))
      .collect(Collectors.toList());

    <span class="hljs-keyword">return</span> new UserDetailsImpl(
      user.getId(),
      user.getUserName(),
      user.getPassword(),
      authorities
    );
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {
    <span class="hljs-keyword">return</span> authorities;
  }

  <span class="hljs-keyword">public</span> <span class="hljs-built_in">Long</span> getId() {
    <span class="hljs-keyword">return</span> id;
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> String getPassword() {
    <span class="hljs-keyword">return</span> password;
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> String getUsername() {
    <span class="hljs-keyword">return</span> username;
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> boolean isAccountNonExpired() {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> boolean isAccountNonLocked() {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> boolean isCredentialsNonExpired() {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> boolean isEnabled() {
    <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
  }

  <span class="hljs-meta">@Override</span>
  <span class="hljs-keyword">public</span> boolean equals(Object o) {
    <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span> == o) <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    <span class="hljs-keyword">if</span> (o == <span class="hljs-literal">null</span> || getClass() != o.getClass()) <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    UserDetailsImpl user = (UserDetailsImpl) o;
    <span class="hljs-keyword">return</span> Objects.equals(id, user.id);
  }
}
</code></pre><p>Now, we can implement the UserDetailsService. Create <em>UserDetailsServiceImpl.java</em> class in <em>security</em> package as follow:</p>
<pre><code>package com.codeurinfo.easytransapi.<span class="hljs-keyword">security</span>;

<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.<span class="hljs-keyword">security</span>.model.<span class="hljs-keyword">User</span>;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.<span class="hljs-keyword">security</span>.repository.UserRepository;
<span class="hljs-keyword">import</span> java.util.ArrayList;

<span class="hljs-keyword">import</span> javax.<span class="hljs-keyword">transaction</span>.Transactional;

<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.core.userdetails.UserDetails;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.core.userdetails.UserDetailsService;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

@Service
<span class="hljs-built_in">public</span> <span class="hljs-keyword">class</span> UserDetailsServiceImpl implements UserDetailsService {

  @Autowired
  private UserRepository userRepository;

  <span class="hljs-comment">/**
   * Override this method to fetch user by userName from th db
   * using the UserRepository
   * @Transactional is used to manage User &amp; roles collection lazy loading
   */</span>
  @Override
  @Transactional
  <span class="hljs-built_in">public</span> UserDetails loadUserByUsername(String userName) {

    <span class="hljs-keyword">User</span> <span class="hljs-keyword">user</span> = userRepository.findByUserName(userName).orElse(<span class="hljs-keyword">null</span>);

    <span class="hljs-keyword">return</span> UserDetailsImpl.build(<span class="hljs-keyword">user</span>);
  }
}
</code></pre><h3 id="create-a-jwt-utility-class">Create a JWT utility class</h3>
<p>In the security package, create a package util and create JwtUtil.class.</p>
<pre><code>package com.codeurinfo.easytransapi.security.util;

<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.UserDetailsImpl;
<span class="hljs-keyword">import</span> io.jsonwebtoken.Claims;
<span class="hljs-keyword">import</span> io.jsonwebtoken.Jwts;
<span class="hljs-keyword">import</span> io.jsonwebtoken.SignatureAlgorithm;
<span class="hljs-keyword">import</span> java.util.Date;
<span class="hljs-keyword">import</span> java.util.HashMap;
<span class="hljs-keyword">import</span> java.util.Map;
<span class="hljs-keyword">import</span> java.util.function.Function;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;

<span class="hljs-meta">@Service</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> JwtUtil {

  <span class="hljs-comment">// Give a secret key for JWT token generating &amp; validation</span>
  <span class="hljs-keyword">private</span> <span class="hljs-built_in">String</span> SECRET_KEY = <span class="hljs-string">"secret"</span>;

  <span class="hljs-comment">// get username from the provided token</span>
  <span class="hljs-keyword">public</span> <span class="hljs-built_in">String</span> extractUsername(<span class="hljs-built_in">String</span> token) {
    <span class="hljs-keyword">return</span> extractClaim(token, Claims::getSubject);
  }

  <span class="hljs-comment">//get the token expiration time</span>
  <span class="hljs-keyword">public</span> <span class="hljs-built_in">Date</span> extractExpiration(<span class="hljs-built_in">String</span> token) {
    <span class="hljs-keyword">return</span> extractClaim(token, Claims::getExpiration);
  }

  <span class="hljs-comment">// get token infos</span>
  <span class="hljs-keyword">public</span> &lt;T&gt; T extractClaim(<span class="hljs-built_in">String</span> token, <span class="hljs-built_in">Function</span>&lt;Claims, T&gt; claimsResolver) {
    final Claims claims = extractAllClaims(token);
    <span class="hljs-keyword">return</span> claimsResolver.apply(claims);
  }

  <span class="hljs-keyword">private</span> Claims extractAllClaims(<span class="hljs-built_in">String</span> token) {
    <span class="hljs-keyword">return</span> Jwts
      .parser()
      .setSigningKey(SECRET_KEY)
      .parseClaimsJws(token)
      .getBody();
  }

  <span class="hljs-keyword">private</span> <span class="hljs-built_in">Boolean</span> isTokenExpired(<span class="hljs-built_in">String</span> token) {
    <span class="hljs-keyword">return</span> extractExpiration(token).before(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>());
  }

  <span class="hljs-keyword">public</span> <span class="hljs-built_in">String</span> generateToken(UserDetailsImpl userDetails) {
    <span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">Object</span>&gt; claims = <span class="hljs-keyword">new</span> HashMap&lt;&gt;();
    <span class="hljs-keyword">return</span> createToken(claims, userDetails.getUsername());
  }

  <span class="hljs-comment">/**
   * Generate a token for the provided subject (username)
   * @param claims
   * @param subject
   */</span>
  <span class="hljs-keyword">private</span> <span class="hljs-built_in">String</span> createToken(<span class="hljs-built_in">Map</span>&lt;<span class="hljs-built_in">String</span>, <span class="hljs-built_in">Object</span>&gt; claims, <span class="hljs-built_in">String</span> subject) {
    <span class="hljs-keyword">return</span> Jwts
      .builder()
      .setClaims(claims)
      .setSubject(subject)
      .setIssuedAt(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(System.currentTimeMillis()))
      .setExpiration(<span class="hljs-keyword">new</span> <span class="hljs-built_in">Date</span>(System.currentTimeMillis() + <span class="hljs-number">1000</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span> * <span class="hljs-number">10</span>)) <span class="hljs-comment">//Expiration in 36,000,000 ms (10 hours)</span>
      .signWith(SignatureAlgorithm.HS256, SECRET_KEY) <span class="hljs-comment">// signing with HS256 algorythm</span>
      .compact();<span class="hljs-comment">//According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1)</span>
      <span class="hljs-comment">//   compaction of the JWT to a URL-safe string </span>
  }

  <span class="hljs-comment">/**
   * Validate token
   */</span>
  <span class="hljs-keyword">public</span> <span class="hljs-built_in">Boolean</span> validateToken(<span class="hljs-built_in">String</span> token, UserDetailsImpl userDetails) {
    final <span class="hljs-built_in">String</span> username = extractUsername(token);

    <span class="hljs-keyword">return</span> (
      username.equals(userDetails.getUsername()) &amp;&amp; !isTokenExpired(token)
    );
  }
}
</code></pre><h3 id="providing-a-login-rest-api-post-endpoint">Providing a /login REST API POST endpoint</h3>
<p>In this section, we'll be coding a controller to expose an authentication endpoint to our REST API.</p>
<p>Let's create <em>AuthenticationRequest.java</em> class in security.model package in order to hold the username and password coming from our REST API consumer's http request payload.</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi.security.model;

<span class="hljs-keyword">import</span> java.util.Objects;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationRequest</span> </span>{

  <span class="hljs-keyword">private</span> String userName;
  <span class="hljs-keyword">private</span> String password;

  <span class="hljs-keyword">public</span> AuthenticationRequest() {}

  <span class="hljs-keyword">public</span> AuthenticationRequest(String userName, String password) {
    <span class="hljs-keyword">this</span>.userName = userName;
    <span class="hljs-keyword">this</span>.password = password;
  }

 <span class="hljs-comment">// Getters and setters</span>

}
</code></pre><p>Create another class named <em>AuthenticationResponse.java</em> to send the response containing the JWT token to the client.</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi.security.model;

<span class="hljs-keyword">import</span> java.util.Objects;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthenticationResponse</span> </span>{

  <span class="hljs-keyword">private</span> String jwt;

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AuthenticationResponse</span><span class="hljs-params">()</span> </span>{}

  <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">AuthenticationResponse</span><span class="hljs-params">(String jwt)</span> </span>{
    <span class="hljs-keyword">this</span>.jwt = jwt;
  }

  <span class="hljs-comment">// getters and setters</span>
</code></pre><p>To expose a<strong> /login</strong> endpoint that will accept an <em>AuthenticationRequest</em> object and return an AuthenticationResponse object to the client, let's create   <em>AuthController.java</em> class in the <em>security</em> package.</p>
<pre><code>package com.codeurinfo.easytransapi;

<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.UserDetailsImpl;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.UserDetailsServiceImpl;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.model.AuthenticationRequest;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.model.AuthenticationResponse;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.repository.UserRepository;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.util.JwtUtil;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.http.ResponseEntity;
<span class="hljs-keyword">import</span> org.springframework.security.authentication.AuthenticationManager;
<span class="hljs-keyword">import</span> org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
<span class="hljs-keyword">import</span> org.springframework.security.core.Authentication;
<span class="hljs-keyword">import</span> org.springframework.security.core.context.SecurityContextHolder;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.PostMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RequestBody;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.RestController;

@<span class="hljs-type">RestController</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AuthController</span> </span>{

  @<span class="hljs-type">Autowired</span>
  <span class="hljs-keyword">private</span> <span class="hljs-type">AuthenticationManager</span> authenticationManager;

  @<span class="hljs-type">Autowired</span>
  <span class="hljs-keyword">private</span> <span class="hljs-type">UserDetailsServiceImpl</span> userDetailsService;

  @<span class="hljs-type">Autowired</span>
  <span class="hljs-keyword">private</span> <span class="hljs-type">JwtUtil</span> jwtUtil;

  @<span class="hljs-type">PostMapping</span>(<span class="hljs-string">"/api/auth/login"</span>)
  <span class="hljs-keyword">public</span> <span class="hljs-type">ResponseEntity</span> createAuthenticationToken(
    @<span class="hljs-type">RequestBody</span> <span class="hljs-type">AuthenticationRequest</span> request
  )
    <span class="hljs-keyword">throws</span> <span class="hljs-type">Exception</span> {
    <span class="hljs-type">Authentication</span> authentication = null;
    <span class="hljs-keyword">try</span> {
      <span class="hljs-comment">// Use AuthenticationManager to verify the provided username/password</span>
      authentication =
        authenticationManager.authenticate(
          new <span class="hljs-type">UsernamePasswordAuthenticationToken</span>(
            request.getUserName(),
            request.getPassword()
          )
        );
    } <span class="hljs-keyword">catch</span> (<span class="hljs-type">Exception</span> exception) {
      <span class="hljs-keyword">throw</span> new <span class="hljs-type">Exception</span>(<span class="hljs-string">"Incorrect username or password"</span>);
    }
    <span class="hljs-comment">//if username/password valid, put the Authentication created object in the SecurityContextHolder's context</span>
    <span class="hljs-type">SecurityContextHolder</span>.getContext().setAuthentication(authentication);

    <span class="hljs-comment">// Retrieve the user from the UserDetailsServiceImpl</span>
    <span class="hljs-keyword">final</span> <span class="hljs-type">UserDetailsImpl</span> userDetails = (<span class="hljs-type">UserDetailsImpl</span>) userDetailsService.loadUserByUsername(
      request.getUserName()
    );

    <span class="hljs-comment">// Generate the token from the JWT util class</span>
    <span class="hljs-type">String</span> jwt = jwtUtil.generateToken(userDetails);

    <span class="hljs-comment">// Send AuthenticationResponse response to client</span>
    <span class="hljs-keyword">return</span> <span class="hljs-type">ResponseEntity</span>.ok(new <span class="hljs-type">AuthenticationResponse</span>(jwt));
  }
}
</code></pre><p>We can now create <em>SecurityConfig.java</em> class, a configuration class to extends <em>WebSecurityConfigurerAdapter</em> class. </p>
<pre><code>package com.codeurinfo.easytransapi.<span class="hljs-keyword">security</span>;

<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.authentication.AuthenticationManager;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.config.annotation.authentication.builders.AuthenticationManagerBuilder;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.config.annotation.<span class="hljs-keyword">method</span>.<span class="hljs-keyword">configuration</span>.EnableGlobalMethodSecurity;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.config.annotation.web.builders.HttpSecurity;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.config.annotation.web.<span class="hljs-keyword">configuration</span>.EnableWebSecurity;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.config.annotation.web.<span class="hljs-keyword">configuration</span>.WebSecurityConfigurerAdapter;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.config.http.SessionCreationPolicy;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.crypto.bcrypt.BCryptPasswordEncoder;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.crypto.<span class="hljs-keyword">password</span>.PasswordEncoder;
<span class="hljs-keyword">import</span> org.springframework.<span class="hljs-keyword">security</span>.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity // <span class="hljs-keyword">Enable</span> Spring <span class="hljs-keyword">Security</span>’s web <span class="hljs-keyword">security</span> support
@EnableGlobalMethodSecurity(securedEnabled = <span class="hljs-keyword">true</span>, prePostEnabled = <span class="hljs-keyword">true</span>) //<span class="hljs-keyword">To</span> configure <span class="hljs-keyword">method</span>-<span class="hljs-keyword">level</span> <span class="hljs-keyword">security</span>
<span class="hljs-built_in">public</span> <span class="hljs-keyword">class</span> SecurityConfig extends WebSecurityConfigurerAdapter {

  @Autowired
  private UserDetailsServiceImpl customUserDetailsService;


  @Override
  protected <span class="hljs-type">void</span> configure(AuthenticationManagerBuilder auth) throws <span class="hljs-keyword">Exception</span> {
    auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
  }

  @Override
  protected <span class="hljs-type">void</span> configure(HttpSecurity http) throws <span class="hljs-keyword">Exception</span> {
    http
      .csrf()
      .<span class="hljs-keyword">disable</span>()
      .authorizeRequests()
      .antMatchers("/api/auth/**").permitAll() // <span class="hljs-keyword">Grant</span> <span class="hljs-keyword">access</span> <span class="hljs-keyword">to</span> every /api/auth based url
      .anyRequest().authenticated() // <span class="hljs-keyword">All</span> other based url wil be allowed <span class="hljs-keyword">if</span> authenticated
      .<span class="hljs-keyword">and</span>()
      .sessionManagement()
      .sessionCreationPolicy(SessionCreationPolicy.STATELESS);//Force <span class="hljs-keyword">server</span> <span class="hljs-keyword">not</span> <span class="hljs-keyword">to</span> never <span class="hljs-keyword">create</span> an HttpSession

  }

  @Override
  @Bean
  <span class="hljs-built_in">public</span> AuthenticationManager authenticationManagerBean() throws <span class="hljs-keyword">Exception</span> {
    <span class="hljs-keyword">return</span> super.authenticationManagerBean();
  }

  @Bean
  <span class="hljs-built_in">public</span> PasswordEncoder passwordEncoder() {
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">new</span> BCryptPasswordEncoder();
  }
}
</code></pre><p>You can learn more about the <em>SecurityConfig.java</em> class <a target="_blank" href="https://spring.io/guides/gs/securing-web/">here.</a></p>
<p>Once more class to code before we can test our API. For simplicity purpose, we'll be preloading users into the database and try to log in with their corresponding cridentials.</p>
<p> Thanks to Spring boot's <em>CommandLineRunner</em> interface, we can create a preload class <em>DatabaseLoader.java</em> like this:</p>
<pre><code>package com.codeurinfo.easytransapi;

<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.model.ERole;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.model.User;
<span class="hljs-keyword">import</span> com.codeurinfo.easytransapi.security.repository.UserRepository;
<span class="hljs-keyword">import</span> java.util.Arrays;
<span class="hljs-keyword">import</span> java.util.<span class="hljs-built_in">Set</span>;
<span class="hljs-keyword">import</span> org.springframework.beans.<span class="hljs-keyword">factory</span>.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.boot.CommandLineRunner;
<span class="hljs-keyword">import</span> org.springframework.security.crypto.password.PasswordEncoder;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;

<span class="hljs-meta">@Component</span>
public <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DatabaseLoader</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">CommandLineRunner</span> </span>{

  <span class="hljs-meta">@Autowired</span>
  UserRepository userRepository;

  <span class="hljs-meta">@Autowired</span>
  PasswordEncoder encoder;

  <span class="hljs-meta">@Override</span>
  public <span class="hljs-keyword">void</span> run(<span class="hljs-built_in">String</span>... args) throws Exception {
    <span class="hljs-comment">// remember we use PasswordEncoder to configure the AuthenticationManagerBuilder in the SecurityConfig class</span>
    <span class="hljs-comment">// thus you must encode  pwd using the same encoder (BCryptPasswordEncoder) before persit</span>
    <span class="hljs-built_in">String</span> pwd1 = encoder.encode(<span class="hljs-string">"will"</span>);
    <span class="hljs-built_in">String</span> pwd2 = encoder.encode(<span class="hljs-string">"user"</span>);
    userRepository.save(
      <span class="hljs-keyword">new</span> User(
        <span class="hljs-string">"will"</span>,
        pwd1,
        <span class="hljs-string">"Wilson"</span>,
        <span class="hljs-built_in">Set</span>.copyOf(Arrays.asList(ERole.ROLE_ADMIN, ERole.ROLE_USER))
      )
    );
    userRepository.save(
      <span class="hljs-keyword">new</span> User(
        <span class="hljs-string">"user"</span>,
        pwd2,
        <span class="hljs-string">"Adjowa"</span>,
        <span class="hljs-built_in">Set</span>.copyOf(Arrays.asList(ERole.ROLE_USER))
      )
    );
  }
}
</code></pre><p>Run the project, go to Postman and make a POST request to this endpoint :</p>
<pre><code><span class="hljs-attribute">http</span>:<span class="hljs-comment">//localhost:8000/api/auth/login</span>
</code></pre><p>You must have a result like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1627061561428/Juik7Zlsk.png" alt="image.png" /></p>
<p> Voila, through our REST API we can log in once and get a token to use in http request headers  for the next 10 hours. In the next tutorial, we'll see how to validate client request header token and how to grant access to endpoints according to users roles.</p>
<p>Hope you learned something new. If so, don't forget to hit the Like button and subscribe to this blog to be up to date with new posts.</p>
]]></content:encoded></item><item><title><![CDATA[Java FullStack Spring boot & React app : Backend REST API / 2 - Spring Data REST in action]]></title><description><![CDATA[Hello,
In previous tutorial we've set up the Easytrans project. In this one, we'll go deep in the REST api.
We will learn how to :

Create entity

Create repository and expose it as REST endpoints without using any other controller component

Create ...]]></description><link>https://blog.wilsonkomlan.com/java-fullstack-spring-boot-and-react-app-backend-rest-api-2</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/java-fullstack-spring-boot-and-react-app-backend-rest-api-2</guid><category><![CDATA[Java]]></category><category><![CDATA[React]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[full stack]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Fri, 16 Jul 2021 01:54:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1626727086542/3c5O_LLHw.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello,
In <a target="_blank" href="https://wilkom2009.hashnode.dev/java-fullstack-spring-boot-and-react-app-backend-rest-api-1">previous tutorial</a> we've set up the Easytrans project. In this one, we'll go deep in the REST api.</p>
<p>We will learn how to :</p>
<ul>
<li><p>Create entity</p>
</li>
<li><p>Create repository and expose it as REST endpoints without using any other controller component</p>
</li>
<li><p>Create queries</p>
</li>
<li>Custom query url</li>
<li>Custom REST API base path</li>
</ul>
<h3 id="entity-and-repository-creation">Entity &amp; repository  creation</h3>
<p>Create a package named : <em>model</em>, and create a class: <em>Route.java</em> such as shown below:</p>
<pre><code><span class="hljs-keyword">package</span> com.codeurinfo.easytransapi.model;

<span class="hljs-keyword">import</span> java.util.Objects;
<span class="hljs-keyword">import</span> javax.persistence.Column;
<span class="hljs-keyword">import</span> javax.persistence.Entity;
<span class="hljs-keyword">import</span> javax.persistence.GeneratedValue;
<span class="hljs-keyword">import</span> javax.persistence.GenerationType;
<span class="hljs-keyword">import</span> javax.persistence.Id;
<span class="hljs-keyword">import</span> javax.persistence.Table;

<span class="hljs-meta">@Entity</span>
<span class="hljs-meta">@Table(name = <span class="hljs-meta-string">"routes"</span>)</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Route</span> </span>{

  <span class="hljs-meta">@Id</span>
  <span class="hljs-meta">@GeneratedValue(strategy = GenerationType.AUTO)</span>
  <span class="hljs-keyword">private</span> <span class="hljs-built_in">Long</span> id;

  <span class="hljs-meta">@Column(unique = true)</span>
  <span class="hljs-keyword">private</span> String name;

  <span class="hljs-keyword">private</span> String start;
  <span class="hljs-keyword">private</span> String terminus;

<span class="hljs-keyword">public</span> Route() {}

  <span class="hljs-keyword">public</span> Route(String name, String start, String terminus) {
    <span class="hljs-keyword">this</span>.name = name;
    <span class="hljs-keyword">this</span>.start = start;
    <span class="hljs-keyword">this</span>.terminus = terminus;
  }

<span class="hljs-comment">/**
Getters and Setters
*/</span>

}
</code></pre><p>A simple class like that. </p>
<p><em>@Entity</em> annotation is to tell database that this class is going to be an entity whereas <em> @Table</em> is used to give the custom name for the corresponding table in the DB. You can visit <a target="_blank" href="https://walkingtechie.blogspot.com/2019/06/difference-between-entity-and-table.html">this blog</a> for more information about these two annotations.
We add a constraint @Column(unique = true) to avoid name duplication.</p>
<p>Next, we're going to create the repository, so create a package named: <em>repository</em> in which you create a class: <em>RouteRepository.java</em>:</p>
<pre><code><span class="hljs-selector-tag">package</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.repository</span>;

<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.model</span><span class="hljs-selector-class">.Route</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.util</span><span class="hljs-selector-class">.Optional</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.jpa</span><span class="hljs-selector-class">.repository</span><span class="hljs-selector-class">.JpaRepository</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.repository</span><span class="hljs-selector-class">.query</span><span class="hljs-selector-class">.Param</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.rest</span><span class="hljs-selector-class">.core</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.RepositoryRestResource</span>;

<span class="hljs-keyword">@RepositoryRestResource</span>
public interface RouteRepository extends JpaRepository&lt;Route, Long&gt; {
  <span class="hljs-selector-tag">Optional</span>&lt;<span class="hljs-selector-tag">Route</span>&gt; <span class="hljs-selector-tag">findRoutesByName</span>(<span class="hljs-keyword">@Param</span>("name") String name);
}
</code></pre><ul>
<li>We use <em>@RepositoryRestResource</em> instead of <em>@Repository</em> because it directly exposes the repository interface as a REST endpoint, so there would be no need for another REST controller like in our case.</li>
</ul>
<p>Now, our backend REST API is ready! Let's test it using Postman.</p>
<ol>
<li><p>Run the main class (<em>EasytransApiApplication.java</em> in our case)</p>
</li>
<li><p>Got to Postman and make a http GET request against this url : 
http://localhost:9000/routes</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626394461128/-2ja72Xl_.png" alt="image.png" /></p>
<p>As result, you'll notice that <em>routes</em> array is empty, that's right because we have no records persisted; also Spring Data Rest generated useful links through "_links" object.
We'll later make use of "http://localhost:9000/routes/search" for different seach queries</p>
<p>3 . In the Postman again, let's make Http POST request against this url:
http://localhost:9000/routes
In Body tab, select raw and JSON, then past the body below:</p>
<pre><code>{
    <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Rex-Adetikope"</span>,
    <span class="hljs-attr">"start"</span>: <span class="hljs-string">"Grand marche - Rex"</span>,
    <span class="hljs-attr">"terminus"</span>: <span class="hljs-string">"Adetikope"</span>
}
</code></pre><p>Clic <em>Send</em> to persist the data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626394562476/JKLimu6xt.png" alt="image.png" /></p>
<p>4 . Let's try our previous GET request against : http://localhost:9000/routes
Now the routes array contains the persited data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626395200079/CLOHA0vTh.png" alt="image.png" /></p>
<p>5 . Now that our REST API allows us to list routes and to persist some route objects, let's make search queries.</p>
<ul>
<li>Find a specific route providing its name in the GET request : <pre><code>http://localhost:<span class="hljs-number">9000</span>/routes/<span class="hljs-keyword">search</span>/findRoutesByName?<span class="hljs-type">name</span>=Rex-Adetikope
</code></pre></li>
<li>Notice, after the search url provided by Spring Data Rest, we add the query method signature (<em>findRoutesByName</em>) followed by the attribute specified in the @Param, which here is <em>name</em>.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626396351195/1Wsk5Em6q.png" alt="image.png" /></p>
<h3 id="search-url-customization">Search url customization</h3>
<p>Instead of using <em>findRoutesByName</em> in the search url, let's use a shorter name:  <em>routesByName</em> .</p>
<p>To do so, go to the repository interface and add the annotation <em>@RestResource(path = "routesByName")</em>, our interface must look like this:</p>
<pre><code><span class="hljs-selector-tag">package</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.repository</span>;

<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.codeurinfo</span><span class="hljs-selector-class">.easytransapi</span><span class="hljs-selector-class">.model</span><span class="hljs-selector-class">.Route</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">java</span><span class="hljs-selector-class">.util</span><span class="hljs-selector-class">.Optional</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.jpa</span><span class="hljs-selector-class">.repository</span><span class="hljs-selector-class">.JpaRepository</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.repository</span><span class="hljs-selector-class">.query</span><span class="hljs-selector-class">.Param</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.rest</span><span class="hljs-selector-class">.core</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.RepositoryRestResource</span>;
<span class="hljs-selector-tag">import</span> <span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.springframework</span><span class="hljs-selector-class">.data</span><span class="hljs-selector-class">.rest</span><span class="hljs-selector-class">.core</span><span class="hljs-selector-class">.annotation</span><span class="hljs-selector-class">.RestResource</span>;

<span class="hljs-keyword">@RepositoryRestResource</span>
public interface RouteRepository extends JpaRepository&lt;Route, Long&gt; {
  <span class="hljs-keyword">@RestResource</span>(path = <span class="hljs-string">"routesByName"</span>)
  Optional&lt;Route&gt; findRoutesByName(@Param(<span class="hljs-string">"name"</span>) String name);
}
</code></pre><p>Save and make a GET request against this url:</p>
<pre><code>http://localhost:<span class="hljs-number">9000</span>/routes/<span class="hljs-keyword">search</span>/routesByName?<span class="hljs-type">name</span>=Rex-Adetikope
</code></pre><p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626397281005/O2Qi-_za3.png" alt="image.png" />
As you can see we have the expected result using <em>routesByName</em> instead of <em>findRoutesByName</em>.</p>
<h3 id="setting-up-a-base-path">Setting up a base path</h3>
<p>In real project, most REST API root path begin with domain/api/path-to-resources, but as you can see, we directely call path-to-resources after the domain name. </p>
<p>To add the /api before any path-to-resource, open the application.yml file and add a spring base-path key and it's value like this:</p>
<pre><code><span class="hljs-attribute">spring</span>:
  <span class="hljs-attribute">data</span>:
    <span class="hljs-attribute">rest</span>:
      <span class="hljs-attribute">base-path</span>: /api
</code></pre><p> Save the yml file, try one of the pervious GET request, you we'll notice a 404 resource not found error.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626398606385/4nab22yxy.png" alt="image.png" /></p>
<p>This because from now, our REST API will be consumed using a base path /api/ before any other resource-path. So:
<em>http://localhost:9000/routes   -&gt;  http://localhost:9000/api/routes</em> etc.</p>
<p>Here is ! Congratulations you have built a basic Java Spring Boot REST API, hope you have learned something new. If so, don't forget to hit the Like button and subscribe to this blog to be notified of new posts.</p>
<p>In the next article, we will add new features to our EasyTrans app. Thank you for being part of this fullStack Java &amp; React developer journey!</p>
]]></content:encoded></item><item><title><![CDATA[Project introduction]]></title><description><![CDATA[Hello,
There are many tutorials dealing with topics such as spring boot, react.js, react native, etc. So it's usually a challenge to make a tutorial about these themes. Fortunately, most of these tutorials are chunks of code, which can be a trap for ...]]></description><link>https://blog.wilsonkomlan.com/project-introduction</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/project-introduction</guid><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[React]]></category><category><![CDATA[full stack]]></category><category><![CDATA[AWS]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Tue, 13 Jul 2021 09:16:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1626727163159/IggNZjT3f.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello,</p>
<p>There are many tutorials dealing with topics such as spring boot, react.js, react native, etc. So it's usually a challenge to make a tutorial about these themes. Fortunately, most of these tutorials are chunks of code, which can be a trap for beginners when it comes to joining them. So in this series, we are going to learn how to join pieces of code to make a really beautiful project. We think this will help someone on their developer journey!</p>
<h2 id="project-architecture">Project Architecture</h2>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626051445180/pUERHFIph.png" alt="project_schema.png" /></p>
<h2 id="project-description">Project description</h2>
<p>We'll build a transport company app, for this purpose we'll call it: <strong>EasyTrans App</strong>.</p>
<h3 id="1-backend-api-easytrans-api">1. Backend : API EasyTrans-api</h3>
<p>Technical specifications: <a target="_blank" href="https://start.spring.io/">Spring boot</a>, <a target="_blank" href="https://spring.io/guides/tutorials/react-and-spring-data-rest/">Spring Data REST</a></p>
<h3 id="2-mobile-app-easytrans-app">2. Mobile App: EasyTrans-app</h3>
<p>Technical specifications: <a target="_blank" href="http://reactnative.dev/">React Native</a></p>
<p>In the next  <a target="_blank" href="https://wilkom2009.hashnode.dev/series/springboot-react">tutorials</a>, we'll build each of these modules and host them on AWS Cloud for production.</p>
]]></content:encoded></item><item><title><![CDATA[Java FullStack Spring boot & React app : Backend REST API / 1 - API Set up]]></title><description><![CDATA[Hello,
In this tutorial, we'll set up the backend. What you'll learn here are:

How to initialize a Spring boot app using the official Spring boot initializer and 
How to customize a spring boot app port.

Project set up
Our backend API will be named...]]></description><link>https://blog.wilsonkomlan.com/java-fullstack-spring-boot-and-react-app-backend-rest-api-1</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/java-fullstack-spring-boot-and-react-app-backend-rest-api-1</guid><category><![CDATA[Java]]></category><category><![CDATA[Springboot]]></category><category><![CDATA[full stack]]></category><category><![CDATA[React]]></category><category><![CDATA[REST API]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Tue, 13 Jul 2021 00:54:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1626781165120/SQAopf3xi.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello,</p>
<p>In this tutorial, we'll set up the backend. What you'll learn here are:</p>
<ul>
<li>How to initialize a Spring boot app using the official Spring boot initializer and </li>
<li>How to customize a spring boot app port.</li>
</ul>
<h2 id="project-set-up">Project set up</h2>
<p>Our backend API will be named : <strong>Easytrans-api</strong>. Let's use <a target="_blank" href="https://start.spring.io/">Spring initializer</a> to initalize the project.</p>
<h3 id="initialize-the-project">Initialize the project</h3>
<ol>
<li>Go to : https://start.spring.io/</li>
<li>Choose Maven Project , language Java, Spring boot version (2.5.2 while I am writing this article)</li>
<li>In the Project Metadata section, type :</li>
</ol>
<ul>
<li></li>
<li>Group name : <em>com.codeurinfo</em>; (reminder, conventionally, a maven group id is the project reverse domain name, here our domain name is : codeurinfo.com)</li>
<li>Artifact : <em>easytrans-api</em></li>
<li>Name : <em>easytrans-api</em></li>
<li>Description : a beautifull description of yours</li>
<li>Package name : <em>com.codeurinfo.easytransapi</em></li>
<li>Packaging : <em>Jar</em> (we'll make use of the embeded tomcat server in spring boot)</li>
<li>Java : <em>8</em> </li>
</ul>
<p>4 . As for dependencies, we just need four, so in Dependencies section, hit ADD DEPENDENCIES ... and choose these below:</p>
<ul>
<li><em>Rest Repositories</em>, for Spring Data Rest</li>
<li><em>Spring Data JPA</em>, for JPA</li>
<li><em>H2 Database</em>, embeded database</li>
<li><em>Spring Boot DevTools</em></li>
</ul>
<p>Everything must look like this picture:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626133096279/v4QarBDym.png" alt="easytrans_start_io.PNG" /></p>
<p>You just need to hit GENERATE CTRL+ ... to generate the zip file of the project.</p>
<p>Now, unzip the zip file :) in your prefered directory and open it in your IDE.</p>
<p>Using VS Code, just open your editor and go to <strong>File -&gt; Open folder</strong> then select the project folder.</p>
<p>Our project is ready and must look like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626134392652/kDEn8n3cw.png" alt="project_vscode.PNG" /></p>
<p>Notice the 4 dependencies in the pom.xml file!</p>
<h3 id="test-project">Test project</h3>
<p>Our project is ready, before we run it, let's remove the <em>application.properties</em> file and add <em>application.yml</em> file in the <em>src/main/resources</em> folder.</p>
<p>Let's configure our app port to 9000. So, open the <em>application.yml</em> file and add the below code snipet:</p>
<pre><code><span class="hljs-attr">server:</span>
  <span class="hljs-attr">port:</span> <span class="hljs-number">9000</span>
</code></pre><p>Now we can run our app, in VS Code, you just open the main java class with <em>@SpringBootApplication</em> annotation and clic <em>Run</em> above the public static void main instruction.</p>
<p>As result, you must have a similar console:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626136579602/hdemsDNEIy.png" alt="run1.PNG" /></p>
<p>Bravo, our backend is ready. Hope you've learnt something here, if yes please give a like to this tutorial and share it. In the next tutorial, we'll add entity classes and make REST call.</p>
]]></content:encoded></item><item><title><![CDATA[How to implement Amazon SNS email subscription on Gatsby website]]></title><description><![CDATA[I had difficulty implementing Amazon Simple Notification Service email subscription on one of my Gatsby websites. Yes you've read it well 😊,  Gatsby , a React-based framework that helps you quickly build and deploy super fast lightweight websites.  ...]]></description><link>https://blog.wilsonkomlan.com/how-to-implement-amazon-sns-email-subscription-on-gatsby-website</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/how-to-implement-amazon-sns-email-subscription-on-gatsby-website</guid><category><![CDATA[Amazon Web Services]]></category><category><![CDATA[Amazon]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Sat, 03 Oct 2020 15:01:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1601735087423/oPN0VQ66D.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I had difficulty implementing <a target="_blank" href="https://docs.aws.amazon.com/sns/latest/dg/welcome.html">Amazon Simple Notification Service</a> email subscription on one of my Gatsby websites. Yes you've read it well 😊,  <a target="_blank" href="https://www.gatsbyjs.com/">Gatsby</a> , a React-based framework that helps you quickly build and deploy super fast lightweight websites.  </p>
<p>In this post I will share, through a demo project, how you can easily implement this feature in your Gatsby website.</p>

<h2 id="prerequisites">Prerequisites</h2>
<ul>
<li>You need an <a target="_blank" href="https://aws.amazon.com/console/">AWS account</a></li>
</ul>
<h2 id="configure-amazon-sns">Configure Amazon SNS</h2>
<ul>
<li>Open <a target="_blank" href="https://aws.amazon.com/console/">AWS console and Sign In</a></li>
<li>In <strong>Services</strong> menu, choose <strong>Simple Notification Service</strong></li>
<li>On SNS page, choose <strong>Create Topic</strong> 
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601719352506/dnMCzGqCM.png" alt="image.png" /></li>
<li>Give a <strong>Name</strong> (here it's : <em>GatsbyNewsletterTopic</em>)</li>
<li>Give a <strong>Display name</strong> (here : <em>Gatsby Newsletter Topic</em>)</li>
<li>Leave optional configurations and hit Create topic</li>
<li>Note the ARN (here, <em>arn:aws:sns:us-east-1:...:GatsbyNewsletterTopic</em>)
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601720056252/DU9uH_yFj.png" alt="tempsniparn.png" /></li>
</ul>
<h2 id="create-a-aws-programmatic-user-for-aws-sdkhttpsawsamazoncomsdk-for-node-js">Create a AWS programmatic user for <a target="_blank" href="https://aws.amazon.com/sdk-for-node-js/">aws-sdk</a></h2>
<ul>
<li>In the same AWS console with the same signed In user for above sns topic, choose <strong>IAM</strong> in Services menu</li>
<li>Choose <strong>Users</strong> in the IAM Dashboard and clic on <strong>Add user</strong>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601721061237/Yo_K9CZ9C.png" alt="image.png" /></li>
<li>Give the user name (here : <em>SnsUser</em>)</li>
<li>Select : <strong>programmatic access</strong> and clic Next permission</li>
<li>In the <strong>Set permissions</strong> tab, select <strong>Attach existing policies directly</strong></li>
<li>In the Policies table, search for <strong>AmazonSNSFullAccess</strong> and check it</li>
<li>Then hit Next - Next - create.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601721798823/kMvUOMcX8.png" alt="snsuser.png" /></li>
<li>Copy or download the created user's cridentials (Access key ID and Secret Access key) for next steps.</li>
</ul>
<h2 id="setting-up-the-gatsby-website-project">Setting up the Gatsby website project</h2>
<p>Now that we've created the sns subscription endpoint and the according user on AWS, we are going to setup our project.</p>

<ul>
<li><p>Create a new project : <code>gatsby new my-gatsby-project https://github.com/gatsbyjs/gatsby-starter-default</code></p>
</li>
<li><p>In the root of the project, type <code>gatsby develop</code> to run</p>
</li>
<li><p>Open the browser and type : <code>http://localhost:8000</code></p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601726563356/PYXB9fk7G.png" alt="image.png" /></p>
<h2 id="create-subscription-component">Create Subscription component</h2>
<ul>
<li>In the component folder, create : subscribeform.js file</li>
<li>Install aws-sdk in the gatsby project
<code>npm install -save aws-sdk</code></li>
<li>Install <a target="_blank" href="https://formik.org/">Formik</a> and <a target="_blank" href="https://www.npmjs.com/package/yup">Yup</a> schema builder
<code>npm install formik yup</code></li>
<li>Copy and paste the below code snipet</li>
</ul>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { useFormik } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Yup <span class="hljs-keyword">from</span> <span class="hljs-string">"yup"</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SubscribeForm</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> formik = useFormik({
    <span class="hljs-attr">initialValues</span>: {
      <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    },
    <span class="hljs-attr">validationSchema</span>: Yup.object({
      <span class="hljs-attr">email</span>: Yup.string().email().required(),
    }),
    onSubmit(values, { resetForm }) {
      <span class="hljs-keyword">const</span> { email } = values    
    },
  })
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{formik.handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your email"</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{formik.handleChange}</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{formik.values.email}</span>
      /&gt;</span>
      {formik.errors.email ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorText"</span>&gt;</span>{formik.errors.email}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      ) : null}
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Subscribe"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  )
}
</code></pre><ul>
<li>Add <strong>subscribeform.js</strong> component in the index page, <strong>index.js</strong> must look like this :</li>
</ul>
<pre><code>
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">"gatsby"</span>

<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/layout"</span>
<span class="hljs-keyword">import</span> Image <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/image"</span>
<span class="hljs-keyword">import</span> SEO <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/seo"</span>
<span class="hljs-keyword">import</span> SubscribeForm <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/subscribeform"</span>

<span class="hljs-keyword">const</span> IndexPage = <span class="hljs-function">() =&gt;</span> (
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">SEO</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Home"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">h1</span>&gt;</span>Hi people<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Welcome to your new Gatsby site.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Now go build something great.<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">maxWidth:</span> `<span class="hljs-attr">300px</span>`, <span class="hljs-attr">marginBottom:</span> `<span class="hljs-attr">1.45rem</span>` }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Image</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">maxWidth:</span> `<span class="hljs-attr">300px</span>`, <span class="hljs-attr">marginBottom:</span> `<span class="hljs-attr">1.45rem</span>` }}&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">SubscribeForm</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/page-2/"</span>&gt;</span>Go to page 2<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name">br</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/using-typescript/"</span>&gt;</span>Go to "Using TypeScript"<span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span></span>
)

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> IndexPage
</code></pre><ul>
<li>Our webpage should have this look : note the email input and the subscribe button</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601727438048/DOOa_RI-k.png" alt="image.png" /></p>
<h1 id="add-subscription-method">Add subscription method</h1>
<p>So far, everything works well as expected, but if you clic on subscribe button, nothing happens 🤣, yes, because we haven't done anything so great, everbody who've gone through Gatsby tutorials could have done what we did! Let's add some codes to our <strong>subscribeform.js</strong>.</p>


<ul>
<li>Add a <strong>config.json</strong> file in the root for AWS cridentials, it should look like this:</li>
</ul>
<pre><code>
{ 
    <span class="hljs-attr">"accessKeyId"</span>: <span class="hljs-string">"secret"</span>, 
    <span class="hljs-attr">"secretAccessKey"</span>: <span class="hljs-string">"secret"</span>, 
    <span class="hljs-attr">"region"</span>: <span class="hljs-string">"secret"</span> 
}
</code></pre><p><strong>Nota bene</strong> : You must replace "<em>secret</em>" with the corresponding <strong>accessKeyId</strong> , <strong>secretAccessKey</strong> and <strong>region</strong> values you've got in the <strong>Create a AWS programmatic user for aws-sdk</strong> section.</p>
<p><strong>Warning</strong> : It is not a best practice to put app cridentials in a project, I'll have a post for how to do that, but for this subscription purpose, we'll not follow this best practice 🤦‍♂️. Let's move on!</p>

<ul>
<li>In the <strong>subscribeform.js</strong> ,  under the last import instruction, add the following lines:</li>
</ul>
<pre><code><span class="hljs-keyword">import</span> AWS <span class="hljs-keyword">from</span> <span class="hljs-string">"aws-sdk"</span>

<span class="hljs-keyword">const</span> AWSConf = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../../config.json'</span>);
AWS.config.update(AWSConf);
</code></pre><ul>
<li>In the onSubmit() method add the following instructions after const {email}=values line :</li>
</ul>
<pre><code><span class="hljs-keyword">var</span> params = {
        Protocol: <span class="hljs-string">"EMAIL"</span> <span class="hljs-comment">/* required */</span>,
        TopicArn: <span class="hljs-string">"yourArn"</span> <span class="hljs-comment">/* required */</span>,
        Endpoint: email,
      }

      <span class="hljs-keyword">var</span> subscribePromise = <span class="hljs-keyword">new</span> AWS.SNS({ apiVersion: <span class="hljs-string">"2010-03-31"</span> })
        .subscribe(params)
        .promise()

      subscribePromise
        .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
          resetForm() <span class="hljs-comment">//reset the form</span>
        })
        .<span class="hljs-keyword">catch</span>(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
          console.<span class="hljs-built_in">error</span>(err, err.stack)
        })
</code></pre><p><strong>Nota bene</strong> : In the TopicArn: "<strong>yourArn</strong>"  instruction, replace <em>yourArn</em> by the ARN generated through <strong>Configure Amazon SNS</strong> section.
Voilà! You've done the great thing 👍.</p>
<ul>
<li>The subscribeform.js code should look like this :</li>
</ul>
<pre><code><span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>
<span class="hljs-keyword">import</span> { useFormik } <span class="hljs-keyword">from</span> <span class="hljs-string">"formik"</span>
<span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> Yup <span class="hljs-keyword">from</span> <span class="hljs-string">"yup"</span>
<span class="hljs-keyword">import</span> AWS <span class="hljs-keyword">from</span> <span class="hljs-string">"aws-sdk"</span>

<span class="hljs-keyword">const</span> AWSConf = <span class="hljs-built_in">require</span>(<span class="hljs-string">'../../config.json'</span>);
AWS.config.update(AWSConf);

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">SubscribeForm</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">const</span> formik = useFormik({
    <span class="hljs-attr">initialValues</span>: {
      <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    },
    <span class="hljs-attr">validationSchema</span>: Yup.object({
      <span class="hljs-attr">email</span>: Yup.string().email().required(),
    }),

    onSubmit(values, { resetForm }) {
      <span class="hljs-keyword">const</span> { email } = values
      <span class="hljs-keyword">var</span> params = {
        <span class="hljs-attr">Protocol</span>: <span class="hljs-string">"EMAIL"</span> <span class="hljs-comment">/* required */</span>,
        <span class="hljs-attr">TopicArn</span>: <span class="hljs-string">"yourArn"</span> <span class="hljs-comment">/* required */</span>,
        <span class="hljs-attr">Endpoint</span>: email,
      }

      <span class="hljs-keyword">var</span> subscribePromise = <span class="hljs-keyword">new</span> AWS.SNS({ <span class="hljs-attr">apiVersion</span>: <span class="hljs-string">"2010-03-31"</span> })
        .subscribe(params)
        .promise()

      subscribePromise
        .then(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">data</span>) </span>{
          resetForm()  <span class="hljs-comment">//reset the form</span>
        })
        .catch(<span class="hljs-function"><span class="hljs-keyword">function</span> (<span class="hljs-params">err</span>) </span>{
          <span class="hljs-built_in">console</span>.error(err, err.stack)
        })

    },
  })

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">onSubmit</span>=<span class="hljs-string">{formik.handleSubmit}</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
        <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
        <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span>
        <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your email"</span>
        <span class="hljs-attr">onChange</span>=<span class="hljs-string">{formik.handleChange}</span>
        <span class="hljs-attr">value</span>=<span class="hljs-string">{formik.values.email}</span>
      /&gt;</span>
      {formik.errors.email ? (
        <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"errorText"</span>&gt;</span>{formik.errors.email}<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
      ) : null}
      <span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"Subscribe"</span> /&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span></span>
  )
}
</code></pre><ul>
<li>Refresh the browser and put a valid email address then submit. The input field will be automatically reset on success, and a Subscription Confirmation email will be sent to the provided email address. </li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1601734665745/e-fyZOYav.png" alt="emailconfirmation.png" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>Well done! You have implemented an Amazon SNS email newsletter subscription in your Gatsby website.</p>
<p>You can find the source code  <a target="_blank" href="https://github.com/wilkom2009/wil-sns-project.git">here</a> .</p>

]]></content:encoded></item><item><title><![CDATA[Why this blog?]]></title><description><![CDATA[Main purpose of this blog
There are many blogs and tutorials from experts covering the topics I will surely talk about, but why do I have to add my blog to that numerous list? 
In my little journey as software developer, I found that sometimes, devel...]]></description><link>https://blog.wilsonkomlan.com/why-this-blog</link><guid isPermaLink="true">https://blog.wilsonkomlan.com/why-this-blog</guid><category><![CDATA[Java]]></category><category><![CDATA[React]]></category><category><![CDATA[Gatsby]]></category><category><![CDATA[Spring]]></category><dc:creator><![CDATA[Wilson KOMLAN]]></dc:creator><pubDate>Fri, 02 Oct 2020 13:12:51 GMT</pubDate><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1626726406107/mFAqy--Bm.png" alt="web-1935737_1920.png" /></p>
<h1 id="main-purpose-of-this-blog">Main purpose of this blog</h1>
<p>There are many blogs and tutorials from experts covering the topics I will surely talk about, but why do I have to add my blog to that numerous list? </p>
<p>In my little journey as software developer, I found that sometimes, developers, espacially newcomers to a programming language world, need specific and understandable tips or code snipets to achieve great projects. Most of the times, experts' solutions are too complex for these newbies to implement. I am here to share some of these take-away, specific, simple yet proven solutions.</p>
<p>Come on! As a developer, I need to prove my skills, because blogging is becoming most developers' trend these days, so <em>qui va se négliger?</em> 😂
</p>

<h1 id="what-you-will-learn-from-my-posts">What you will learn from my posts</h1>
<ul>
<li>Java programing language and its compatible frameworks</li>
<li>React and its compatible libraries</li>
<li>Cloud AWS</li>
<li>GatsbyJs</li>
<li>Etc.</li>
</ul>
]]></content:encoded></item></channel></rss>