<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ViralPatel.net</title>
	<atom:link href="https://www.viralpatel.net/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.viralpatel.net</link>
	<description>Java, Spring, Web, API Tutorials, Tips and Tricks</description>
	<lastBuildDate>Fri, 12 Jun 2020 12:23:32 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.7.1</generator>

<image>
	<url>https://www.viralpatel.net/app/uploads/favicon-150x150.png</url>
	<title>ViralPatel.net</title>
	<link>https://www.viralpatel.net</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Java URL Encoder/Decoder Example</title>
		<link>https://www.viralpatel.net/java-url-encoder-decoder/</link>
					<comments>https://www.viralpatel.net/java-url-encoder-decoder/#respond</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Wed, 10 Jun 2020 12:42:57 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3865</guid>

					<description><![CDATA[Java URL Encoder/Decoder Example &#8211; In this tutorial we will see how to URL encode/decode attributes in Java. Overview URL encoding, is a mechanism for encoding information in a Uniform Resource Identifier (URI) under certain circumstances. When we&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<div class="wp-block-image"><figure class="aligncenter size-large"><img width="640" height="360" src="https://www.viralpatel.net/app/uploads/2020/06/java-url-encoder-decoder-640x360.jpg" alt="Java URL Encoder Decoder Example" class="wp-image-3866" srcset="https://www.viralpatel.net/app/uploads/2020/06/java-url-encoder-decoder-640x360.jpg 640w, https://www.viralpatel.net/app/uploads/2020/06/java-url-encoder-decoder-300x169.jpg 300w, https://www.viralpatel.net/app/uploads/2020/06/java-url-encoder-decoder-768x432.jpg 768w, https://www.viralpatel.net/app/uploads/2020/06/java-url-encoder-decoder.jpg 960w" sizes="(max-width: 640px) 100vw, 640px" /></figure></div>



<p><strong>Java URL Encoder/Decoder Example</strong> &#8211; In this tutorial we will see how to URL encode/decode attributes in Java.</p>



<h2>Overview</h2>



<p><strong>URL encoding</strong>, is a mechanism for encoding information in a Uniform Resource Identifier (URI) under certain circumstances. </p>



<p>When we submit an HTML form using GET or POST request, the data/fields in the form are encoded using application/x-www-form-urlencoded type. There is an optional attribute on <code>&lt;form></code> element called <code>enctype</code>. Its default value is <code>application/x-www-form-urlencoded</code>. This specification defines how the values are encoded (for e.g. replacing space with +) and decoded on server.</p>



<p>When HTML form data is sent in an HTTP GET request, it is included in the query component of the request URI. When sent in an HTTP POST request, the data is placed in the request body, and <code>application/x-www-form-urlencoded</code> is included in the message&#8217;s Content-Type header.</p>



<h2>Encode URL in Java</h2>



<p>To encode the query parameters or attributes, Java provides a utility class <code>URLEncoder</code> with a couple of <code>encode()</code> methods.</p>



<p>The <code>URLEncoder.encode()</code> method escapes all characters except:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-1" data-shcb-language-name="Shell Session" data-shcb-language-slug="shell"><div><code class="hljs language-shell"> A-Z a-z 0-9 - _ . ! ~ * ' ( )</code></div><small class="shcb-language" id="shcb-language-1"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Shell Session</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">shell</span><span class="shcb-language__paren">)</span></small></pre>

<pre class="wp-block-code" aria-describedby="shcb-language-2" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">import</span> java.io.UnsupportedEncodingException;
<span class="hljs-keyword">import</span> java.net.URLEncoder;
<span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;
<span class="hljs-comment">//..</span>

URLEncoder.encode(plainText, StandardCharsets.UTF_8.toString());</code></div><small class="shcb-language" id="shcb-language-2"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>In following example, we encode a few plain text strings using URLEncoder.encode.</p>



<p>URLEncoderTest.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-3" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel;

<span class="hljs-keyword">import</span> org.junit.Test;
<span class="hljs-keyword">import</span> org.slf4j.Logger;
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;

<span class="hljs-keyword">import</span> java.io.UnsupportedEncodingException;
<span class="hljs-keyword">import</span> java.net.URLEncoder;
<span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;

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

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger LOGGER = LoggerFactory.getLogger(URLEncoderTest<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>  <span class="hljs-keyword">void</span> <span class="hljs-title">encode</span><span class="hljs-params">(String plain)</span> <span class="hljs-keyword">throws</span> UnsupportedEncodingException </span>{

        String encoded = URLEncoder.encode(plain, StandardCharsets.UTF_8.toString());
        LOGGER.info(<span class="hljs-string">"Plain text: {}, Encoded text: {}"</span>, plain, encoded);
    }

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">encodeTests</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> UnsupportedEncodingException </span>{
        encode(<span class="hljs-string">"john+doe@example.com"</span>);
        encode(<span class="hljs-string">"sample text"</span>);
        encode(<span class="hljs-string">"+1653-124-23"</span>);
    }
}</code></div><small class="shcb-language" id="shcb-language-3"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Run the above test in your favourite IDE and check the output. The plain text is encoded using Java URL Encoder.</p>



<p>Output:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-4" data-shcb-language-name="Shell Session" data-shcb-language-slug="shell"><div><code class="hljs language-shell">Plain text: john+doe@example.com, Encoded text: john%2Bdoe%40example.com
Plain text: sample text, Encoded text: sample+text
Plain text: +1653-124-23, Encoded text: %2B1653-124-23</code></div><small class="shcb-language" id="shcb-language-4"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Shell Session</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">shell</span><span class="shcb-language__paren">)</span></small></pre>


<h2>Decode URL in Java</h2>



<p>Java also provides utility class URLDecoder to decode the value. Usually on server side when we receive the form attributes, using URLDecoder we can decode them to original values.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-5" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">import</span> java.io.UnsupportedEncodingException;
<span class="hljs-keyword">import</span> java.net.URLDecoder;
<span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;
<span class="hljs-comment">//..</span>

URLDecoder.decode(encodedText, StandardCharsets.UTF_8.toString());</code></div><small class="shcb-language" id="shcb-language-5"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>URLDecoderTest.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-6" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel;

<span class="hljs-keyword">import</span> org.junit.Test;
<span class="hljs-keyword">import</span> org.slf4j.Logger;
<span class="hljs-keyword">import</span> org.slf4j.LoggerFactory;

<span class="hljs-keyword">import</span> java.io.UnsupportedEncodingException;
<span class="hljs-keyword">import</span> java.net.URLDecoder;
<span class="hljs-keyword">import</span> java.nio.charset.StandardCharsets;

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

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger LOGGER = LoggerFactory.getLogger(URLEncoderTest<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span>  <span class="hljs-keyword">void</span> <span class="hljs-title">decode</span><span class="hljs-params">(String encoded)</span> <span class="hljs-keyword">throws</span> UnsupportedEncodingException </span>{

        String plain = URLDecoder.decode(encoded, StandardCharsets.UTF_8.toString());
        LOGGER.info(<span class="hljs-string">"Encoded text: {}, Plain text: {}"</span>, encoded, plain);
    }

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">decodeTests</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> UnsupportedEncodingException </span>{
        decode(<span class="hljs-string">"john%2Bdoe%40example.com"</span>);
        decode(<span class="hljs-string">"sample+text"</span>);
        decode(<span class="hljs-string">"%2B1653-124-23"</span>);
    }
}</code></div><small class="shcb-language" id="shcb-language-6"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Run the above test in your favourite IDE and check the output. The encoded text is decoded using Java URL Decoder.</p>



<p>Output:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-7" data-shcb-language-name="Shell Session" data-shcb-language-slug="shell"><div><code class="hljs language-shell">Encoded text: john%2Bdoe%40example.com, Plain text: john+doe@example.com
Encoded text: sample+text, Plain text: sample text
Encoded text: %2B1653-124-23, Plain text: +1653-124-23</code></div><small class="shcb-language" id="shcb-language-7"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Shell Session</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">shell</span><span class="shcb-language__paren">)</span></small></pre>


<h2>Conclusion</h2>



<p>Java provides utility classes URLEncoder and URLDecoder to encode/decode text using URLencoding to transfer data on http. In this tutorial we saw how to use Java URL encoder and decoder.</p>



<p>Download or browse the code on Github.</p>



<p>Github &#8211; <a href="https://github.com/viralpatel/java-url-encode-decode" target="_blank" rel="noreferrer noopener">source code</a></p>



<h2>Reference</h2>



<ul><li><a rel="noreferrer noopener" href="https://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.1" target="_blank">Form encoding in HTML</a></li></ul>



<p>Further Read: <a href="https://www.viralpatel.net/lambda-expressions-java-tutorial/">Getting Started with Java 8 Lambda Expression</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/java-url-encoder-decoder/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Show Multiple Examples in OpenAPI Spec</title>
		<link>https://www.viralpatel.net/openapi-multiple-examples/</link>
					<comments>https://www.viralpatel.net/openapi-multiple-examples/#respond</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Fri, 05 Jun 2020 08:28:19 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[OpenAPI]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3850</guid>

					<description><![CDATA[Show Multiple Examples in OpenAPI &#8211; OpenAPI (aka Swagger) Specifications has become a defecto standard for documenting and sharing REST API. When using OpenAPI it is always best practice to add as much detail&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<p><strong>Show Multiple Examples in OpenAPI</strong> &#8211; OpenAPI (aka Swagger) Specifications has become a defecto standard for documenting and sharing REST API. When using OpenAPI it is always best practice to add as much detail as we can. The API specification should be built from the API consumers perspective. The DX or developer experience is important when developing the API.</p>



<p>To improve the API experience we must define attributes with descriptions and example. It is also possible to define multiple examples to show different way the API can be consumed / requested. </p>



<p>First, let us see how swagger editor (editor.swagger.io) shows multiple examples. The examples are shown in a dropdown where user can choose and see appropriate request payload. <code>sample1</code> and <code>sample2</code> are two examples for Pet store API.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img width="640" height="366" src="https://www.viralpatel.net/app/uploads/2020/06/openapi-multiple-examples-640x366.png" alt="openapi multiple examples" class="wp-image-3852" srcset="https://www.viralpatel.net/app/uploads/2020/06/openapi-multiple-examples-640x366.png 640w, https://www.viralpatel.net/app/uploads/2020/06/openapi-multiple-examples-300x172.png 300w, https://www.viralpatel.net/app/uploads/2020/06/openapi-multiple-examples-768x440.png 768w, https://www.viralpatel.net/app/uploads/2020/06/openapi-multiple-examples.png 917w" sizes="(max-width: 640px) 100vw, 640px" /></figure></div>



<p></p>



<h2>Adding Multiple Examples in OpenAPI</h2>



<p>To add multiple examples in OpenAPI, we can define <code>examples</code> attribute as shown below. Notice how we defined <code>sample1</code> and <code>sample2</code>. You can give any meaningful name relevant to your API.</p>



<p>openapi.yaml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-8" data-shcb-language-name="YAML" data-shcb-language-slug="yaml"><div><code class="hljs language-yaml"><span class="hljs-attr">paths:</span>
  <span class="hljs-string">/pets:</span>    
    <span class="hljs-attr">post:</span>
      <span class="hljs-attr">description:</span> <span class="hljs-string">Creates</span> <span class="hljs-string">a</span> <span class="hljs-string">new</span> <span class="hljs-string">pet</span> <span class="hljs-string">in</span> <span class="hljs-string">the</span> <span class="hljs-string">store.</span> <span class="hljs-string">Duplicates</span> <span class="hljs-string">are</span> <span class="hljs-string">allowed</span>
      <span class="hljs-attr">operationId:</span> <span class="hljs-string">addPet</span>
      <span class="hljs-attr">requestBody:</span>
        <span class="hljs-attr">description:</span> <span class="hljs-string">Pet</span> <span class="hljs-string">to</span> <span class="hljs-string">add</span> <span class="hljs-string">to</span> <span class="hljs-string">the</span> <span class="hljs-string">store</span>
        <span class="hljs-attr">required:</span> <span class="hljs-literal">true</span>
        <span class="hljs-attr">content:</span>
          <span class="hljs-attr">application/json:</span>
            <span class="hljs-attr">schema:</span>
              <span class="hljs-string">$ref:</span> <span class="hljs-string">'#/components/schemas/NewPet'</span>
            <span class="hljs-attr">examples:</span>
              <span class="hljs-attr">sample1:</span>
                <span class="hljs-attr">value:</span>
                  <span class="hljs-attr">name:</span> <span class="hljs-string">Cupcake</span>
                  <span class="hljs-attr">tag:</span> <span class="hljs-string">Chihuahua</span>
              <span class="hljs-attr">sample2:</span>
                <span class="hljs-attr">value:</span>
                  <span class="hljs-attr">name:</span> <span class="hljs-string">Prince</span>
                  <span class="hljs-attr">tag:</span> <span class="hljs-string">Poodle</span></code></div><small class="shcb-language" id="shcb-language-8"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">YAML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">yaml</span><span class="shcb-language__paren">)</span></small></pre>


<p></p>



<p>In OpenAPI, we can also provide example at attribute level. While it is good to define an attribute example (e.g. petType) so the consumer of API know what to pass or what to expect from attribute. However it is also a good idea to provide example at broader request/response level. </p>



<p>The request/response level example would provide much broader context to API consumer and also helps documenting API better. Furthermore many mock tools can generate mock responses from the examples provided in Swagger file.</p>



<h3>Multiple Examples in API Response</h3>



<p>The multiple example works with both API Request and Response. Similar to what we did above, the same can be specified for API Response. In below screenshot we can see how swagger editor shows multiple response example.</p>



<figure class="wp-block-image size-large"><img width="640" height="345" src="https://www.viralpatel.net/app/uploads/2020/06/multiple-examples-response-openapi-640x345.png" alt="multiple examples in api response" class="wp-image-3853" srcset="https://www.viralpatel.net/app/uploads/2020/06/multiple-examples-response-openapi-640x345.png 640w, https://www.viralpatel.net/app/uploads/2020/06/multiple-examples-response-openapi-300x162.png 300w, https://www.viralpatel.net/app/uploads/2020/06/multiple-examples-response-openapi-768x414.png 768w, https://www.viralpatel.net/app/uploads/2020/06/multiple-examples-response-openapi.png 882w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>openapi.yaml with examples in response</p>


<pre class="wp-block-code" aria-describedby="shcb-language-9" data-shcb-language-name="PHP" data-shcb-language-slug="php"><div><code class="hljs language-php">paths:
  /pets:
    get:
      description: Returns all pets
      operationId: findPets
      parameters:
        - name: tags
          in: query
          description: tags to filter by
          required: <span class="hljs-keyword">false</span>
          style: form
          schema:
            type: <span class="hljs-keyword">array</span>
            items:
              type: string
        - name: limit
          in: query
          description: maximum number of results to <span class="hljs-keyword">return</span>
          required: <span class="hljs-keyword">false</span>
          schema:
            type: integer
            format: int32
      responses:
        <span class="hljs-string">'200'</span>:
          description: pet response
          content:
            application/json:
              schema:
                type: <span class="hljs-keyword">array</span>
                items:
                  $ref: <span class="hljs-string">'#/components/schemas/Pet'</span>
              examples:
                sample1:
                  value:
                    name: Cupcake
                    tag: Chihuahua
                sample2:
                  value:
                    name: Prince
                    tag: Poodle
        <span class="hljs-keyword">default</span>:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: <span class="hljs-string">'#/components/schemas/Error'</span></code></div><small class="shcb-language" id="shcb-language-9"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">PHP</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">php</span><span class="shcb-language__paren">)</span></small></pre>


<p>Hope this little trick will make your API documentation awesome :-)</p>



<h2>Reference</h2>



<p><a href="https://swagger.io/docs/specification/adding-examples/">https://swagger.io/docs/specification/adding-examples/</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/openapi-multiple-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Run Local WordPress using Docker</title>
		<link>https://www.viralpatel.net/local-wordpress-docker/</link>
					<comments>https://www.viralpatel.net/local-wordpress-docker/#comments</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Mon, 01 Jun 2020 09:27:41 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Dockerfile]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wordpress tips]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3816</guid>

					<description><![CDATA[Local WordPress using Docker &#8211; Running a local WordPress development environment is crucial for testing themes and plugin before we push into staging or production environment. To run WordPress locally, we need to install&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><img width="820" height="312" src="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-container.jpg" alt="Local WordPress setup using Docker container" class="wp-image-3826" srcset="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-container.jpg 820w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-container-300x114.jpg 300w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-container-640x244.jpg 640w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-container-768x292.jpg 768w" sizes="(max-width: 820px) 100vw, 820px" /></figure>



<p><strong>Local WordPress using Docker</strong> &#8211; Running a local WordPress development environment is crucial for testing themes and plugin before we push into staging or production environment. To run WordPress locally, we need to install and setup PHP, MySQL (or MariaDB) and WordPress which is not straightforward. </p>



<p>Docker provides an ideal way of setting up local WordPress development setup (for Windows you might prefer <a rel="noreferrer noopener" href="https://www.viralpatel.net/tag/wamp/" target="_blank">WAMP</a>). Using simple docker commands we can quickly spin up a new environment where we can test WordPress themes and plugins.  Assuming you already have setup Docker in your machine, starting WordPress is quite rapid.</p>



<p>Since we are running WordPress in Docker, the same setup will work in Window, Mac and Linux.</p>



<h2>Local WordPress Setup with Docker</h2>



<p>Let us see how to run local WordPress setup for development using Docker.</p>



<p>Setup Docker Compose for WordPress. Start up a command line terminal and create <code>wp-local</code> folder.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-10" data-shcb-language-name="Shell Session" data-shcb-language-slug="shell"><div><code class="hljs language-shell"><span class="hljs-meta">$</span><span class="bash"> mkdir wp-local &amp;&amp; <span class="hljs-built_in">cd</span> wp-local </span>
<span class="hljs-meta">$</span><span class="bash"> touch docker-compose.yml</span></code></div><small class="shcb-language" id="shcb-language-10"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Shell Session</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">shell</span><span class="shcb-language__paren">)</span></small></pre>


<figure class="wp-block-image size-large"><img width="640" height="367" src="https://www.viralpatel.net/app/uploads/2020/06/wordpress-docker-compose-yml-640x367.png" alt="create docker-compose.yml for wordpress" class="wp-image-3817" srcset="https://www.viralpatel.net/app/uploads/2020/06/wordpress-docker-compose-yml-640x367.png 640w, https://www.viralpatel.net/app/uploads/2020/06/wordpress-docker-compose-yml-300x172.png 300w, https://www.viralpatel.net/app/uploads/2020/06/wordpress-docker-compose-yml.png 742w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>To setup WordPress + MySQL + phpMyAdmin images in the docker-compose, copy following content into it.</p>



<p>docker-compose.yml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-11" data-shcb-language-name="YAML" data-shcb-language-slug="yaml"><div><code class="hljs language-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">"3"</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-attr">db:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">mysql:5.7</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">db_data:/var/lib/mysql</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">password</span>
      <span class="hljs-attr">MYSQL_DATABASE:</span> <span class="hljs-string">wordpress</span>
      <span class="hljs-attr">MYSQL_USER:</span> <span class="hljs-string">wordpress</span>
      <span class="hljs-attr">MYSQL_PASSWORD:</span> <span class="hljs-string">wordpress</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">wp</span>

  <span class="hljs-attr">wordpress:</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">db</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">wordpress</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./:/var/www/html/wp-content</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">WORDPRESS_DB_HOST:</span> <span class="hljs-string">db:3306</span>
      <span class="hljs-attr">WORDPRESS_DB_USER:</span> <span class="hljs-string">wordpress</span>
      <span class="hljs-attr">WORDPRESS_DB_PASSWORD:</span> <span class="hljs-string">wordpress</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">80</span><span class="hljs-string">:80</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">443</span><span class="hljs-string">:443</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">wp</span>

  <span class="hljs-attr">phpmyadmin:</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">db</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">phpmyadmin/phpmyadmin</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">8080</span><span class="hljs-string">:80</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">PMA_HOST:</span> <span class="hljs-string">db</span>
      <span class="hljs-attr">MYSQL_ROOT_PASSWORD:</span> <span class="hljs-string">password</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">wp</span>

<span class="hljs-attr">networks:</span>
  <span class="hljs-attr">wp:</span>

<span class="hljs-attr">volumes:</span>
  <span class="hljs-attr">db_data:</span></code></div><small class="shcb-language" id="shcb-language-11"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">YAML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">yaml</span><span class="shcb-language__paren">)</span></small></pre>


<p>In above docker-compose.yml file we are creating 3 containers; mysql, wordpress and phpmyadmin. The wordpress container exposing the wordpress at port 80. Similarly phpmyadmin is exposed at port 8080. Both wordpress and phpmyadmin depends on the db container which runs MySQL image.</p>



<h3>Docker Compose UP</h3>



<p>Save the docker-compose.yml file and run docker-compose up command to create and start the docker containers with WordPress, MySQL and phpMyAdmin.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-12" data-shcb-language-name="Shell Session" data-shcb-language-slug="shell"><div><code class="hljs language-shell"><span class="hljs-meta">$</span><span class="bash"> docker-compose up -d</span></code></div><small class="shcb-language" id="shcb-language-12"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Shell Session</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">shell</span><span class="shcb-language__paren">)</span></small></pre>


<p>When running first time, Docker will build up the stack and download all the images. Hence it might take a while. However subsequent invocation is going to be instant.</p>



<figure class="wp-block-image size-large"><img width="640" height="375" src="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-up-install-640x375.png" alt="wordpress docker-compose up" class="wp-image-3824" srcset="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-up-install-640x375.png 640w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-up-install-300x176.png 300w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-up-install-768x450.png 768w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-up-install.png 1102w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>Setup WordPress</h3>



<p>Once the docker-compose is completed, open up the browser and goto http://localhost  </p>



<figure class="wp-block-image size-large"><img width="640" height="546" src="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-started-640x546.png" alt="local wordpress docker installation" class="wp-image-3819" srcset="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-started-640x546.png 640w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-started-300x256.png 300w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-started-768x655.png 768w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-started.png 962w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>We can start the local wordpress setup. Enter Site Title, Username and Password and press Install WordPress.</p>



<figure class="wp-block-image size-large"><img width="640" height="626" src="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-step-640x626.png" alt="local wordpress docker installation steps" class="wp-image-3820" srcset="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-step-640x626.png 640w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-step-300x293.png 300w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-step-768x751.png 768w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-installation-step.png 962w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>Once WordPress setup is completed, login using the username/password provided in previous step and you will be greeted with WordPress Dashboard.</p>



<figure class="wp-block-image size-large"><img width="640" height="517" src="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-dashboard-640x517.png" alt="wordpress docker dashboard" class="wp-image-3818" srcset="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-dashboard-640x517.png 640w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-dashboard-300x242.png 300w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-dashboard-768x620.png 768w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-compose-dashboard.png 1166w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>phpMyAdmin Setup</h3>



<p>Since we also setup phpMyAdmin in our Docker compose file, login to phpMyAdmin to view/update WordPress database.</p>



<p>The username/password for phpMyAdmin is the value of WORDPRESS_DB_USER and WORDPRESS_DB_PASSWORD environment used in Docker compose file.</p>



<p>Username: wordpress<br>Password: wordpress</p>



<figure class="wp-block-image size-large"><img width="640" height="517" src="https://www.viralpatel.net/app/uploads/2020/06/phpmyadmin-docker-wordpress-1-640x517.png" alt="phpmyadmin docker login page" class="wp-image-3822" srcset="https://www.viralpatel.net/app/uploads/2020/06/phpmyadmin-docker-wordpress-1-640x517.png 640w, https://www.viralpatel.net/app/uploads/2020/06/phpmyadmin-docker-wordpress-1-300x242.png 300w, https://www.viralpatel.net/app/uploads/2020/06/phpmyadmin-docker-wordpress-1-768x620.png 768w, https://www.viralpatel.net/app/uploads/2020/06/phpmyadmin-docker-wordpress-1.png 1166w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h2>Bonus: Increase File Upload Size in Local WordPress Docker</h2>



<p>If you are trying to import settings from existing WordPress site once you start your local WordPress docker container, you will realise the default max upload size is 2mb.</p>



<p>To increase the upload file size, we can specify custom php.ini file (in our case upload.ini) and setup the Docker compose file to copy it within container.</p>



<p>Create file <code>upload.ini</code> in the same folder as docker-compose.yml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-13" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash">$ touch upload.ini</code></div><small class="shcb-language" id="shcb-language-13"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>Add following in upload.ini to change the upload_max_filesize.</p>



<p>upload.ini</p>


<pre class="wp-block-code"><div><code class="hljs">file_uploads = On
memory_limit = 64M
upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 600</code></div></pre>


<p>Update the <code>docker-compose.yml</code> file and mount the local <code>upload.ini</code> file.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-14" data-shcb-language-name="YAML" data-shcb-language-slug="yaml"><div><code class="hljs language-yaml">  <span class="hljs-attr">wordpress:</span>
    <span class="hljs-attr">depends_on:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">db</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">wordpress</span>
    <span class="hljs-attr">restart:</span> <span class="hljs-string">always</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./:/var/www/html/wp-content</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./upload.ini:/usr/local/etc/php/conf.d/uploads.ini</span>
    <span class="hljs-attr">environment:</span>
      <span class="hljs-attr">WORDPRESS_DB_HOST:</span> <span class="hljs-string">db:3306</span>
      <span class="hljs-attr">WORDPRESS_DB_USER:</span> <span class="hljs-string">wordpress</span>
      <span class="hljs-attr">WORDPRESS_DB_PASSWORD:</span> <span class="hljs-string">wordpress</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">80</span><span class="hljs-string">:80</span>
      <span class="hljs-bullet">-</span> <span class="hljs-number">443</span><span class="hljs-string">:443</span>
    <span class="hljs-attr">networks:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">wp</span></code></div><small class="shcb-language" id="shcb-language-14"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">YAML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">yaml</span><span class="shcb-language__paren">)</span></small></pre>


<p>Restart the docker container by running <code>docker-compose up -d</code></p>



<p>Check the max image size under <strong>Media &gt; Add New</strong></p>



<figure class="wp-block-image size-large"><img width="640" height="322" src="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-increase-upload-size-640x322.png" alt="wordpress max file upload size docker image" class="wp-image-3825" srcset="https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-increase-upload-size-640x322.png 640w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-increase-upload-size-300x151.png 300w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-increase-upload-size-768x387.png 768w, https://www.viralpatel.net/app/uploads/2020/06/local-wordpress-docker-increase-upload-size.png 1040w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h2>Source Code</h2>



<p>The docker-compose.yml is available in Github for further update.</p>



<p>Github &#8211; <a href="https://github.com/viralpatel/wp-docker" target="_blank" rel="noreferrer noopener">source code</a></p>



<p>Happy WordPressing :-)</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/local-wordpress-docker/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Create and Validate JWT Token in Java using JJWT</title>
		<link>https://www.viralpatel.net/java-create-validate-jwt-token/</link>
					<comments>https://www.viralpatel.net/java-create-validate-jwt-token/#comments</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Sat, 30 May 2020 02:46:26 +0000</pubDate>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[json]]></category>
		<category><![CDATA[JWT Token]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3797</guid>

					<description><![CDATA[1. JWT Token Overview JSON Web Token (JWT) is an open standard defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2020/05/create-validate-jwt-token-java-jjwt.jpg" alt="Create and Validate JWT Token using JJWT"/></figure>



<h2>1. JWT Token Overview</h2>



<p>JSON Web Token (JWT) is an open standard defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.</p>



<p>Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens signs using public/private key pairs, the signature also certifies that only the party holding the private key is the one signed it.</p>



<h3>1.1 What is JSON Web Token (JWT) Structure?</h3>



<p>JWT tokens consist of 3 parts separated by a period ( . ).<br>These parts are:</p>



<ol><li>Header</li><li>Payload</li><li>Signature</li></ol>



<p>The JWT typically looks like:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-15" data-shcb-language-name="CSS" data-shcb-language-slug="css"><div><code class="hljs language-css"><span class="hljs-selector-tag">aaaa</span><span class="hljs-selector-class">.bbbb</span><span class="hljs-selector-class">.cccc</span></code></div><small class="shcb-language" id="shcb-language-15"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">CSS</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">css</span><span class="shcb-language__paren">)</span></small></pre>


<h2>2. Setting up JJWT library</h2>



<p>To start using JJWT library for JWT generation, add following dependencies in your build.gradle file.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-16" data-shcb-language-name="Gradle" data-shcb-language-slug="gradle"><div><code class="hljs language-gradle"><span class="hljs-keyword">compile</span> <span class="hljs-string">'io.jsonwebtoken:jjwt-api:0.11.1'</span>
<span class="hljs-keyword">runtime</span> <span class="hljs-string">'io.jsonwebtoken:jjwt-impl:0.11.1'</span>
<span class="hljs-keyword">runtime</span> <span class="hljs-string">'io.jsonwebtoken:jjwt-jackson:0.11.1'</span></code></div><small class="shcb-language" id="shcb-language-16"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Gradle</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">gradle</span><span class="shcb-language__paren">)</span></small></pre>


<p>Alternatively if using Maven, add following dependencies in pom.xml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-17" data-shcb-language-name="HTML, XML" data-shcb-language-slug="xml"><div><code class="hljs language-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>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-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>0.11.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-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-impl<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.11.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</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-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-jackson<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.11.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</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></code></div><small class="shcb-language" id="shcb-language-17"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">HTML, XML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">xml</span><span class="shcb-language__paren">)</span></small></pre>


<h2>3. Create JWT Token</h2>



<p><code>Jwts.builder()</code> is used to create a JWT token. We can specify claims, subject and other JWT attribute.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-18" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">import</span> io.jsonwebtoken.Jwts;

<span class="hljs-keyword">import</span> java.time.Instant;
<span class="hljs-keyword">import</span> java.time.temporal.ChronoUnit;
<span class="hljs-keyword">import</span> java.util.Date;
<span class="hljs-keyword">import</span> java.util.UUID;

<span class="hljs-comment">//...</span>

String jwtToken = Jwts.builder()
        .claim(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Jane Doe"</span>)
        .claim(<span class="hljs-string">"email"</span>, <span class="hljs-string">"jane@example.com"</span>)
        .setSubject(<span class="hljs-string">"jane"</span>)
        .setId(UUID.randomUUID().toString())
        .setIssuedAt(Date.from(now))
        .setExpiration(Date.from(now.plus(<span class="hljs-number">5l</span>, ChronoUnit.MINUTES)))
        .compact();</code></div><small class="shcb-language" id="shcb-language-18"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Generated JWT Token:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-19" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash shcb-wrap-lines">eyJhbGciOiJub25lIn0.eyJuYW1lIjoiSmFuZSBEb2UiLCJlbWFpbCI6ImphbmVAZXhhbXBsZS5jb20iLCJzdWIiOiJqYW5lIiwianRpIjoiNDVmNGRiNTEtYTRlYy00YjYzLWJhMDgtNTE3MDJjYTI1MmEzIiwiaWF0IjoxNTkwNTc3NTY0LCJleHAiOjE1OTA1Nzc4NjR9.</code></div><small class="shcb-language" id="shcb-language-19"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>The above code to generate JWT is pretty self-explanatory however let&#8217;s check step by step how are we generating JWT token:</p>



<ol><li>Add claims <code>name</code> and <code>email</code> with value <code>Jane Doe</code> and <code>jane@example.com</code> respectively</li><li>Add subject in JWT token with value <code>jane</code></li><li>Set Id for the JWT token using randomly generate GUID</li><li>Set issued at to current time</li><li>Set expiration to current time plus 5 minutes. So the JWT is valid for only 5 minutes</li></ol>



<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2020/05/jwt-io-jwt-header-payload.png" alt="JWT.io Parse JWT Header and Payload"/></figure>



<p>The JWT generated above is not signed (Check algorithm <code>alg</code> attribute in the header). We have just encoded the claims in JSON format. If using JWT for authentication or authorization it is advisable to Sign the JWT, so it can be verified.</p>



<h2>4. Validate/Parse JWT Token</h2>



<p>To validate or parse the JWT token, <code>Jwts.parserBuilder()</code> method is used.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-20" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">import</span> io.jsonwebtoken.Jwts;
<span class="hljs-keyword">import</span> io.jsonwebtoken.Jws;
<span class="hljs-keyword">import</span> io.jsonwebtoken.Claims;
<span class="hljs-comment">//...</span>

Jws&lt;Claims&gt; jwt = Jwts.parserBuilder()
      .setSigningKey(...)
      .build()
      .parseClaimsJws(jwt);</code></div><small class="shcb-language" id="shcb-language-20"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>While parsing the JWT token we need to pass Signing key to verify the JWT signature. Let us see how to sign the JWT token using different algorithms.</p>



<h2>5. Create and Validate JWT Token Signed using HMAC Secret</h2>



<p>The simplest way of creating a signed JWT token is by using HMAC secret. HMAC stands for hash-based message authentication code and is cryptographic hash function. It is used to simultaneously verify both the data integrity and the authenticity of a token.</p>



<h3>5.1 Create JWT Token signed with HMAC</h3>



<p>To create JWT token signed with HMAC shared secret, we need to specify signature using .signWith() method. </p>


<pre class="wp-block-code" aria-describedby="shcb-language-21" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">import</span> io.jsonwebtoken.SignatureAlgorithm;
<span class="hljs-keyword">import</span> javax.crypto.spec.SecretKeySpec;
<span class="hljs-keyword">import</span> java.security.Key;
<span class="hljs-keyword">import</span> java.util.Base64;
<span class="hljs-comment">//...</span>

<span class="hljs-comment">// Key is hardcoded here for simplicity. </span>
<span class="hljs-comment">// Ideally this will get loaded from env configuration/secret vault</span>
String secret = <span class="hljs-string">"asdfSFS34wfsdfsdfSDSD32dfsddDDerQSNCK34SOWEK5354fdgdf4"</span>;

Key hmacKey = <span class="hljs-keyword">new</span> SecretKeySpec(Base64.getDecoder().decode(secret), 
                            SignatureAlgorithm.HS256.getJcaName());

Instant now = Instant.now();
String jwtToken = Jwts.builder()
        .claim(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Jane Doe"</span>)
        .claim(<span class="hljs-string">"email"</span>, <span class="hljs-string">"jane@example.com"</span>)
        .setSubject(<span class="hljs-string">"jane"</span>)
        .setId(UUID.randomUUID().toString())
        .setIssuedAt(Date.from(now))
        .setExpiration(Date.from(now.plus(<span class="hljs-number">5l</span>, ChronoUnit.MINUTES)))
        .signWith(hmacKey)
        .compact();</code></div><small class="shcb-language" id="shcb-language-21"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Generated JWT Token:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-22" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash shcb-wrap-lines">eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiSmFuZSBEb2UiLCJlbWFpbCI6ImphbmVAZXhhbXBsZS5jb20iLCJzdWIiOiJqYW5lIiwianRpIjoiYjMwMmU5NmUtODg2OS00NTJkLTg1ZjMtZGZjNDQzNTY3ZGUwIiwiaWF0IjoxNTkwNjE4NjI2LCJleHAiOjE1OTA2MTg5MjZ9.LJaar-3rnb3iuRXJBYK024l1PtEu3ay5ds24Q0bkf7w</code></div><small class="shcb-language" id="shcb-language-22"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<h3>5.2 Validate/Parse JWT Token signed with HMAC</h3>



<p>To validate/parse the JWT token generated using HMAC shared secret, the same steps can be applied. We need to use <code>setSigningKey()</code> method to set the key before we parse the JWT token.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-23" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Jws&lt;Claims&gt; <span class="hljs-title">parseJwt</span><span class="hljs-params">(String jwtString)</span> </span>{
    String secret = <span class="hljs-string">"asdfSFS34wfsdfsdfSDSD32dfsddDDerQSNCK34SOWEK5354fdgdf4"</span>;
    Key hmacKey = <span class="hljs-keyword">new</span> SecretKeySpec(Base64.getDecoder().decode(secret), 
                                    SignatureAlgorithm.HS256.getJcaName());

    Jws&lt;Claims&gt; jwt = Jwts.parserBuilder()
            .setSigningKey(hmacKey)
            .build()
            .parseClaimsJws(jwtString);

    <span class="hljs-keyword">return</span> jwt;
}</code></div><small class="shcb-language" id="shcb-language-23"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Output:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-24" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json shcb-wrap-lines">{name=Jane Doe, email=jane@example.com, sub=jane, jti=21da0729-577a-4d76-9c09-0ee11dcc2fdb, iat=1590619729, exp=1590620029}</code></div><small class="shcb-language" id="shcb-language-24"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<p>If the JWT token expires (<code>exp</code> claim value is less than current system time), the parseClaimsJws() method will throw <code>SignatureException</code>.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-25" data-shcb-language-name="Shell Session" data-shcb-language-slug="shell"><div><code class="hljs language-shell shcb-wrap-lines">Exception in thread "main" io.jsonwebtoken.security.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.
    at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:411)
    at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:541)
    at io.jsonwebtoken.impl.DefaultJwtParser.parseClaimsJws(DefaultJwtParser.java:601)
    at io.jsonwebtoken.impl.ImmutableJwtParser.parseClaimsJws(ImmutableJwtParser.java:173)
    at net.viralpatel.jwt.JWTGenerator.parseJwt(JWTGenerator.java:32)
    at net.viralpatel.jwt.JWTGenerator.main(JWTGenerator.java:20)</code></div><small class="shcb-language" id="shcb-language-25"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Shell Session</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">shell</span><span class="shcb-language__paren">)</span></small></pre>


<h2>6. Create and Validate JWT Token Signed using RSA Private Key</h2>



<p>When using JWT token for microservice authentication/authorization it is advisable to sign with RSA Private/Public Keys instead of using Shared HMAC Secret. The token is generated and signed by a central authority (usually an Authorization Server) and each microservice can validate the JWT token using the Public Key exposed from Authorization Server.</p>



<p>Before we see how to generate JWT token with Private/Public key, let us see how to generate a Private and Public RSA Key pairs.</p>



<h3>6.1 Generate Private and Public RSA Key</h3>



<p>Generate an RSA private key, of size 2048, and output it to a file named key.pem:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-26" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash">$ openssl genrsa -out key.pem 2048
Generating RSA private key, 2048 bit long modulus
..........+++
..........................................................................+++
e is 65537 (0x10001)</code></div><small class="shcb-language" id="shcb-language-26"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>Extract the public key from the key pair, which can be used in a certificate:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-27" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash">$ openssl rsa -<span class="hljs-keyword">in</span> key.pem -outform PEM -pubout -out public.pem
writing RSA key</code></div><small class="shcb-language" id="shcb-language-27"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>The <code>key.pem</code> file contains the private key generated using RSA and <code>public.pem</code> file contains public key.</p>



<h3>6.2 Create JWT Token signed with RSA</h3>



<p>Following code snippets shows how to generate JWT Token Signed using RSA.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-28" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java shcb-wrap-lines"><span class="hljs-keyword">import</span> io.jsonwebtoken.Jwts;
<span class="hljs-keyword">import</span> java.security.KeyFactory;
<span class="hljs-keyword">import</span> java.security.NoSuchAlgorithmException;
<span class="hljs-keyword">import</span> java.security.PrivateKey;
<span class="hljs-keyword">import</span> java.security.spec.InvalidKeySpecException;
<span class="hljs-keyword">import</span> java.security.spec.PKCS8EncodedKeySpec;
<span class="hljs-keyword">import</span> java.time.Instant;
<span class="hljs-keyword">import</span> java.time.temporal.ChronoUnit;
<span class="hljs-keyword">import</span> java.util.Base64;
<span class="hljs-keyword">import</span> java.util.Date;
<span class="hljs-keyword">import</span> java.util.UUID;
<span class="hljs-comment">// ...</span>

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">createJwtSignedHMAC</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> InvalidKeySpecException, NoSuchAlgorithmException </span>{

    PrivateKey privateKey = getPrivateKey();

    Instant now = Instant.now();
    String jwtToken = Jwts.builder()
            .claim(<span class="hljs-string">"name"</span>, <span class="hljs-string">"Jane Doe"</span>)
            .claim(<span class="hljs-string">"email"</span>, <span class="hljs-string">"jane@example.com"</span>)
            .setSubject(<span class="hljs-string">"jane"</span>)
            .setId(UUID.randomUUID().toString())
            .setIssuedAt(Date.from(now))
            .setExpiration(Date.from(now.plus(<span class="hljs-number">5l</span>, ChronoUnit.MINUTES)))
            .signWith(privateKey)
            .compact();

    <span class="hljs-keyword">return</span> jwtToken;
}

<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> PrivateKey <span class="hljs-title">getPrivateKey</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> NoSuchAlgorithmException, InvalidKeySpecException </span>{
    String rsaPrivateKey = <span class="hljs-string">"-----BEGIN PRIVATE KEY-----"</span> +
            <span class="hljs-string">"MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDK7c0HtOvefMRM"</span> +
            <span class="hljs-string">"s1tkdiJm+A16Df85lQlmXjQvMHNgY4P/znvl4kRON9DdBdo3K81OG7pR/0H9XvdB"</span> +
            <span class="hljs-string">"TEojj/6vCVuMDeeIiBrgx0OJjhv0r8oUD4d52+1kXXITaniyZcbJ08s4sF7fUSCu"</span> +
            <span class="hljs-string">"IZOhvvwQTd/tIwXGU1qqfg+bsomQ6h2czPSKXAux54vUiRO2IWf/Y6twyk8cy1PH"</span> +
            <span class="hljs-string">"IOfelCVUJ4kzmP+CsOH7Rh3JMwZ0Mc4GAzndWpKwNXKjVM20/bKE9FgIiIjzmEQd"</span> +
            <span class="hljs-string">"VpSdUz2MbAKM1kskdaHXQyuaHoHfPwESYuEwBld4vh9AGMF3jYMu8ggnAzVRIoWG"</span> +
            <span class="hljs-string">"Mr5eCE2tAgMBAAECggEBAKBPXiKRdahMzlJ9elyRyrmnihX7Cr41k7hwAS+qSetC"</span> +
            <span class="hljs-string">"kpu6RjykFCvqgjCpF+tvyf/DfdybF0mPBStrlkIj1iH29YBd16QPSZR7NkprnoAd"</span> +
            <span class="hljs-string">"gzl3zyGgcRhRjfXyrajZKEJ281s0Ua5/i56kXdlwY/aJXrYabcxwOvbnIXNxhqWY"</span> +
            <span class="hljs-string">"NSejZn75fcacSyvaueRO6NqxmCTBG2IO4FDc/xGzsyFKIOVYS+B4o/ktUOlU3Kbf"</span> +
            <span class="hljs-string">"vwtz7U5GAh9mpFF+Dkr77Kv3i2aQUonja6is7X3JlA93dPu4JDWK8jrhgdZqY9p9"</span> +
            <span class="hljs-string">"Q8odbKYUaBV8Z8CnNgz2zaNQinshzwOeGfFlsd6H7SECgYEA7ScsDCL7omoXj4lV"</span> +
            <span class="hljs-string">"Mt9RkWp6wQ8WDu5M+OCDrcM1/lfyta2wf7+9hv7iDb+FwQnWO3W7eFngYUTwSw5x"</span> +
            <span class="hljs-string">"YP2uvOL5qbe7YntKI4Q9gHgUd4XdRJJSIdcoY9/d1pavkYwOGk7KsUrmSeoJJ2Jg"</span> +
            <span class="hljs-string">"54ypVzZlVRkcHjuwiiXKvHwj2+UCgYEA2w5YvWSujExREmue0BOXtypOPgxuolZY"</span> +
            <span class="hljs-string">"pS5LnuAr4rvrZakE8I4sdYjh0yLZ6qXJHzVlxW3DhTqhcrhTLhd54YDogy2IT2ff"</span> +
            <span class="hljs-string">"0GzAV0kX+nz+mRhw0/u+Yw6h0QuzH9Q04Wg3T/u/K9+rG335j/RU1Tnh7nxetfGb"</span> +
            <span class="hljs-string">"EwJ1oOqcXikCgYEAqBAWmxM/mL3urH36ru6r842uKJr0WuhuDAGvz7iDzxesnSvV"</span> +
            <span class="hljs-string">"5PKQ8dY3hN6xfzflZoXssUGgTc55K/e0SbP93UZNAAWA+i29QKY6n4x5lKp9QFch"</span> +
            <span class="hljs-string">"dXHw4baIk8Z97Xt/kw07f6FAyijdC9ggLHf2miOmdEQzNQm/9mcJ4cFn+DECgYEA"</span> +
            <span class="hljs-string">"gvOepQntNr3gsUxY0jcEOWE3COzRroZD0+tLFZ0ZXx/L5ygVZeD4PwMnTNrGvvmA"</span> +
            <span class="hljs-string">"tAFt54pomdqk7Tm3sBQkrmQrm0+67w0/xQ9eJE/z37CdWtQ7jt4twHXc0mVWHa70"</span> +
            <span class="hljs-string">"NdPhTRVIAWhil7rFWANOO3Gw2KrMy6O1erW7sAjQlZECgYBmjXWzgasT7JcHrP72"</span> +
            <span class="hljs-string">"fqrEx4cg/jQFNlqODNb515tfXSBBoAFiaxWJK3Uh/60/I6cFL/Qoner4trNDWSNo"</span> +
            <span class="hljs-string">"YENBqXLZnWGfIo0vAIgniJ6OD67+1hEQtbenhSfeE8Hou2BnFOTajUxmYgGm3+hx"</span> +
            <span class="hljs-string">"h8TPOvfHATdiwIm7Qu76gHhpzQ=="</span> +
            <span class="hljs-string">"-----END PRIVATE KEY-----"</span>;

    rsaPrivateKey = rsaPrivateKey.replace(<span class="hljs-string">"-----BEGIN PRIVATE KEY-----"</span>, <span class="hljs-string">""</span>);
    rsaPrivateKey = rsaPrivateKey.replace(<span class="hljs-string">"-----END PRIVATE KEY-----"</span>, <span class="hljs-string">""</span>);

    PKCS8EncodedKeySpec keySpec = <span class="hljs-keyword">new</span> PKCS8EncodedKeySpec(Base64.getDecoder().decode(rsaPrivateKey));
    KeyFactory kf = KeyFactory.getInstance(<span class="hljs-string">"RSA"</span>);
    PrivateKey privKey = kf.generatePrivate(keySpec);
    <span class="hljs-keyword">return</span> privKey;
}</code></div><small class="shcb-language" id="shcb-language-28"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Generated JWT Token:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-29" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash">eyJhbGciOiJSUzI1NiJ9.eyJuYW1lIjoiSmFuZSBEb2UiLCJlbWFpbCI6ImphbmVAZXhhbXBsZS5jb20iLCJzdWIiOiJqYW5lIiwianRpIjoiNGJiMDU4YzUtZDZhNi00NGNiLWEwOWYtZmM5MjdiNjcwYTJiIiwiaWF0IjoxNTkwODA1NDM3LCJleHAiOjE1OTA4MDU3Mzd9.HZa6ckOvT73KqmYluW5vww10ESNGKRrcYumDjE6ESctrIkLyXrc_fasjDfMAit5SPgIWv8u2GO2XsZzFhyL1Ar_VfCMGY1m6-2Aq-clci0jfzk-q1_SBB57fBQE6io9lPuZcuGtRHjsSmwUUFwHA_bcvVU1Ka85UnQnYilgPoE0BQG9v1ZJy_hjPSisfQh56flHMqs-W4P3X6zY4Ak_92A8FHaaxWABJhJCY1Hl7OR2kSnbqcJaPRYI064x-p1gIePScPTjuDRjNOoyaA-5QEgvWV2BTW6lWIS9yE6NdzvmOt2Nv_5YN5ESuQcVT6XgxNwscoQu3iG3UiOthU6kz-w</code></div><small class="shcb-language" id="shcb-language-29"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>For simplicity the Private Key is hard coded in above example. However, in real production system it will be loaded from environment variable, or a secret vault (Hashicorp Vault or AWS Parameter Store).</p>



<p>In above example the method <code>getPrivateKey()</code> gets the <code>java.security.PrivateKey</code> which is then used in <code>Jwts.builder</code> to sign the JWT token using Private key.</p>



<h3>6.3 Validate/Parse JWT Token signed with RSA Private/Public Keys</h3>



<p>Next, let us validate and parse the JWT signed using RSA. For that we will need Public Key instance in <code>java.security.PublicKey</code> format which <code>Jwts.parserBuilder</code> will use to validate the JWT.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-30" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java shcb-wrap-lines"><span class="hljs-keyword">import</span> io.jsonwebtoken.Claims;
<span class="hljs-keyword">import</span> io.jsonwebtoken.Jws;
<span class="hljs-keyword">import</span> io.jsonwebtoken.Jwts;

<span class="hljs-keyword">import</span> java.security.KeyFactory;
<span class="hljs-keyword">import</span> java.security.NoSuchAlgorithmException;
<span class="hljs-keyword">import</span> java.security.PublicKey;
<span class="hljs-keyword">import</span> java.security.spec.InvalidKeySpecException;
<span class="hljs-keyword">import</span> java.security.spec.X509EncodedKeySpec;
<span class="hljs-keyword">import</span> java.util.Base64;
<span class="hljs-comment">//..</span>

<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Jws&lt;Claims&gt; <span class="hljs-title">parseJwt</span><span class="hljs-params">(String jwtString)</span> <span class="hljs-keyword">throws</span> InvalidKeySpecException, NoSuchAlgorithmException </span>{

    PublicKey publicKey = getPublicKey();

    Jws&lt;Claims&gt; jwt = Jwts.parserBuilder()
            .setSigningKey(publicKey)
            .build()
            .parseClaimsJws(jwtString);

    <span class="hljs-keyword">return</span> jwt;
}

<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> PublicKey <span class="hljs-title">getPublicKey</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> NoSuchAlgorithmException, InvalidKeySpecException </span>{
    String rsaPublicKey = <span class="hljs-string">"-----BEGIN PUBLIC KEY-----"</span> +
            <span class="hljs-string">"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyu3NB7Tr3nzETLNbZHYi"</span> +
            <span class="hljs-string">"ZvgNeg3/OZUJZl40LzBzYGOD/8575eJETjfQ3QXaNyvNThu6Uf9B/V73QUxKI4/+"</span> +
            <span class="hljs-string">"rwlbjA3niIga4MdDiY4b9K/KFA+HedvtZF1yE2p4smXGydPLOLBe31EgriGTob78"</span> +
            <span class="hljs-string">"EE3f7SMFxlNaqn4Pm7KJkOodnMz0ilwLseeL1IkTtiFn/2OrcMpPHMtTxyDn3pQl"</span> +
            <span class="hljs-string">"VCeJM5j/grDh+0YdyTMGdDHOBgM53VqSsDVyo1TNtP2yhPRYCIiI85hEHVaUnVM9"</span> +
            <span class="hljs-string">"jGwCjNZLJHWh10Mrmh6B3z8BEmLhMAZXeL4fQBjBd42DLvIIJwM1USKFhjK+XghN"</span> +
            <span class="hljs-string">"rQIDAQAB"</span> +
            <span class="hljs-string">"-----END PUBLIC KEY-----"</span>;
    rsaPublicKey = rsaPublicKey.replace(<span class="hljs-string">"-----BEGIN PUBLIC KEY-----"</span>, <span class="hljs-string">""</span>);
    rsaPublicKey = rsaPublicKey.replace(<span class="hljs-string">"-----END PUBLIC KEY-----"</span>, <span class="hljs-string">""</span>);
    X509EncodedKeySpec keySpec = <span class="hljs-keyword">new</span> X509EncodedKeySpec(Base64.getDecoder().decode(rsaPublicKey));
    KeyFactory kf = KeyFactory.getInstance(<span class="hljs-string">"RSA"</span>);
    PublicKey publicKey = kf.generatePublic(keySpec);
    <span class="hljs-keyword">return</span> publicKey;
}</code></div><small class="shcb-language" id="shcb-language-30"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Output:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-31" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json shcb-wrap-lines">{name=Jane Doe, email=jane@example.com, sub=jane, jti=4bb058c5-d6a6-44cb-a09f-fc927b670a2b, iat=1590805437, exp=1590805737}</code></div><small class="shcb-language" id="shcb-language-31"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<p>In above example, we have hardcoded the Public Key. In a production system, it is usually configured through environment variable or service configuration.</p>



<h2>7. Source Code &#8211; Generate and Validate JWT Tokens using Java &amp; JJWT</h2>



<p>Source code for the Creating and Validating JWT token in Java.</p>



<p>Github &#8211; <a href="https://github.com/viralpatel/java-create-validate-jwt-token">source code</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/java-create-validate-jwt-token/feed/</wfw:commentRss>
			<slash:comments>7</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Boot GraphQL Subscription Realtime API</title>
		<link>https://www.viralpatel.net/spring-boot-graphql-subscription-realtime-api/</link>
					<comments>https://www.viralpatel.net/spring-boot-graphql-subscription-realtime-api/#comments</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Mon, 25 May 2020 06:15:58 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[graphql]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3785</guid>

					<description><![CDATA[GraphQL Subscription provides a great way of building real-time API. In this tutorial we will build a realtime GraphQL subscription API using Spring Boot. 1. Overview Spring Boot GraphQL Subscription &#8211; GraphQL provides an&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2020/05/spring-boot-graphql-subscription.jpg" alt="Spring Boot GraphQL Subscription Realtime API"/></figure>



<p>GraphQL Subscription provides a great way of building real-time API. In this tutorial we will build a realtime GraphQL subscription API using Spring Boot.</p>



<h2>1. Overview</h2>



<p><strong>Spring Boot GraphQL Subscription</strong> &#8211; GraphQL provides an alternate way of building APIs. Similar to REST, with GraphQL we can query data from server/backend and also update data. This is called <code>Query</code> and <code>Mutation</code> in GraphQL. Checkout the tutorial on <a href="https://www.viralpatel.net/graphql-spring-boot-tutorial/">Getting Started with GraphQL with Spring Boot</a> in which both Query and Mutation is discussed in detail.</p>



<p>Oftentimes clients want to get pushed updates from the server when data they care about changes. GraphQL <code>Subscription</code> provides this capability of long-lived stream of source events that client can subscribe to.</p>



<h2>2. GraphQL Subscription</h2>



<p>GraphQL subscriptions are a way to push data from the server to the clients that choose to listen to real time messages from the server. Subscriptions are similar to queries in that they specify a set of fields to be delivered to the client, but instead of immediately returning a single answer, a result is sent every time a particular event happens on the server.</p>



<p>When using Subscription, the client will connect to GraphQL server using Websocket. A persistent websocket connect gets established at the beginning and used across the lifecycle until client wants to consume messages or until server is available. Each time a new message is available, server pushes it on the websocket connection to client.</p>



<p>Designing a realtime API using GraphQL subscription requires careful considerations. Unlike Query and Mutation which are stateless operation types, Subscription is a stateful operation. A stateful connection using WebSocket is established with server. Server should be designed to handle multiple connections and scale along with new connections. Usually to achieve this server can use a messaging service such as RabbitMQ, Redis Pub/Sub or Kafka.</p>



<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<div class="video-container"><iframe title="Spring Boot GraphQL Subscription Realtime API Demo" width="720" height="540" src="https://www.youtube.com/embed/2hIl0J-ldRI?feature=oembed&#038;wmode=opaque" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
</div></figure>



<h2>3. Spring Boot GraphQL Subscription API</h2>



<p>For this tutorial, we will going to mock the messaging server and send mock data to client through Subscription. Let us start with initializing Spring Boot app.</p>



<p>The next step would be to create Spring Boot app with GraphQL support. Let us scaffold the app with <a href="https://start.spring.io">start.spring.io</a> using following options:</p>



<ol><li>Gradle project</li><li>Java 11</li><li>Spring Boot 2.3.0</li><li>Group: <code>net.viralpatel</code> Artifact: <code>spring-boot-graphql-subscription</code></li></ol>



<h3>3.1 Dependencies</h3>



<p>Let us add GraphQL Java and other dependencies in Gradle. Open <code>build.gradle</code> file and add following code:</p>



<p>build.gradle</p>


<pre class="wp-block-code" aria-describedby="shcb-language-32" data-shcb-language-name="Gradle" data-shcb-language-slug="gradle"><div><code class="hljs language-gradle shcb-wrap-lines">plugins {
    id <span class="hljs-string">'org.springframework.boot'</span> version <span class="hljs-string">'2.3.0.RELEASE'</span>
    id <span class="hljs-string">'io.spring.dependency-management'</span> version <span class="hljs-string">'1.0.9.RELEASE'</span>
    id <span class="hljs-string">'java'</span>
}
<span class="hljs-keyword">group</span> = <span class="hljs-string">'net.viralpatel'</span>
version = <span class="hljs-string">'0.0.1-SNAPSHOT'</span>
<span class="hljs-keyword">sourceCompatibility</span> = <span class="hljs-string">'11'</span>

<span class="hljs-keyword">repositories</span> {
    mavenCentral()
}

<span class="hljs-keyword">dependencies</span> {
    implementation <span class="hljs-string">'org.springframework.boot:spring-boot-starter'</span>
    implementation <span class="hljs-string">'com.graphql-java-kickstart:graphql-spring-boot-starter:7.0.1'</span>
    implementation <span class="hljs-string">'io.projectreactor:reactor-core'</span>
    runtimeOnly <span class="hljs-string">'com.graphql-java-kickstart:graphiql-spring-boot-starter:7.0.2-SNAPSHOT'</span>
    testImplementation <span class="hljs-string">'org.springframework.boot:spring-boot-starter-test'</span>
}

test {
    useJUnitPlatform()
}</code></div><small class="shcb-language" id="shcb-language-32"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Gradle</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">gradle</span><span class="shcb-language__paren">)</span></small></pre>


<p>Or if you are using Maven, add following test dependencies.</p>



<p>pom.xml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-33" data-shcb-language-name="HTML, XML" data-shcb-language-slug="xml"><div><code class="hljs language-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<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>boot:spring-boot-starter<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>com.graphql-java-kickstart<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>graphql-spring-boot-starter<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>7.0.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-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>io.projectreactor<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>reactor-core<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>com.graphql-java-kickstart<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>graphiql-spring-boot-starter<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>7.0.2<span class="hljs-tag">&lt;/<span class="hljs-name">version</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></code></div><small class="shcb-language" id="shcb-language-33"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">HTML, XML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">xml</span><span class="shcb-language__paren">)</span></small></pre>


<h3>3.2 GraphQL Schema SDL</h3>



<p>The GraphQL schema can be written using GraphQL SDL (Schema Definition Language). Following is our app’s GraphQL schema.</p>



<p>Schema definition file is under <code>src/resources</code> directory. GraphQL Spring Boot starter will read this and configure it using graphql-java-tools.</p>



<p>src/resources/schema.graphqls</p>


<pre class="wp-block-code" aria-describedby="shcb-language-34" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json">type Query {
    stockDetail(symbol: String): StockDetail
}

type Subscription {
    stockPrice(symbol: String): StockPrice
}

type StockDetail {
    symbol: String,
    name: String,
    marketCap: String
}

type StockPrice {
    symbol: String
    price: String
    timestamp: String
}</code></div><small class="shcb-language" id="shcb-language-34"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<p>The schema consist of GraphQL <code>Query</code> and <code>Subscription</code> default operation types. It also contains user defined types StockDetail and StockPrice.</p>



<p>The Query <code>stockDetail</code> returns the type StockDetail and is used as GET API to get the stock detail once when called. The Subscription method <code>stockPrice</code> returns the type StockPrice. Since it is Subscription method, instead of returning the result once it subscribe to the method and listen for any changes from server. Server will push changes in realtime whenever there is new data available.</p>



<h3>3.3 Query Resolver</h3>



<p>The Spring Boot Graphql starter expects an instance of GraphQLQueryResolver in classpath when the app boots.</p>



<p>QueryResolver.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-35" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqlsubscription;

<span class="hljs-keyword">import</span> graphql.kickstart.tools.GraphQLQueryResolver;
<span class="hljs-keyword">import</span> net.viralpatel.springbootgraphqlsubscription.model.StockDetail;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;

<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">QueryResolver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">GraphQLQueryResolver</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> StockDetail <span class="hljs-title">stockDetail</span><span class="hljs-params">(String symbol)</span> </span>{

       <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> StockDetail(symbol, <span class="hljs-string">"name"</span>, <span class="hljs-number">2000l</span>);
    }
}</code></div><small class="shcb-language" id="shcb-language-35"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>The custom QueryResolver class defines method stockDetail which matches to the GraphQL SDL we defined above. This method will be invoked whenever the client calls the Query method stockDetail.</p>



<p>The response is just hardcoded value of stock symbol, name and price. Instead of hardcoding, these values can come from database or any backend API.</p>



<h3>3.3 Subscription Resolver</h3>



<p>Similar to QueryResolver, the custom SubscriptionResolver class is required on classpath when using subscription type in GraphQL SDL.</p>



<p>SubscriptionResolver.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-36" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java shcb-wrap-lines"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqlsubscription;

<span class="hljs-keyword">import</span> graphql.kickstart.tools.GraphQLSubscriptionResolver;
<span class="hljs-keyword">import</span> net.viralpatel.springbootgraphqlsubscription.model.StockPrice;
<span class="hljs-keyword">import</span> org.reactivestreams.Publisher;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Component;
<span class="hljs-keyword">import</span> reactor.core.publisher.Flux;

<span class="hljs-keyword">import</span> java.time.Duration;
<span class="hljs-keyword">import</span> java.time.LocalDateTime;
<span class="hljs-keyword">import</span> java.util.Random;

<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">SubscriptionResolver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">GraphQLSubscriptionResolver</span> </span>{

    <span class="hljs-function"><span class="hljs-keyword">public</span> Publisher&lt;StockPrice&gt; <span class="hljs-title">stockPrice</span><span class="hljs-params">(String symbol)</span> </span>{

        Random random = <span class="hljs-keyword">new</span> Random();
        <span class="hljs-keyword">return</span> Flux.interval(Duration.ofSeconds(<span class="hljs-number">1</span>))
                .map(num -&gt; <span class="hljs-keyword">new</span> StockPrice(symbol, random.nextDouble(), LocalDateTime.now()));
    }
}</code></div><small class="shcb-language" id="shcb-language-36"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>The custom SubscriptionResolver class contains stockPrice method which matches to the GraphQL SDL we defined earlier. This method will be invoked whenever client subscribe for this method. The client would establish a websoket connection with server and the <code>stockPrice()</code> method will return a project reactor&#8217;s Publisher instance. The Publisher instace does not return the result immediately rather it will send the result whenever server pushes it. This is the same way Spring Boot Webflux pushes the result non-blocking way.</p>



<p>For simplicity, we have hardcoded the result. The <code>stockPrice()</code> method would return a random value every second using <code>Flux.interval</code> method. Instead of hardcoding these results can also come from a Kafka topic or RabbitMQ queue.</p>



<p>StockDetail.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-37" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqlsubscription.model;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StockDetail</span> </span>{
    <span class="hljs-keyword">private</span> String symbol;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">long</span> marketCap;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">StockDetail</span><span class="hljs-params">(String symbol, String name, <span class="hljs-keyword">long</span> marketCap)</span> </span>{
        <span class="hljs-keyword">this</span>.name = name;
        <span class="hljs-keyword">this</span>.symbol = symbol;
        <span class="hljs-keyword">this</span>.marketCap = marketCap;
    }

    <span class="hljs-comment">// getter and setters</span>
}</code></div><small class="shcb-language" id="shcb-language-37"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>StockPrice.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-38" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqlsubscription.model;

<span class="hljs-keyword">import</span> java.time.LocalDateTime;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StockPrice</span> </span>{
    <span class="hljs-keyword">private</span> String symbol;
    <span class="hljs-keyword">private</span> <span class="hljs-keyword">double</span> price;
    <span class="hljs-keyword">private</span> LocalDateTime timestamp;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">StockPrice</span><span class="hljs-params">(String symbol, <span class="hljs-keyword">double</span> price, LocalDateTime timestamp)</span> </span>{
        <span class="hljs-keyword">this</span>.price = price;
        <span class="hljs-keyword">this</span>.symbol = symbol;
        <span class="hljs-keyword">this</span>.timestamp = timestamp;
    }

    <span class="hljs-comment">// getter and setters</span>
}</code></div><small class="shcb-language" id="shcb-language-38"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>The above are just some plain old Java objects to carry the data from server to client.</p>



<h2>4. Build and Execute</h2>



<p>Start the Spring Boot application by running SpringBootGraphqlSubscriptionApplication class or by running gradle:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-39" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash">./gradlew bootRun</code></div><small class="shcb-language" id="shcb-language-39"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>Once the Spring Boot app is started on default port 8080, open <code>http://localhost:8080/graphiql</code></p>



<p>Try running following GraphQL subscription method and see the output.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-40" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json">subscription {
  stockPrice(symbol: <span class="hljs-string">"GOOG"</span>) {
    symbol
    price
    timestamp
  }
}</code></div><small class="shcb-language" id="shcb-language-40"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<p>At first we will see following output in Graphiql editor.</p>


<pre class="wp-block-code"><div><code class="hljs">Your subscription data will appear here after server publication!</code></div></pre>


<p>And after a few seconds we should start getting result back from server.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-41" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json">{
  <span class="hljs-attr">"stockPrice"</span>: {
    <span class="hljs-attr">"symbol"</span>: <span class="hljs-string">"GOOG"</span>,
    <span class="hljs-attr">"price"</span>: <span class="hljs-string">"0.7199789993583869"</span>,
    <span class="hljs-attr">"timestamp"</span>: <span class="hljs-string">"2020-05-24T19:41:51.780299"</span>
  }
}</code></div><small class="shcb-language" id="shcb-language-41"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2020/05/spring-boot-graphql-subscription-graphiql-editor.png" alt="Spring Boot GraphQL Subscription GraphiQL Editor"/></figure>



<h2>5. Source Code &#8211; Spring Boot GraphQL Subscription Example</h2>



<p>Source code for the Spring Boot GraphQL Subscription API.</p>



<p>Github &#8211; <a href="https://github.com/viralpatel/spring-boot-graphql-subscription">spring-boot-graphql-subscription</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/spring-boot-graphql-subscription-realtime-api/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Boot DynamoDB Integration Test using Testcontainers</title>
		<link>https://www.viralpatel.net/spring-boot-dynamodb-integration-test-testcontainers/</link>
					<comments>https://www.viralpatel.net/spring-boot-dynamodb-integration-test-testcontainers/#respond</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Sun, 17 May 2020 05:37:45 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[DynamoDB]]></category>
		<category><![CDATA[Testcontainers]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3774</guid>

					<description><![CDATA[1. Overview Spring Boot Webflux DynamoDB Integration tests &#8211; In this tutorial we will see how to setup integration test for a Spring Boot Webflux project with DynamoDB using Testcontainers. This post will use&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2020/05/spring-boot-dynamodb-integration-tests.png" alt="Spring Boot DynamoDB Integration Tests using TestContainers"/></figure>



<h2>1. Overview</h2>



<p><strong>Spring Boot Webflux DynamoDB Integration tests</strong> &#8211; In this tutorial we will see how to setup integration test for a Spring Boot Webflux project with DynamoDB using Testcontainers. This post will use the example from previous <a href="https://www.viralpatel.net/spring-boot-webflux-dynamodb/">Spring Boot Webflux DynamoDB tutorial</a>. Let us add integration tests using Testcontainers and integrate DynamoDB tests with our Spring Boot project.</p>



<h2>2. What is Testcontainers?</h2>



<p>Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.</p>



<p>The key here is Docker containers. It allows us to use any Docker image and run it as container within our integration tests. There are number of standard Testcontainers available to test integration with technologies such as Elastic search, Kafka, RabbitMQ etc. We can also use any Docker container using Testcontainers <code>GenericContainer</code> api.</p>



<p>One key thing to remember while using Testcontainers is that local Docker installation is required to run these test cases. If you are running your integration tests in continues integration (CI) pipelines, remember to use machine instance instead of docker. As Testcontainers need Docker to run, we cannot run it inside a Docker container in CI. Usually all the standard CI platforms such as Circle CI do provides machine instance where you can run your integration tests.</p>



<h2>3. Spring Boot DynamoDB Integration Tests using Testcontainers</h2>



<h3>3.1 Gradle test dependencies</h3>



<p>Add following dependencies for Testcontainers and Junit support for Testcontainers.</p>



<p>build.gradle</p>


<pre class="wp-block-code" aria-describedby="shcb-language-42" data-shcb-language-name="CSS" data-shcb-language-slug="css"><div><code class="hljs language-css"><span class="hljs-selector-tag">testCompile</span> "<span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.testcontainers</span><span class="hljs-selector-pseudo">:testcontainers</span><span class="hljs-selector-pseudo">:1.14.1"</span>
<span class="hljs-selector-tag">testCompile</span> "<span class="hljs-selector-tag">org</span><span class="hljs-selector-class">.testcontainers</span><span class="hljs-selector-pseudo">:junit-jupiter</span><span class="hljs-selector-pseudo">:1.14.1"</span></code></div><small class="shcb-language" id="shcb-language-42"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">CSS</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">css</span><span class="shcb-language__paren">)</span></small></pre>


<p>Or if you are using Maven, add following test dependencies.</p>



<p>pom.xml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-43" data-shcb-language-name="HTML, XML" data-shcb-language-slug="xml"><div><code class="hljs language-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.testcontainers<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>testcontainers<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.14.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<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-tag">&lt;<span class="hljs-name">dependency</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>org.testcontainers<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>junit-jupiter<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.14.1<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">scope</span>&gt;</span>test<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></code></div><small class="shcb-language" id="shcb-language-43"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">HTML, XML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">xml</span><span class="shcb-language__paren">)</span></small></pre>


<h3>3.2 Define DynamoDB Docker @Container</h3>



<p>Once the dependencies are defined, we can start using the Testcontainers in JUnit. First thing is to define a <code>GenericContainer</code> object with official docker image of DynamoDB <code>amazon/dynamodb-local</code>. The <code>withExposedPorts()</code> method defines the port where DynamoDB will be listening to inside the Docker container. The GenericContainer object is annotated with <code>@Container</code> annotation. This annotation works in conjunction with <code>@Testcontainers</code> annotation to mark containers that should be managed by the Testcontainers extension.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-44" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> DYNAMODB_PORT = <span class="hljs-number">8000</span>;

<span class="hljs-meta">@Container</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> GenericContainer dynamodb =
        <span class="hljs-keyword">new</span> GenericContainer&lt;&gt;(<span class="hljs-string">"amazon/dynamodb-local"</span>)
            .withExposedPorts(DYNAMODB_PORT);</code></div><small class="shcb-language" id="shcb-language-44"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Testcontainers will start the Docker container with DynamoDB on the given DYNAMO_PORT 8000, however that will be the internal port which we need to map to actual random port which the AWS DynamoDB client from Spring Boot app can connect to.</p>



<p>Since our Spring Boot app connects to DynamoDB on the host and port defined under <code>application.dynamodb.endpoint</code> config in application.yaml file, for the test case we need to override this config at runtime to point to actual host and port where Docker is running.</p>



<p>To achieve this we are using <code>ApplicationContextInitializer</code> to override the <code>application.dynamodb.endpoint</code> property. We are using <code>GenericContainer</code>&#8216;s getContainerIpAddress and getMappedPort method to get the ip address and actual port number of DynamoDB running inside Docker.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-45" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamoDBInitializer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ApplicationContextInitializer</span>&lt;<span class="hljs-title">ConfigurableApplicationContext</span>&gt; </span>{
    <span class="hljs-meta">@Override</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initialise</span><span class="hljs-params">(ConfigurableApplicationContext ctx)</span> </span>{

        TestPropertyValues.of(
                String.format(<span class="hljs-string">"application.dynamodb.endpoint: http://%s:%s"</span>,
                    dynamodb.getContainerIpAddress(), dynamodb.getMappedPort(DYNAMODB_PORT)))
                .applyTo(ctx);
    }
}</code></div><small class="shcb-language" id="shcb-language-45"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h3>3.3 End to end integration test</h3>



<p>In following <code>RoutesTests</code>, we have one testcase that creates a blank table <code>customers</code> and then uses Spring&#8217;s <code>WebTestClient</code> to call POST /customers API. The testcase checks the response from API. Since this is an integration test, the whole service is booted and the customer record is created in DynamoDB database using Testcontainers.</p>



<p>RoutesTests.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-46" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootwebfluxdynamodb;

<span class="hljs-keyword">import</span> net.viralpatel.springbootwebfluxdynamodb.customer.Customer;
<span class="hljs-keyword">import</span> org.junit.jupiter.api.Test;
<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.boot.test.context.SpringBootTest;
<span class="hljs-keyword">import</span> org.springframework.boot.test.util.TestPropertyValues;
<span class="hljs-keyword">import</span> org.springframework.context.ApplicationContextInitializer;
<span class="hljs-keyword">import</span> org.springframework.context.ConfigurableApplicationContext;
<span class="hljs-keyword">import</span> org.springframework.test.context.ContextConfiguration;
<span class="hljs-keyword">import</span> org.springframework.test.web.reactive.server.WebTestClient;
<span class="hljs-keyword">import</span> org.testcontainers.containers.GenericContainer;
<span class="hljs-keyword">import</span> org.testcontainers.junit.jupiter.Container;
<span class="hljs-keyword">import</span> org.testcontainers.junit.jupiter.Testcontainers;
<span class="hljs-keyword">import</span> reactor.core.publisher.Mono;
<span class="hljs-keyword">import</span> software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
<span class="hljs-keyword">import</span> software.amazon.awssdk.services.dynamodb.model.*;

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

<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> org.hamcrest.Matchers.*;

<span class="hljs-meta">@SpringBootTest</span>(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
<span class="hljs-meta">@Testcontainers</span>
<span class="hljs-meta">@ContextConfiguration</span>(initializers = RoutesTests.DynamoDBInitializer<span class="hljs-class">.<span class="hljs-keyword">class</span>)
<span class="hljs-title">public</span> <span class="hljs-title">class</span> <span class="hljs-title">RoutesTests</span> </span>{

    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">int</span> DYNAMODB_PORT = <span class="hljs-number">8000</span>;

    <span class="hljs-meta">@Autowired</span>
    DynamoDbAsyncClient dynamoDbAsyncClient;

    <span class="hljs-meta">@Container</span>
    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> GenericContainer dynamodb =
            <span class="hljs-keyword">new</span> GenericContainer&lt;&gt;(<span class="hljs-string">"amazon/dynamodb-local:latest"</span>)
                .withExposedPorts(DYNAMODB_PORT);

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamoDBInitializer</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ApplicationContextInitializer</span>&lt;<span class="hljs-title">ConfigurableApplicationContext</span>&gt; </span>{
        <span class="hljs-meta">@Override</span>
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initialize</span><span class="hljs-params">(ConfigurableApplicationContext ctx)</span> </span>{

            TestPropertyValues.of(
                    String.format(<span class="hljs-string">"application.dynamodb.endpoint: http://%s:%s"</span>,
                        dynamodb.getContainerIpAddress(), dynamodb.getMappedPort(DYNAMODB_PORT)))
                    .applyTo(ctx);
        }
    }

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-keyword">public</span> WebTestClient webTestClient;

    <span class="hljs-meta">@Test</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">shouldCreateCustomerWhenCustomerAPIInvoked</span><span class="hljs-params">()</span> </span>{

        <span class="hljs-comment">// Create customers table in DynamoDB</span>
        CompletableFuture&lt;CreateTableResponse&gt; createTable = dynamoDbAsyncClient.createTable(CreateTableRequest.builder()
                .tableName(<span class="hljs-string">"customers"</span>)
                .attributeDefinitions(AttributeDefinition.builder().attributeName(<span class="hljs-string">"customerId"</span>).attributeType(<span class="hljs-string">"S"</span>).build())
                .keySchema(KeySchemaElement.builder().attributeName(<span class="hljs-string">"customerId"</span>).keyType(KeyType.HASH).build())
                .provisionedThroughput(ProvisionedThroughput.builder().readCapacityUnits(<span class="hljs-number">5l</span>).writeCapacityUnits(<span class="hljs-number">5l</span>).build())
                .build());

        Mono.fromFuture(createTable).block();

        Customer customer = <span class="hljs-keyword">new</span> Customer();
        customer.setName(<span class="hljs-string">"John"</span>);
        customer.setCity(<span class="hljs-string">"Sydney"</span>);
        customer.setEmail(<span class="hljs-string">"john@example.com"</span>);

        webTestClient
                .post()
                .uri(<span class="hljs-string">"/customers"</span>)
                .bodyValue(customer)
                .exchange()
                .expectStatus().is2xxSuccessful()
                .expectHeader().value(<span class="hljs-string">"Location"</span>, is(not(blankOrNullString())));
    }
}</code></div><small class="shcb-language" id="shcb-language-46"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Let us go through the above code step by step and see what is going on.</p>



<p><code>@SpringBootTest</code> &#8211; Specify that the test case is an integration test. Spring should load the full application context and make all beans available to the test case.</p>



<p><code>@Testcontainers</code> &#8211; It is a JUnit Jupiter extension to activate automatic startup and stop of containers used in a test case. The test containers extension finds all fields that are annotated with <code>Container</code> and calls their container lifecycle methods. Containers declared as static fields will be shared between test methods. They will be started only once before any test method is executed and stopped after the last test method has executed. Containers declared as instance fields will be started and stopped for every test method.</p>



<p><code>@ContextConfiguration</code> &#8211; It overrides the Spring properties. We use it to override the host and port of DynamoDB where our DynamoDB client connects. The <code>DynamoDBInitializer</code> static class defined within the test case override this property. We can move this logic into an abstract class and reuse it across multiple tests.</p>



<h2>4. Gotchas / Errors in Integration Test</h2>



<p>If you haven&#8217;t setup your local AWS CLI, you might get following error when running the test case. This is because when the DynamoDB client initialize, it tries to find credentials to connect to dynamodb. In our DynamoDBConfig client we are using DefaultCredentialsProvider which tries to find the credentials at number of places.</p>



<p><code>Unable to load credentials from service endpoint</code></p>


<pre class="wp-block-code" aria-describedby="shcb-language-47" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash">software.amazon.awssdk.core.exception.SdkClientException: Unable to load credentials from any of the providers <span class="hljs-keyword">in</span> the chain AwsCredentialsProviderChain(credentialsProviders=[SystemPropertyCredentialsProvider(), EnvironmentVariableCredentialsProvider(), ProfileCredentialsProvider(), WebIdentityTokenCredentialsProvider(), ContainerCredentialsProvider(), InstanceProfileCredentialsProvider()]) : [SystemPropertyCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., EnvironmentVariableCredentialsProvider(): Unable to load credentials from system settings. Access key must be specified either via environment variable (AWS_ACCESS_KEY_ID) or system property (aws.accessKeyId)., ProfileCredentialsProvider(): Profile file contained no credentials <span class="hljs-keyword">for</span> profile <span class="hljs-string">'default'</span>: ProfileFile(profiles=[]), WebIdentityTokenCredentialsProvider(): Either the environment variable AWS_WEB_IDENTITY_TOKEN_FILE or the javaproperty aws.webIdentityTokenFile must be <span class="hljs-built_in">set</span>., ContainerCredentialsProvider(): Cannot fetch credentials from container - neither AWS_CONTAINER_CREDENTIALS_FULL_URI or AWS_CONTAINER_CREDENTIALS_RELATIVE_URI environment variables are <span class="hljs-built_in">set</span>., InstanceProfileCredentialsProvider(): Unable to load credentials from service endpoint.]
    at software.amazon.awssdk.core.exception.SdkClientException<span class="hljs-variable">$BuilderImpl</span>.build(SdkClientException.java:97) ~[sdk-core-2.10.40.jar:na]
    Suppressed: reactor.core.publisher.FluxOnAssembly<span class="hljs-variable">$OnAssemblyException</span>: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ HTTP POST <span class="hljs-string">"/customers"</span> [ExceptionHandlingWebHandler]
Stack trace:
        at software.amazon.awssdk.core.exception.SdkClientException<span class="hljs-variable">$BuilderImpl</span>.build(SdkClientException.java:97) ~[sdk-core-2.10.40.jar:na]</code></div><small class="shcb-language" id="shcb-language-47"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>To resolve this error, either setup your AWS CLI so that client can find the credential or define environment variables:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-48" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash"><span class="hljs-built_in">export</span> AWS_SECRET_ACCESS_KEY=<span class="hljs-built_in">test</span>
<span class="hljs-built_in">export</span> AWS_ACCESS_KEY_ID=<span class="hljs-built_in">test</span></code></div><small class="shcb-language" id="shcb-language-48"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<p>The env variables value can be any non empty string.</p>



<p><a href="https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html">Read more on working with AWS Credentials</a></p>



<h2>5. Source Code &#8211; Spring Boot DynamoDB Integration Tests</h2>



<p>Source code for the Testcontainers integration test for DynamoDB and Spring Boot is in Github.</p>



<p>Github &#8211; <a href="https://github.com/viralpatel/spring-boot-webflux-dynamodb">spring-boot-webflux-dynamodb</a></p>



<h2>References</h2>



<ol><li><a href="https://www.testcontainers.org/">Testcontainers</a></li><li><a href="https://docs.spring.io/spring-framework/docs/5.0.0.BUILD-SNAPSHOT/spring-framework-reference/html/web-reactive.html">Spring Boot Webflux</a></li><li><a href="https://docs.aws.amazon.com/sdk-for-java/v2/developer-guide/basics-async.html">AWS DynamoDB Async Client</a></li></ol>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/spring-boot-dynamodb-integration-test-testcontainers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Boot Webflux DynamoDB Tutorial</title>
		<link>https://www.viralpatel.net/spring-boot-webflux-dynamodb/</link>
					<comments>https://www.viralpatel.net/spring-boot-webflux-dynamodb/#comments</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Wed, 25 Dec 2019 00:22:37 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[DynamoDB]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3768</guid>

					<description><![CDATA[Creating REST API in Spring Boot Webflux and AWS DynamoDB. Step by step guide for storing retriving data in DynamoDB using Spring Boot Webflux and exposing it as REST API.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2019/12/spring-boot-webflux-dynamodb-rest-api.png" alt="Spring Boot Webflux DynamoDB Tutorial"/></figure>



<h2>1. Overview</h2>



<p><strong>Spring Boot Webflux DynamoDB Tutorial</strong> &#8211; Let us integrate AWS DynamoDB with Spring Boot Webflux. In this tutorial will be try to integrate DynamoDB with Webflux in Spring Boot. Instead of using the default AWS Sync Client which blocks the thread, we will use Async client with Webflux.  </p>



<p>We are going to create a REST API with basic CRUD operations on a Customer entity. The customer record will be stored in AWS DynamoDB. Also we will use Webflux to connect with DynamoDB. </p>



<h2>2. Project Structure</h2>



<p>Let&#8217;s start by bootstrapping a new Spring Boot project using start.spring.io. Following project settings were selected in start.spring.io.</p>



<ul><li>Project: <em>Gradle Project</em></li><li>Language: <em>Java</em></li><li>Spring Boot: <em>2.2.2</em></li><li>Dependencies: <em>Spring Reactive Web</em></li></ul>



<p>Once generated, import the project in your favorite IDE. </p>



<p>Update the <code>build.gradle</code> file as following. We have added awssdk dynamodb 2.10.40 through dependencyManagement. Also note that spring-boot-starter-weblux is on classpath.</p>



<p>build.gradle</p>


<pre class="wp-block-code" aria-describedby="shcb-language-49" data-shcb-language-name="Gradle" data-shcb-language-slug="gradle"><div><code class="hljs language-gradle">plugins {
    id <span class="hljs-string">'org.springframework.boot'</span> version <span class="hljs-string">'2.2.2.RELEASE'</span>
    id <span class="hljs-string">'io.spring.dependency-management'</span> version <span class="hljs-string">'1.0.8.RELEASE'</span>
    id <span class="hljs-string">'java'</span>
}

<span class="hljs-keyword">group</span> = <span class="hljs-string">'net.viralpatel'</span>
version = <span class="hljs-string">'0.0.1-SNAPSHOT'</span>
<span class="hljs-keyword">sourceCompatibility</span> = <span class="hljs-string">'11'</span>

<span class="hljs-keyword">repositories</span> {
    mavenCentral()
    maven {
        url <span class="hljs-string">'https://s3-us-west-2.amazonaws.com/dynamodb-local/release'</span>
    }
}

<span class="hljs-keyword">dependencies</span> {
    implementation <span class="hljs-string">'org.springframework.boot:spring-boot-starter-webflux'</span>
    implementation <span class="hljs-string">'software.amazon.awssdk:dynamodb'</span>
    testImplementation(<span class="hljs-string">'org.springframework.boot:spring-boot-starter-test'</span>) {
        <span class="hljs-keyword">exclude</span> <span class="hljs-keyword">group</span>: <span class="hljs-string">'org.junit.vintage'</span>, module: <span class="hljs-string">'junit-vintage-engine'</span>
    }
    testImplementation <span class="hljs-string">'io.projectreactor:reactor-test'</span>
}

dependencyManagement {
    imports {
        mavenBom <span class="hljs-string">'software.amazon.awssdk:bom:2.10.40'</span>
    }
}

test {
    useJUnitPlatform()
}</code></div><small class="shcb-language" id="shcb-language-49"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Gradle</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">gradle</span><span class="shcb-language__paren">)</span></small></pre>


<p>Add following configuration in <code>application.yaml</code> file. We have defined a couple of properties for dynamodb endpoint and table name. Note the endpoint is pointing to our local DynamoDB. In production you might want to change this to point to your AWS region. We can also use Spring profiles to switch the value for this properties in different environment. </p>



<p>application.yaml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-50" data-shcb-language-name="YAML" data-shcb-language-slug="yaml"><div><code class="hljs language-yaml"><span class="hljs-attr">application:</span>
    <span class="hljs-attr">dynamodb:</span>
        <span class="hljs-attr">endpoint:</span> <span class="hljs-string">http://localhost:8000</span>
        <span class="hljs-attr">customer_table:</span> <span class="hljs-string">customers</span></code></div><small class="shcb-language" id="shcb-language-50"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">YAML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">yaml</span><span class="shcb-language__paren">)</span></small></pre>


<p>Following is the directory structure for our REST API project. Note that the customer related classes are segregated in a customer package.</p>



<div class="wp-block-image"><figure class="aligncenter"><img src="https://www.viralpatel.net/app/uploads/2019/12/spring-boot-webflux-dynamodb-project-structure.png" alt="Spring Boot Webflux DynamoDB Project Structure"/></figure></div>



<h2>3. Setting up DynamoDB Locally without Docker</h2>



<p>Before we proceed with the rest of tutorial, we will setup a local dynamodb instance where we can test our changes. Instead of relying on AWS environment for DynamoDB this would speed up the development process. </p>



<p>We will create <code>customers</code> table in local DynamoDB. Follow the steps at https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html</p>



<ol><li>Download the AWS DynamoDB Local JAR from above link and unzip it</li><li>Run the local dynamodb jar
<pre class="wp-block-code"><code>java -Djava.library.path=./DynamoDBLocal_lib/ 
         -jar DynamoDBLocal.jar</code></pre></li><li>Create customer table in dynamodb.
<pre class="wp-block-code"><code>aws dynamodb create-table 
    --table-name customers 
    --attribute-definitions AttributeName=customerId,AttributeType=S 
    --key-schema AttributeName=customerId,KeyType=HASH 
    --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 
    --endpoint-url http://localhost:8000</code></pre></li><li>Verify the table is created.     
<pre class="wp-block-code"><code>aws dynamodb list-tables 
    --endpoint-url http://localhost:8000</code></pre>
Output:
<pre class="wp-block-code"><code>{
      "TableNames": [
          "customers"
      ]
}</code></pre></li></ol>



<h2>4. REST API in Spring Boot Webflux DynamoDB</h2>



<p>Let us start by defining the Repository and DynamoDB configuration to access the data from DynamoDB. As noted earlier we will use <code>DynamoDbAsyncClient</code> to access DynamoDB.</p>



<h3>4.1 Repository with AWS Async Client</h3>



<p>The repository class contains basic CRUD methods to maintain Customer entity. Note how we use <code>dynamoDbAsyncClient</code> to access DynamoDB using different GetItemRequest, DeleteItemRequest, ScanRequest APIs. Also we map the return type from DynamoDbAsyncClient which is <code>CompletableFuture</code> to Reactor&#8217;s <code>Mono</code> class using <code>Mono.fromCompletionStage</code>. </p>



<p>CustomerRepository.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-51" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootwebfluxdynamodb.customer;

<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Value;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Repository;
<span class="hljs-keyword">import</span> reactor.core.publisher.Flux;
<span class="hljs-keyword">import</span> reactor.core.publisher.Mono;
<span class="hljs-keyword">import</span> software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;
<span class="hljs-keyword">import</span> software.amazon.awssdk.services.dynamodb.model.*;

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

<span class="hljs-meta">@Repository</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomerRepository</span> </span>{

    <span class="hljs-keyword">private</span> DynamoDbAsyncClient dynamoDbAsyncClient;
    <span class="hljs-keyword">private</span> String customerTable;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomerRepository</span><span class="hljs-params">(DynamoDbAsyncClient dynamoDbAsyncClient,
                              @Value(<span class="hljs-string">"${application.dynamodb.customer_table}"</span>)</span> String customerTable) </span>{
        <span class="hljs-keyword">this</span>.dynamoDbAsyncClient = dynamoDbAsyncClient;
        <span class="hljs-keyword">this</span>.customerTable = customerTable;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Flux&lt;Customer&gt; <span class="hljs-title">listCustomers</span><span class="hljs-params">()</span> </span>{

        ScanRequest scanRequest = ScanRequest.builder()
                .tableName(customerTable)
                .build();

        <span class="hljs-keyword">return</span> Mono.fromCompletionStage(dynamoDbAsyncClient.scan(scanRequest))
                .map(scanResponse -&gt; scanResponse.items())
                .map(CustomerMapper::fromList)
                .flatMapMany(Flux::fromIterable);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;Customer&gt; <span class="hljs-title">createCustomer</span><span class="hljs-params">(Customer customer)</span> </span>{

        customer.setId(UUID.randomUUID().toString());

        PutItemRequest putItemRequest = PutItemRequest.builder()
                .tableName(customerTable)
                .item(CustomerMapper.toMap(customer))
                .build();

        <span class="hljs-keyword">return</span> Mono.fromCompletionStage(dynamoDbAsyncClient.putItem(putItemRequest))
                .map(putItemResponse -&gt; putItemResponse.attributes())
                .map(attributeValueMap -&gt; customer);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;String&gt; <span class="hljs-title">deleteCustomer</span><span class="hljs-params">(String customerId)</span> </span>{
        DeleteItemRequest deleteItemRequest = DeleteItemRequest.builder()
                .tableName(customerTable)
                .key(Map.of(<span class="hljs-string">"customerId"</span>, AttributeValue.builder().s(customerId).build()))
                .build();

        <span class="hljs-keyword">return</span> Mono.fromCompletionStage(dynamoDbAsyncClient.deleteItem(deleteItemRequest))
                .map(deleteItemResponse -&gt; deleteItemResponse.attributes())
                .map(attributeValueMap -&gt; customerId);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;Customer&gt; <span class="hljs-title">getCustomer</span><span class="hljs-params">(String customerId)</span> </span>{
        GetItemRequest getItemRequest = GetItemRequest.builder()
                .tableName(customerTable)
                .key(Map.of(<span class="hljs-string">"customerId"</span>, AttributeValue.builder().s(customerId).build()))
                .build();

        <span class="hljs-keyword">return</span> Mono.fromCompletionStage(dynamoDbAsyncClient.getItem(getItemRequest))
                .map(getItemResponse -&gt; getItemResponse.item())
                .map(CustomerMapper::fromMap);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;String&gt; <span class="hljs-title">updateCustomer</span><span class="hljs-params">(String customerId, Customer customer)</span> </span>{

        customer.setId(customerId);
        PutItemRequest putItemRequest = PutItemRequest.builder()
                .tableName(customerTable)
                .item(CustomerMapper.toMap(customer))
                .build();

        <span class="hljs-keyword">return</span> Mono.fromCompletionStage(dynamoDbAsyncClient.putItem(putItemRequest))
                .map(updateItemResponse -&gt; customerId);
    }
}</code></div><small class="shcb-language" id="shcb-language-51"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>In following configuration class we create an instance of DynamoDbAsyncClient. Note how we mapped the endpoint from the application.yaml using Spring <code>@Value</code> annotation.</p>



<p>DynamoDBConfig.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-52" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootwebfluxdynamodb.config;

<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Value;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
<span class="hljs-keyword">import</span> software.amazon.awssdk.services.dynamodb.DynamoDbAsyncClient;

<span class="hljs-keyword">import</span> java.net.URI;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DynamoDBConfig</span> </span>{

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> DynamoDbAsyncClient <span class="hljs-title">dynamoDbAsyncClient</span><span class="hljs-params">(
            @Value(<span class="hljs-string">"${application.dynamodb.endpoint}"</span>)</span> String dynamoDBEndpoint) </span>{
        <span class="hljs-keyword">return</span> DynamoDbAsyncClient.builder()
                .endpointOverride(URI.create(dynamoDBEndpoint))
                .credentialsProvider(DefaultCredentialsProvider.builder().build())
                .build();
    }
}</code></div><small class="shcb-language" id="shcb-language-52"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Below is a utility class to map response from DynamoDB into our Customer entity class and vice versa. It&#8217;s just a boilerplate code.</p>



<p>CustomerMapper.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-53" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootwebfluxdynamodb.customer;

<span class="hljs-keyword">import</span> software.amazon.awssdk.services.dynamodb.model.AttributeValue;

<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.Map;
<span class="hljs-keyword">import</span> java.util.stream.Collectors;

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

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> List&lt;Customer&gt; <span class="hljs-title">fromList</span><span class="hljs-params">(List&lt;Map&lt;String, AttributeValue&gt;&gt; items)</span> </span>{
        <span class="hljs-keyword">return</span> items.stream()
                .map(CustomerMapper::fromMap)
                .collect(Collectors.toList());
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Customer <span class="hljs-title">fromMap</span><span class="hljs-params">(Map&lt;String, AttributeValue&gt; attributeValueMap)</span> </span>{
        Customer customer = <span class="hljs-keyword">new</span> Customer();
        customer.setId(attributeValueMap.get(<span class="hljs-string">"customerId"</span>).s());
        customer.setName(attributeValueMap.get(<span class="hljs-string">"name"</span>).s());
        customer.setEmail(attributeValueMap.get(<span class="hljs-string">"email"</span>).s());
        customer.setCity(attributeValueMap.get(<span class="hljs-string">"city"</span>).s());
        <span class="hljs-keyword">return</span> customer;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> Map&lt;String, AttributeValue&gt; <span class="hljs-title">toMap</span><span class="hljs-params">(Customer customer)</span> </span>{
        <span class="hljs-keyword">return</span> Map.of(
                <span class="hljs-string">"customerId"</span>, AttributeValue.builder().s(customer.getId()).build(),
                <span class="hljs-string">"name"</span>, AttributeValue.builder().s(customer.getName()).build(),
                <span class="hljs-string">"email"</span>, AttributeValue.builder().s(customer.getEmail()).build(),
                <span class="hljs-string">"city"</span>, AttributeValue.builder().s(customer.getCity()).build()
        );
    }
}</code></div><small class="shcb-language" id="shcb-language-53"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h3>4.2 Service</h3>



<p>Next we are defining Spring&#8217;s Service class to abstract the repository from our routes (controller in old world) layer. Note that we are calling CustomerRepository from the service class and mapping the response into ServerResponse with appropriate Http Status. </p>



<p>CustomerService.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-54" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootwebfluxdynamodb.customer;

<span class="hljs-keyword">import</span> org.springframework.stereotype.Service;
<span class="hljs-keyword">import</span> org.springframework.web.reactive.function.BodyInserters;
<span class="hljs-keyword">import</span> org.springframework.web.reactive.function.server.ServerRequest;
<span class="hljs-keyword">import</span> org.springframework.web.reactive.function.server.ServerResponse;
<span class="hljs-keyword">import</span> reactor.core.publisher.Mono;

<span class="hljs-keyword">import</span> java.net.URI;
<span class="hljs-keyword">import</span> java.util.stream.Collectors;

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

    <span class="hljs-keyword">private</span> CustomerRepository customerRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomerService</span><span class="hljs-params">(CustomerRepository customerRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.customerRepository = customerRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">listCustomers</span><span class="hljs-params">(ServerRequest serverRequest)</span> </span>{
        <span class="hljs-keyword">return</span> customerRepository.listCustomers()
                .collect(Collectors.toList())
                .flatMap(customers -&gt; ServerResponse.ok().body(BodyInserters.fromValue(customers)));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">createCustomer</span><span class="hljs-params">(ServerRequest serverRequest)</span> </span>{

        <span class="hljs-keyword">return</span> serverRequest.bodyToMono(Customer<span class="hljs-class">.<span class="hljs-keyword">class</span>)
                .<span class="hljs-title">flatMap</span>(<span class="hljs-title">customer</span> -&gt; <span class="hljs-title">customerRepository</span>.<span class="hljs-title">createCustomer</span>(<span class="hljs-title">customer</span>))
                .<span class="hljs-title">flatMap</span>(<span class="hljs-title">customer</span> -&gt; <span class="hljs-title">ServerResponse</span>.<span class="hljs-title">created</span>(<span class="hljs-title">URI</span>.<span class="hljs-title">create</span>("/<span class="hljs-title">customers</span>/" + <span class="hljs-title">customer</span>.<span class="hljs-title">getId</span>())).<span class="hljs-title">build</span>())</span>;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">deleteCustomer</span><span class="hljs-params">(ServerRequest serverRequest)</span> </span>{
        String customerId = serverRequest.pathVariable(<span class="hljs-string">"customerId"</span>);

        <span class="hljs-keyword">return</span> customerRepository.deleteCustomer(customerId)
                .flatMap(customer -&gt; ServerResponse.ok().build());
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">getCustomer</span><span class="hljs-params">(ServerRequest serverRequest)</span> </span>{
        String customerId = serverRequest.pathVariable(<span class="hljs-string">"customerId"</span>);

        <span class="hljs-keyword">return</span> customerRepository.getCustomer(customerId)
                .flatMap(customer -&gt; ServerResponse.ok().body(BodyInserters.fromValue(customer)));
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Mono&lt;ServerResponse&gt; <span class="hljs-title">updateCustomer</span><span class="hljs-params">(ServerRequest serverRequest)</span> </span>{
        String customerId = serverRequest.pathVariable(<span class="hljs-string">"customerId"</span>);

        <span class="hljs-keyword">return</span> serverRequest.bodyToMono(Customer<span class="hljs-class">.<span class="hljs-keyword">class</span>)
                .<span class="hljs-title">flatMap</span>(<span class="hljs-title">customer</span> -&gt; <span class="hljs-title">customerRepository</span>.<span class="hljs-title">updateCustomer</span>(<span class="hljs-title">customerId</span>, <span class="hljs-title">customer</span>))
                .<span class="hljs-title">flatMap</span>(<span class="hljs-title">customer</span> -&gt; <span class="hljs-title">ServerResponse</span>.<span class="hljs-title">ok</span>().<span class="hljs-title">build</span>())</span>;
    }
}</code></div><small class="shcb-language" id="shcb-language-54"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h3>4.3 REST API Webflux Routes</h3>



<p>Finally we glue everything up using Routes.java. In this class we utilize Spring Webflux RouterFunctions to define the route endpoints for Customer REST API. </p>



<p>We defined a bunch of methods using GET, PUT, POST, DELETE methods in Spring Webflux RouterFunctions and invoked appropriate CustomerService methods.   </p>



<p>Routes.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-55" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootwebfluxdynamodb;

<span class="hljs-keyword">import</span> net.viralpatel.springbootwebfluxdynamodb.customer.CustomerService;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;
<span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;
<span class="hljs-keyword">import</span> org.springframework.web.reactive.function.server.RouterFunction;
<span class="hljs-keyword">import</span> org.springframework.web.reactive.function.server.ServerResponse;

<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> org.springframework.web.reactive.function.server.RequestPredicates.*;
<span class="hljs-keyword">import</span> <span class="hljs-keyword">static</span> org.springframework.web.reactive.function.server.RouterFunctions.route;

<span class="hljs-meta">@Configuration</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Routes</span> </span>{

    <span class="hljs-keyword">private</span> CustomerService customerService;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Routes</span><span class="hljs-params">(CustomerService customerService)</span> </span>{
        <span class="hljs-keyword">this</span>.customerService = customerService;
    }

    <span class="hljs-meta">@Bean</span>
    <span class="hljs-function">RouterFunction&lt;ServerResponse&gt; <span class="hljs-title">customers</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">return</span> route(GET(<span class="hljs-string">"/customers"</span>), customerService::listCustomers)
                .andRoute(POST(<span class="hljs-string">"/customers"</span>), customerService::createCustomer)
                .andRoute(GET(<span class="hljs-string">"/customers/{customerId}"</span>), customerService::getCustomer)
                .andRoute(PUT(<span class="hljs-string">"/customers/{customerId}"</span>), customerService::updateCustomer)
                .andRoute(DELETE(<span class="hljs-string">"/customers/{customerId}"</span>), customerService::deleteCustomer);
    }
}</code></div><small class="shcb-language" id="shcb-language-55"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h2>That&#8217;s All Folks</h2>



<p>Build and execute the project using Gradle.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-56" data-shcb-language-name="Shell Session" data-shcb-language-slug="shell"><div><code class="hljs language-shell"><span class="hljs-meta">$</span><span class="bash"> ./gradlew bootRun</span></code></div><small class="shcb-language" id="shcb-language-56"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Shell Session</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">shell</span><span class="shcb-language__paren">)</span></small></pre>


<p>Make sure your local instance of DynamoDB is up and running and customers table is created before starting the project. If everything is setup correctly, the customer API should be able to communicate with DynamoDB. </p>



<p>Open Postman and fire up the APIs.</p>



<p><strong>Create new customer</strong></p>



<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2019/12/postman-create-customer-api-dynamodb-webflux.png" alt="Create Customer REST API Webflux DynamoDB"/></figure>



<p><strong>List all customers</strong></p>



<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2019/12/postman-list-customers-api-dynamodb-webflux.png" alt="List Customers REST API Webflux DynamoDB"/></figure>



<h2>Download &#8211; Spring Boot Webflux DynamoDB example</h2>



<p>Source code of this project is available on Github.</p>



<p>Github &#8211; <a href="https://github.com/viralpatel/spring-boot-webflux-dynamodb">spring-boot-webflux-dynamodb</a></p>



<h2>Further Reading</h2>



<ul><li><a href="https://www.viralpatel.net/spring-boot-jsp-hello-world-example/">Spring Boot JSP Example</a></li><li><a href="https://www.viralpatel.net/spring-boot-custom-favicon-example/">Spring Boot Custom Favicon Example</a></li></ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/spring-boot-webflux-dynamodb/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Basic Authentication in Spring WebClient</title>
		<link>https://www.viralpatel.net/basic-authentication-spring-webclient/</link>
					<comments>https://www.viralpatel.net/basic-authentication-spring-webclient/#respond</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Tue, 30 Jul 2019 00:46:47 +0000</pubDate>
				<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3725</guid>

					<description><![CDATA[In this short post we will see how to setup Basic Authentication in Spring WebClient while invoking external APIs. Overview WebClient is a non-blocking HTTP client with fluent functional style API. It is part&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<p>In this short post we will see how to setup Basic Authentication in Spring WebClient while invoking external APIs.</p>



<h2>Overview</h2>



<p>WebClient is a non-blocking HTTP client with fluent functional style API. It is part of Spring Webflux module that was introduced in Spring 5. <code>WebClient</code> replaces the <code>RestTemplate</code> to invoke external APIs with non-blocking. </p>



<p>WebClient provides different ways of injecting HTTP headers, query params etc while making external call. In this example we will check how to specify Basic Authentication in Webclient.</p>



<h2>Basic Authentication in WebClient</h2>



<p>Until Spring 5.1, basic authentication was setup using a custom ExchangeFilterFunction. This way of setting up Basic auth was only available while creating WebClient since it relies on WebClient filters. </p>


<pre class="wp-block-code" aria-describedby="shcb-language-57" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">private</span> WebClient client = WebClient.builder()
            .filter(ExchangeFilterFunctions
                .basicAuthentication(username, token))
            .build();</code></div><small class="shcb-language" id="shcb-language-57"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Alternatively if we want to provide the Basic auth while calling the API, we have to set the Authorization header manually which is not great!</p>


<pre class="wp-block-code" aria-describedby="shcb-language-58" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java">webClient.get()
            .uri(<span class="hljs-string">"/customers"</span>)
            .header(<span class="hljs-string">"Authorization"</span>, <span class="hljs-string">"Basic "</span> + Base64Utils
                    .encodeToString((username + <span class="hljs-string">":"</span> + token).getBytes(UTF_8)))
            .retrieve()
            .bodyToFlux(String<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;</code></div><small class="shcb-language" id="shcb-language-58"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Thankfully, Spring provided some helper methods to make this easy and consistent in Spring 5.1.</p>



<h2>Basic Authentication in Spring 5.1 and above</h2>



<p>The above way of setting Basic authentication using custom ExchangeFilterFunction is deprecated in Spring 5.1. A new method <code>setBasicAuth</code> is introduced in <code>HttpHeaders</code> class that can be used to set basic authentication.</p>



<p>Below we set use <code>defaultHeaders</code> in WebClient builder to setup Basic auth while creating WebClient instance:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-59" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">private</span> WebClient client = WebClient.builder()
            .defaultHeaders(header -&gt; header.setBasicAuth(userName, password))
            .build();</code></div><small class="shcb-language" id="shcb-language-59"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Alternately the basic auth can also be setup while calling any API:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-60" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java">Mono&lt;String&gt; response = client.get()
                    .url(<span class="hljs-string">"/customers"</span>)
                    .headers(headers -&gt; headers.setBasicAuth(userName, password))
                    .retrieve()
                    .bodyToFlux(String<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;</code></div><small class="shcb-language" id="shcb-language-60"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Two variants of <code>setBasicAuth</code> methods are available in HttpHeaders.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-61" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-function"><span class="hljs-keyword">void</span>    <span class="hljs-title">setBasicAuth</span><span class="hljs-params">(String username, String password)</span>
        <span class="hljs-comment">//Set the value of the Authorization header to Basic Authentication based on the given username and password.</span>

<span class="hljs-keyword">void</span>    <span class="hljs-title">setBasicAuth</span><span class="hljs-params">(String username, String password, Charset charset)</span>
        <span class="hljs-comment">//Set the value of the Authorization header to Basic Authentication based on the given username and password.</span></span></code></div><small class="shcb-language" id="shcb-language-61"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h3>Bonus tip &#8211; Setting Bearer Token in WebClient</h3>



<p>Similar to Basic Auth, we can also setup the Bearer token in WebClient using new method <code>setBearerAuth</code> in <code>HttpHeaders</code> class:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-62" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-function"><span class="hljs-keyword">void</span>    <span class="hljs-title">setBearerAuth</span><span class="hljs-params">(String token)</span>
        <span class="hljs-comment">//Set the value of the Authorization header to the given Bearer token.</span></span></code></div><small class="shcb-language" id="shcb-language-62"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>The process would be exactly similar to setting up the Basic Auth.</p>



<h2>Conclusion</h2>



<p>The <code>setBasicAuth</code> method in HttpHeaders class makes it easy setting up basic authentication in WebClient Spring WebFlux. The Basic Auth can be setup while building the WebClient or alternatively during invoking APIs using <code>get()</code>, <code>post()</code> etc.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/basic-authentication-spring-webclient/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Getting Started with GraphQL and Spring Boot</title>
		<link>https://www.viralpatel.net/graphql-spring-boot-tutorial/</link>
					<comments>https://www.viralpatel.net/graphql-spring-boot-tutorial/#comments</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Thu, 25 Jul 2019 06:56:10 +0000</pubDate>
				<category><![CDATA[GraphQL]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<guid isPermaLink="false">http://www.viralpatel.net/?p=3719</guid>

					<description><![CDATA[1. Overview Let&#8217;s get started with GraphQL in Spring Boot application. In this app we will try mimicking simple Shopping cart application with Customers, Orders and some Products. The app would give us an&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2019/07/graphql-spring-boot-logo.png" alt="GraphQL Spring Boot Tutorial"/></figure>



<h2>1. Overview</h2>



<p>Let&#8217;s get started with GraphQL in Spring Boot application. In this app we will try mimicking simple Shopping cart application with Customers, Orders and some Products. The app would give us an overview of how to add GraphQL support to Spring Boot using GraphQL Java Tools and GraphQL Spring Boot starter.</p>



<p>Before we deep dive into code, let&#8217;s have an overview of GraphQL.</p>



<h2>2. Introduction to GraphQL</h2>



<p>Facebook opened source GraphQL in 2015 and since then it has been on a roll. There is tremendous amount of adoption from Tech companies such as Github, Shopify, Airbnb etc. Since GraphQL is just a specification, open source community has been busy writing tools and support for GraphQL in all possible known languages. </p>



<p>GraphQL provides clients to specify the fields they want in the API request and server response will only contain those fields. This solves the problem of <em>underfetching</em> or <em>overfetching</em> that REST has. Clients are in power here and based on the user experience they can fetch as much or as little information they want. </p>



<p>GraphQL is <em>schema driven</em>, meaning we need to first design the schema for our API. The schema act as both contract between the client and server and also documentation for our business domain. I think this <em>design first</em> principle gives GraphQL an edge over REST. Swagger, RAML, JSONSchema tries to elevate some of these pain points, however since they are not mandatory most of the API design lack some sort of documentation.</p>



<h3>2.1 Overview of GraphQL Schema</h3>



<p>Schema design is the first thing we would look at. GraphQL schema are typed meaning we need to specify the types and attributes of each type. </p>



<figure class="wp-block-table"><table><thead><tr><th>GraphQL type</th><th>Description</th></tr></thead><tbody><tr><td>Query</td><td>Is used for fetching information. Similar to <code>GET</code> method.</td></tr><tr><td>Mutation</td><td>Is used for inserting, updating or deleting information. Similar to <code>POST</code>, <code>PUT</code> or <code>PATCH</code> methods in REST.</td></tr><tr><td>Subscription</td><td>Is used for streaming the information from server similar to Websocket</td></tr></tbody></table></figure>



<p>For this GraphQL Spring Boot tutorial, subscription will be out of scope. We will tackle that beast in another tutorial :-)</p>



<p>Let&#8217;s create the graphql schema. There are 3 graphql types for this app: <code>Customer</code>, <code>Product</code> and <code>Order</code>. Each type has a few attributes:</p>



<figure class="wp-block-image"><img src="https://www.viralpatel.net/app/uploads/2019/07/graphql-erd-spring-boot.svg" alt="GraphQL Spring Boot Schema Design"/></figure>



<p>We will shortly see how to write GraphQL schema in SDL (schema definition language).</p>



<h2>3. GraphQL support in Spring Boot</h2>



<p>The next step would be to create Spring Boot app with GraphQL support. Let us scaffold the app using <a href="https://start.spring.io">start.spring.io</a>. We will be using following settings for Spring Initilizer.</p>



<ol><li>Gradle project</li><li>Java 11</li><li>Spring Boot 2.1.6</li><li>Group: <code>net.viralpatel</code> Artifact: <code>spring-boot-graphql-tutorial</code>.</li><li>Dependencies: <code>Spring Data JPA</code></li></ol>



<p>Download the generated source code and open it in Intellij or Eclipse.</p>



<h3>3.1 GraphQL dependencies</h3>



<p>Let us add GraphQL Java and other dependencies in Gradle. Open <code>build.gradle</code> file and add following code:</p>



<p>build.gradle</p>


<pre class="wp-block-code" aria-describedby="shcb-language-63" data-shcb-language-name="JavaScript" data-shcb-language-slug="javascript"><div><code class="hljs language-javascript">plugins {
    id <span class="hljs-string">'org.springframework.boot'</span> version <span class="hljs-string">'2.1.6.RELEASE'</span>
    id <span class="hljs-string">'java'</span>
}

apply plugin: <span class="hljs-string">'io.spring.dependency-management'</span>
group = <span class="hljs-string">'net.viralpatel'</span>
version = <span class="hljs-string">'0.0.1-SNAPSHOT'</span>
sourceCompatibility = <span class="hljs-string">'11'</span>

repositories {
    mavenCentral()
}

dependencies {
    implementation <span class="hljs-string">'org.springframework.boot:spring-boot-starter-data-jpa'</span>
    implementation <span class="hljs-string">'com.h2database:h2'</span>

    implementation <span class="hljs-string">'com.graphql-java-kickstart:graphql-spring-boot-starter:5.9.0'</span>
    implementation <span class="hljs-string">'com.graphql-java-kickstart:graphql-java-tools:5.6.0'</span>
    implementation <span class="hljs-string">'com.graphql-java-kickstart:graphiql-spring-boot-starter:5.9.0'</span>

    testImplementation <span class="hljs-string">'org.springframework.boot:spring-boot-starter-test'</span>
}</code></div><small class="shcb-language" id="shcb-language-63"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JavaScript</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">javascript</span><span class="shcb-language__paren">)</span></small></pre>


<p>We are adding following dependencies:</p>



<ol><li><code>spring-data-jpa</code> and <code>h2</code> for creating data repositories to store customers, products and orders.</li><li><code>graphql-spring-boot-starter</code> for adding GraphQL Java support with Spring Boot.    </li><li><code>graphql-java-tools</code> is schema first tool inspired from <a href="https://github.com/apollographql/graphql-tools">GraphQL Tool for JS</a> which let us design the schema first and generate all boilerplate graphql java configuration.</li><li><code>graphiql-spring-boot-starter</code> adds support for GraphiQL (notice the extra &#8216;i&#8217;). GraphiQL provides nice editor to query and introspect GraphQL API.</li></ol>



<p>Since we are using <a href="https://github.com/graphql-java-kickstart/graphql-spring-boot">GraphQL Java Spring Boot</a>, we need to fix the kotlin version to 1.3.10. </p>



<p>Create gradle.properties file and add following code in it.</p>



<p>gradle.properties</p>


<pre class="wp-block-code"><div><code class="hljs">kotlin.version = 1.3.10</code></div></pre>


<h3>3.2 GraphQL Schema SDL</h3>



<p>The GraphQL schema can be written using GraphQL SDL (Schema Definition Language). Following is our app&#8217;s GraphQL schema.</p>



<p>Schema definition file is under <code>src/resources</code> directory. GraphQL Spring Boot starter will read this and configure it using graphql-java-tools. </p>



<p>src/resources/schema.graphqls</p>


<pre class="wp-block-code" aria-describedby="shcb-language-64" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json">type Query {
    customerById(id: ID!): Customer
}

type Customer {
    id: ID!
    name: String!
    email: String!
    orders: [Order]
}

type Order {
    id: ID!
    customer: Customer!
    product: Product!
    quantity: Int!
    status: String!
}

type Product {
    id: ID!
    name: String
    description: String
    price: String
}</code></div><small class="shcb-language" id="shcb-language-64"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<h3>3.3 Java POJOs for GraphQL</h3>



<p>Next we create POJOs for each graphql type: <code>Customer</code>, <code>Product</code> and <code>Order</code>. </p>



<p>Customer.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-65" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqljava.customers;

<span class="hljs-keyword">import</span> net.viralpatel.springbootgraphqljava.orders.Order;
<span class="hljs-keyword">import</span> java.util.List;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> </span>{
    <span class="hljs-keyword">private</span> Long id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> String email;
    <span class="hljs-keyword">private</span> List&lt;Order&gt; orders;

    <span class="hljs-comment">// getters and setters</span>
}</code></div><small class="shcb-language" id="shcb-language-65"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Order.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-66" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqljava.orders;

<span class="hljs-keyword">import</span> net.viralpatel.springbootgraphqljava.customers.Customer;
<span class="hljs-keyword">import</span> net.viralpatel.springbootgraphqljava.products.Product;

<span class="hljs-keyword">import</span> java.time.LocalDate;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> </span>{
    <span class="hljs-keyword">private</span> Long id;
    <span class="hljs-keyword">private</span> Customer customer;
    <span class="hljs-keyword">private</span> Product product;
    <span class="hljs-keyword">private</span> Integer quantity;
    <span class="hljs-keyword">private</span> String status;
    <span class="hljs-keyword">private</span> LocalDate created;

    <span class="hljs-comment">// getters and setters</span>
}</code></div><small class="shcb-language" id="shcb-language-66"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Product.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-67" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqljava.products;

<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span> </span>{
    <span class="hljs-keyword">private</span> Long id;
    <span class="hljs-keyword">private</span> String name;
    <span class="hljs-keyword">private</span> String description;
    <span class="hljs-keyword">private</span> Double price;

    <span class="hljs-comment">// getters and setters</span>
}</code></div><small class="shcb-language" id="shcb-language-67"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h3>3.4 GraphQL Query Resolvers</h3>



<p>Once we defined the POJOs for our GraphQL schema we need to define the Resolvers. Resolvers are core to GraphQL. Each resolver is responsible for fetching/retrieving data for any given type and its attribute. Let us start with the root resolver. Remember Query is the root which exposes <code>customerById</code>.  </p>



<p>QueryResolver.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-68" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqljava;

<span class="hljs-keyword">import</span> com.coxautodev.graphql.tools.GraphQLQueryResolver;

<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">QueryResolver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">GraphQLQueryResolver</span> </span>{

    <span class="hljs-keyword">private</span> CustomerRepository customerRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">QueryResolver</span><span class="hljs-params">(CustomerRepository customerRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.customerRepository = customerRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Customer <span class="hljs-title">customerById</span><span class="hljs-params">(Long id)</span> </span>{
        <span class="hljs-keyword">return</span> customerRepository
                .findById(id)
                .orElse(<span class="hljs-keyword">null</span>);
    }
}</code></div><small class="shcb-language" id="shcb-language-68"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Notice how we implemented <code>GraphQLQueryResolver</code> interface. This would let GraphQL Java knows we are intending to use this as root resolver for Query. </p>



<p>QueryResolver exposes a public method <code>customerById</code> which takes Id as input and returns the customer object. Notice we using Spring Data JPA to load the customer record from our database. I have skipped some of the code related to mapping Spring Data model to GraphQL Pojo for simplicity. You can check the full source code in Github repository.</p>



<p>Next we create custom resolvers for each type. </p>



<p>CustomerResolver.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-69" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqljava.customers;

<span class="hljs-keyword">import</span> com.coxautodev.graphql.tools.GraphQLResolver;

<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">CustomerResolver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">GraphQLResolver</span>&lt;<span class="hljs-title">Customer</span>&gt; </span>{

    <span class="hljs-keyword">private</span> OrderRepository orderRepository;

    <span class="hljs-meta">@Autowired</span>
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomerResolver</span><span class="hljs-params">(OrderRepository orderRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.orderRepository = orderRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Order&gt; <span class="hljs-title">orders</span><span class="hljs-params">(Customer customer)</span> </span>{
        <span class="hljs-keyword">return</span> orderRepository.findByCustomerId(customer.getId())
                .stream()
                .collect(Collectors.toList());
    }
}</code></div><small class="shcb-language" id="shcb-language-69"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Notice how we implemented <code>GraphQLResolver&lt;T&gt;</code> interface for <code>Customer</code> class. GraphQL Java tools would identify this as resolver for Customer class. Here we implement a method <code>orders()</code> that GraphQL would call when it wants to resolve all orders for given customer.</p>



<p>Also notice these resolvers are annotated as Spring <code>@Components</code>. Hence we can inject any Spring bean in the resolvers.</p>



<p>OrderResolver.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-70" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqljava.orders;

<span class="hljs-keyword">import</span> com.coxautodev.graphql.tools.GraphQLResolver;

<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">OrderResolver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">GraphQLResolver</span>&lt;<span class="hljs-title">Order</span>&gt; </span>{

    <span class="hljs-keyword">private</span> ProductRepository productRepository;
    <span class="hljs-keyword">private</span> CustomerRepository customerRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OrderResolver</span><span class="hljs-params">(ProductRepository productRepository, CustomerRepository customerRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.productRepository = productRepository;
        <span class="hljs-keyword">this</span>.customerRepository = customerRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Customer <span class="hljs-title">customer</span><span class="hljs-params">(Order order)</span> </span>{
        <span class="hljs-keyword">return</span> customerRepository
                .findById(order.getCustomer().getId())
                .orElse(<span class="hljs-keyword">null</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Product <span class="hljs-title">product</span><span class="hljs-params">(Order order)</span> </span>{
        <span class="hljs-keyword">return</span> productRepository
                .findById(order.getProduct().getId())
                .orElse(<span class="hljs-keyword">null</span>);
    }
}</code></div><small class="shcb-language" id="shcb-language-70"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Last but not least, the <code>OrderResolver</code> will resolve the attributes for Order type. Each order has customer and product attribute which resolve by querying appropriate Spring Data repositories.</p>



<h3>3.5 GraphQL Mutation Resolvers</h3>



<p>Next up is the mutations. Mutation are nothing but a way of altering the data in GraphQL API. Like <code>Query</code>, <code>Mutation</code> is also a top-level type.</p>



<p>Let&#8217;s define following mutation type in schema.graphqls</p>


<pre class="wp-block-code" aria-describedby="shcb-language-71" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json">type Mutation {
    createOrder(order: CreateOrderInput!): Order!
}

input CreateOrderInput {
    customerId: ID!
    productId: ID!
    quantity: Int!
}</code></div><small class="shcb-language" id="shcb-language-71"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<p>We have added method <code>createOrder</code> within Mutation type. Also note that the order parameter is of type <code>CreateOrderInput</code>. Input type is another type used specifically in mutation.</p>



<p>Input types can&#8217;t have fields that are other objects, only basic scalar types, list types, and other input types.</p>



<p>Once the mutation schema is defined, we can declare class <code>OrderMutationResolver</code> implementing <code>GraphQLMutationResolver</code> interface to handle <code>createOrder</code> mutation.</p>



<p>OrderMutationResolver.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-72" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootgraphqljava.orders;

<span class="hljs-keyword">import</span> com.coxautodev.graphql.tools.GraphQLMutationResolver;

<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">OrderMutationResolver</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">GraphQLMutationResolver</span> </span>{

    <span class="hljs-keyword">private</span> OrderRepository orderRepository;

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">OrderMutationResolver</span><span class="hljs-params">(OrderRepository orderRepository)</span> </span>{
        <span class="hljs-keyword">this</span>.orderRepository = orderRepository;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> Order <span class="hljs-title">createOrder</span><span class="hljs-params">(CreateOrderInput createOrderInput)</span> </span>{
        Order order = <span class="hljs-keyword">new</span> Order();

        order.setCustomerId(createOrderInput.getCustomerId());
        order.setProductId(createOrderInput.getProductId());
        order.setQuantity(createOrderInput.getQuantity());
        order.setStatus(<span class="hljs-string">"PENDING"</span>);
        orderRepository.save(order);

        <span class="hljs-keyword">return</span> order;
    }
}</code></div><small class="shcb-language" id="shcb-language-72"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>The createOrder method creates a new order using OrderRepository and returns the object.</p>



<h2>4. Build and run</h2>



<p>Start the Spring Boot application by running <code>SpringBootGraphqlJavaApplication</code> class or by running gradle:</p>


<pre class="wp-block-code" aria-describedby="shcb-language-73" data-shcb-language-name="Bash" data-shcb-language-slug="bash"><div><code class="hljs language-bash">./gradlew bootRun</code></div><small class="shcb-language" id="shcb-language-73"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Bash</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">bash</span><span class="shcb-language__paren">)</span></small></pre>


<h3>4.1 Introspecting using GraphiQL</h3>



<p>Once the Spring Boot app is started on default port 8080, open http://localhost:8080/graphiql</p>



<p>Try running following GraphQL query and see the output.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-74" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json">query {
  customerById(id: <span class="hljs-number">1</span>) {
    name
    orders {
      id
      status
      product {
        name
      }
    }
  }
}</code></div><small class="shcb-language" id="shcb-language-74"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<p>Also run following mutation query to create a new order.</p>


<pre class="wp-block-code" aria-describedby="shcb-language-75" data-shcb-language-name="JSON / JSON with Comments" data-shcb-language-slug="json"><div><code class="hljs language-json">mutation {
  createOrder(order: {
    customerId: <span class="hljs-number">1</span>
    productId: <span class="hljs-number">1</span>
    quantity:<span class="hljs-number">4</span>
  }) {
    id
    status
  }
}</code></div><small class="shcb-language" id="shcb-language-75"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">JSON / JSON with Comments</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">json</span><span class="shcb-language__paren">)</span></small></pre>


<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<div class="video-container"><iframe title="GraphQL Spring Boot Java Demo" width="720" height="405" src="https://www.youtube.com/embed/Uhc1qIzwESA?feature=oembed&#038;wmode=opaque" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></div>
</div></figure>



<h2>5. Download</h2>



<p>The project is available on Github. </p>



<p>Github &#8211; <a href="https://github.com/viralpatel/spring-boot-graphql-java">Spring Boot GraphQL Java</a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/graphql-spring-boot-tutorial/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Spring Boot FreeMarker Tutorial with Example</title>
		<link>https://www.viralpatel.net/spring-boot-freemarker-tutorial-with-example/</link>
					<comments>https://www.viralpatel.net/spring-boot-freemarker-tutorial-with-example/#respond</comments>
		
		<dc:creator><![CDATA[Viral Patel]]></dc:creator>
		<pubDate>Mon, 15 Jul 2019 01:12:00 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Freemarker]]></category>
		<category><![CDATA[spring mvc]]></category>
		<guid isPermaLink="false">http://viralpatel.net/?p=3515</guid>

					<description><![CDATA[Spring Boot FreeMarker Hello World Tutorial &#8211; Getting started with FreeMarker templates in Spring Boot is super easy. Spring Boot&#8217;s auto-configuration (spring starters) speeds up integrating any new tech in any Spring based project.&#46;&#46;&#46;]]></description>
										<content:encoded><![CDATA[
<p><strong>Spring Boot FreeMarker Hello World Tutorial</strong> &#8211; Getting started with FreeMarker templates in Spring Boot is super easy. Spring Boot&#8217;s auto-configuration (spring starters) speeds up integrating any new tech in any Spring based project. In this tutorial we will learn Spring Boot and FreeMarker integration and create a hello world app.</p>



<p>This Spring Boot app will show a form to capture user input (name, email and date of birth). Show some default values in the table using Freemarker and allow the user to delete the entries from the table. Nothing fancy, the basic stuff.</p>



<p>For this project we will use following technologies:</p>



<ul><li>Spring Boot 2.1.6</li><li>Java 8 (Can also be compiled with Java 11)</li><li>Maven</li></ul>



<div class="wp-block-image"><figure class="aligncenter"><img width="457" height="384" src="https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-example-project-structure.png" alt="spring boot freemarker example project structure" class="wp-image-3517" srcset="https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-example-project-structure.png 457w, https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-example-project-structure-300x252.png 300w" sizes="(max-width: 457px) 100vw, 457px" /></figure></div>



<h2>1. Maven dependencies for Spring Boot with FreeMarker</h2>



<p>The directory structure is like that of standard Spring Boot project. You could generate this using Spring Initializer (<a href="https://start.spring.io/">start.spring.io</a>) or just clone this repository. Note that we include the <code>spring-boot-starter-freemarker</code> to auto configure Freemarker view for Spring Boot web project.</p>



<p>pom.xml</p>


<pre class="wp-block-code" aria-describedby="shcb-language-76" data-shcb-language-name="HTML, XML" data-shcb-language-slug="xml"><div><code class="hljs language-xml"><span class="hljs-meta">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">project</span> <span class="hljs-attr">xmlns</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0"</span> <span class="hljs-attr">xmlns:xsi</span>=<span class="hljs-string">"http://www.w3.org/2001/XMLSchema-instance"</span>
         <span class="hljs-attr">xsi:schemaLocation</span>=<span class="hljs-string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">modelVersion</span>&gt;</span>4.0.0<span class="hljs-tag">&lt;/<span class="hljs-name">modelVersion</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">groupId</span>&gt;</span>net.viralpatel<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-freemarker-example<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.0.1-SNAPSHOT<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">packaging</span>&gt;</span>jar<span class="hljs-tag">&lt;/<span class="hljs-name">packaging</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">name</span>&gt;</span>spring-boot-freemarker-example<span class="hljs-tag">&lt;/<span class="hljs-name">name</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">description</span>&gt;</span>Spring Boot FreeMarker (FTL) Hello World example<span class="hljs-tag">&lt;/<span class="hljs-name">description</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">parent</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-parent<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.1.6.RELEASE<span class="hljs-tag">&lt;/<span class="hljs-name">version</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">relativePath</span>/&gt;</span> <span class="hljs-comment">&lt;!-- lookup parent from repository --&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">parent</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">properties</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">java.version</span>&gt;</span>1.8<span class="hljs-tag">&lt;/<span class="hljs-name">java.version</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">properties</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">dependencies</span>&gt;</span>
        <span class="hljs-comment">&lt;!-- Compile --&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-freemarker<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-web<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;!-- Test --&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-test<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>test<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-tag">&lt;/<span class="hljs-name">dependencies</span>&gt;</span>

    <span class="hljs-tag">&lt;<span class="hljs-name">build</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">plugins</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">plugin</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-maven-plugin<span class="hljs-tag">&lt;/<span class="hljs-name">artifactId</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">plugin</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">plugins</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">build</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">project</span>&gt;</span></code></div><small class="shcb-language" id="shcb-language-76"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">HTML, XML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">xml</span><span class="shcb-language__paren">)</span></small></pre>


<h2>2. Spring Boot Application Class</h2>



<p>The Spring Boot application class is the standard one. The Spring Boot Jar project to bootstrap the server and configure default beans. The <code>@SpringBootApplication</code> is a convenient annotation that wraps <code>@Configuration</code>,&nbsp;<code>@EnableAutoConfiguration</code>&nbsp;and&nbsp;<code>@ComponentScan</code>. </p>



<p>SpringBootFreemarkerExampleApplication.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-77" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootfreemarkerexample;

<span class="hljs-keyword">import</span> org.springframework.boot.SpringApplication;
<span class="hljs-keyword">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;


<span class="hljs-meta">@SpringBootApplication</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SpringBootFreemarkerExampleApplication</span> </span>{

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">main</span><span class="hljs-params">(String[] args)</span> </span>{
		SpringApplication.run(SpringBootFreemarkerExampleApplication<span class="hljs-class">.<span class="hljs-keyword">class</span>, <span class="hljs-title">args</span>)</span>;
	}
}</code></div><small class="shcb-language" id="shcb-language-77"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h2>Model and Controller &#8211; Spring Boot with FreeMarker</h2>



<p>Let&#8217;s start with a simple Customer pojo class which contains attributes customerId, customerName, dateOfBirth and email. Also let us add constructor, getter and setter methods. </p>



<p>Customer.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-78" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootfreemarkerexample;

<span class="hljs-keyword">import</span> java.time.LocalDate;

<span class="hljs-keyword">import</span> org.springframework.format.annotation.DateTimeFormat;

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

	<span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> customerId;
	<span class="hljs-keyword">private</span> String customerName;

	<span class="hljs-meta">@DateTimeFormat</span>(iso = DateTimeFormat.ISO.DATE)
	<span class="hljs-keyword">private</span> LocalDate dateOfBirth;
	<span class="hljs-keyword">private</span> String email;

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

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">Customer</span><span class="hljs-params">(<span class="hljs-keyword">int</span> customerId, String customerName, String email, LocalDate dateOfBirth)</span> </span>{
		<span class="hljs-keyword">super</span>();
		<span class="hljs-keyword">this</span>.customerId = customerId;
		<span class="hljs-keyword">this</span>.customerName = customerName;
		<span class="hljs-keyword">this</span>.dateOfBirth = dateOfBirth;
		<span class="hljs-keyword">this</span>.email = email;
	}

	<span class="hljs-comment">// Getter and setters</span>
}</code></div><small class="shcb-language" id="shcb-language-78"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<p>Now let us check the CustomerController class. Again, its the standard Spring MVC Controller defined using <code>@Controller</code> annotation. This class defines methods <code>index()</code>, <code>add()</code> and <code>delete()</code> which are mapped to /, /add and /delete urls respectively.  Note that we are using <code>@GetMapping</code> annotation to map these urls.</p>



<p>Note that in index() method, we return the &#8220;index&#8221; string. This would render index.ftl freemarker template which we will soon create. Also the @ModelAttribute annotation in index() method binds the modelmap which we can use to pass back the values to freemarker template. </p>



<p>CustomerController.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-79" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootfreemarkerexample;

<span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;
<span class="hljs-keyword">import</span> org.springframework.stereotype.Controller;
<span class="hljs-keyword">import</span> org.springframework.ui.ModelMap;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.GetMapping;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.ModelAttribute;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.PathVariable;
<span class="hljs-keyword">import</span> org.springframework.web.bind.annotation.PostMapping;

<span class="hljs-meta">@Controller</span>
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomerController</span> </span>{

    <span class="hljs-keyword">private</span> CustomerService customerService;
	
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">CustomerController</span><span class="hljs-params">(CustomerService customerService)</span> </span>{
        <span class="hljs-keyword">this</span>.customerService = customerService;
    }

    <span class="hljs-meta">@GetMapping</span>(<span class="hljs-string">"/"</span>)
	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">index</span><span class="hljs-params">(@ModelAttribute(<span class="hljs-string">"model"</span>)</span> ModelMap model) </span>{
		model.addAttribute(<span class="hljs-string">"customers"</span>, customerService.findAll());
		<span class="hljs-keyword">return</span> <span class="hljs-string">"index"</span>;
	}

	<span class="hljs-meta">@PostMapping</span>(<span class="hljs-string">"/add"</span>)
	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">add</span><span class="hljs-params">(Customer customer)</span> </span>{
		customerService.add(customer);
		<span class="hljs-keyword">return</span> <span class="hljs-string">"redirect:/"</span>;
	}

	<span class="hljs-meta">@GetMapping</span>(<span class="hljs-string">"/delete/{customerId}"</span>)
	<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">delete</span><span class="hljs-params">(@PathVariable <span class="hljs-keyword">int</span> customerId)</span> </span>{
		customerService.remove(customerId);
		<span class="hljs-keyword">return</span> <span class="hljs-string">"redirect:/"</span>;
	}
}</code></div><small class="shcb-language" id="shcb-language-79"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h2>Services &#8211; Spring Boot with FreeMarker</h2>



<p>The CustomerService is again standard Spring <code>@Service</code> class. We defined a static List of customers. This is just a temporary local data store to keep list of customers. Ideally we would use a database or an in-memory database. However let us keep things simple for now.</p>



<p>CustomerService.java</p>


<pre class="wp-block-code" aria-describedby="shcb-language-80" data-shcb-language-name="Java" data-shcb-language-slug="java"><div><code class="hljs language-java"><span class="hljs-keyword">package</span> net.viralpatel.springbootfreemarkerexample;

<span class="hljs-keyword">import</span> java.time.LocalDate;
<span class="hljs-keyword">import</span> java.util.ArrayList;
<span class="hljs-keyword">import</span> java.util.List;
<span class="hljs-keyword">import</span> java.util.Optional;
<span class="hljs-keyword">import</span> java.util.Random;

<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-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CustomerService</span> </span>{

	<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> List&lt;Customer&gt; customers = <span class="hljs-keyword">new</span> ArrayList&lt;&gt;();
	<span class="hljs-keyword">static</span> {
		customers.add(<span class="hljs-keyword">new</span> Customer(<span class="hljs-number">101</span>, <span class="hljs-string">"Steve"</span>, <span class="hljs-string">"steve@apple.com"</span>, LocalDate.of(<span class="hljs-number">1955</span>, <span class="hljs-number">2</span>, <span class="hljs-number">24</span>)));
		customers.add(<span class="hljs-keyword">new</span> Customer(<span class="hljs-number">201</span>, <span class="hljs-string">"Bill"</span>, <span class="hljs-string">"bill@microsoft.com"</span>, LocalDate.of(<span class="hljs-number">1955</span>, <span class="hljs-number">10</span>, <span class="hljs-number">28</span>)));
		customers.add(<span class="hljs-keyword">new</span> Customer(<span class="hljs-number">301</span>, <span class="hljs-string">"Larry"</span>, <span class="hljs-string">"larry@gmail.com"</span>, LocalDate.of(<span class="hljs-number">1973</span>, <span class="hljs-number">8</span>, <span class="hljs-number">21</span>)));
		customers.add(<span class="hljs-keyword">new</span> Customer(<span class="hljs-number">401</span>, <span class="hljs-string">"Sergey"</span>, <span class="hljs-string">"sergey@abc.xyz"</span>, LocalDate.of(<span class="hljs-number">1973</span>, <span class="hljs-number">3</span>, <span class="hljs-number">26</span>)));
	}

	<span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Customer&gt; <span class="hljs-title">findAll</span><span class="hljs-params">()</span> </span>{
		<span class="hljs-keyword">return</span> customers;
	}

	<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">add</span><span class="hljs-params">(Customer customer)</span> </span>{
		customer.setCustomerId(generateRandomId());
		customers.add(customer);
	}

	<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">int</span> <span class="hljs-title">generateRandomId</span><span class="hljs-params">()</span> </span>{
		<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Random().nextInt(<span class="hljs-number">1000</span>);
	}

	<span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;Customer&gt; <span class="hljs-title">remove</span><span class="hljs-params">(<span class="hljs-keyword">int</span> customerId)</span> </span>{
		customers.removeIf(c -&gt; c.getCustomerId() == customerId);
		<span class="hljs-keyword">return</span> findAll();
	}

	<span class="hljs-function"><span class="hljs-keyword">public</span> Optional&lt;Customer&gt; <span class="hljs-title">find</span><span class="hljs-params">(<span class="hljs-keyword">int</span> customerId)</span> </span>{
		<span class="hljs-keyword">return</span> customers.stream().filter(c -&gt; c.getCustomerId() == customerId).findFirst();
	}
}</code></div><small class="shcb-language" id="shcb-language-80"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">Java</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">java</span><span class="shcb-language__paren">)</span></small></pre>


<h2>FreeMarker Template or .ftl file</h2>



<p>Finally let us create the freemarker template file to render our view. Create index.ftl file under src/resources folder. This view will render list of customers and a form to add new customer. Note we are using freemarker templates tags <code>&lt;#list&gt;</code> to loop through customers and render them onto our view. </p>



<p>index.ftl</p>


<pre class="wp-block-code" aria-describedby="shcb-language-81" data-shcb-language-name="HTML, XML" data-shcb-language-slug="xml"><div><code class="hljs language-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Spring Boot FreeMarker example - viralpatel.net<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>

<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/bootstrap/4.0.0-beta/css/bootstrap.min.css"</span>
	<span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css">
<span class="hljs-selector-class">.container</span> {
	<span class="hljs-attribute">margin-top</span>: <span class="hljs-number">80px</span>;
}
<span class="hljs-selector-class">.bg-dark</span> {
	<span class="hljs-attribute">background-color</span>: <span class="hljs-number">#3b8dbd</span> <span class="hljs-meta">!important</span>;
}
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar navbar-expand-md navbar-dark bg-dark fixed-top"</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-brand"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://www.viralpatel.net"</span>&gt;</span>Spring Boot
			FreeMarker example - viralpatel.net<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span> <span class="hljs-attr">data-toggle</span>=<span class="hljs-string">"collapse"</span>
			<span class="hljs-attr">data-target</span>=<span class="hljs-string">"#navbarsExampleDefault"</span>
			<span class="hljs-attr">aria-controls</span>=<span class="hljs-string">"navbarsExampleDefault"</span> <span class="hljs-attr">aria-expanded</span>=<span class="hljs-string">"false"</span>
			<span class="hljs-attr">aria-label</span>=<span class="hljs-string">"Toggle navigation"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"navbar-toggler-icon"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span>
	<span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>

		<span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-inline"</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"post"</span> <span class="hljs-attr">action</span>=<span class="hljs-string">"/add"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-name">input</span>
				<span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control mb-2 mr-sm-2 mb-sm-0"</span>
				<span class="hljs-attr">id</span>=<span class="hljs-string">"customerName"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"customerName"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Customer name"</span> /&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-name">input</span>
				<span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>  <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control mb-2 mr-sm-2 mb-sm-0"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span>
				<span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> /&gt;</span> 
				
				
			<span class="hljs-tag">&lt;<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"date"</span>
				 <span class="hljs-attr">class</span>=<span class="hljs-string">"form-control mb-2 mr-sm-2 mb-sm-0"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"dateOfBirth"</span>
				<span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Birthdate"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"dateOfBirth"</span> /&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-primary"</span>&gt;</span>Add<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-name">form</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">table</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"table"</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-name">thead</span>&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>#<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Customer name<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Email<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span>Birthdate<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">th</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
				<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-name">thead</span>&gt;</span>
			<span class="hljs-tag">&lt;<span class="hljs-name">tbody</span>&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-name">#list</span> <span class="hljs-attr">model</span>["<span class="hljs-attr">customers</span>"] <span class="hljs-attr">as</span> <span class="hljs-attr">customer</span>&gt;</span>
				<span class="hljs-tag">&lt;<span class="hljs-name">tr</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">th</span> <span class="hljs-attr">scope</span>=<span class="hljs-string">"row"</span>&gt;</span>${customer.customerId}<span class="hljs-tag">&lt;/<span class="hljs-name">th</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>${customer.customerName}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>${customer.email}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span>${customer.dateOfBirth}<span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
					<span class="hljs-tag">&lt;<span class="hljs-name">td</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"btn btn-sm btn-warning"</span> <span class="hljs-attr">role</span>=<span class="hljs-string">"button"</span>
						<span class="hljs-attr">href</span>=<span class="hljs-string">"/delete/${customer.customerId}"</span>&gt;</span>Delete<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">td</span>&gt;</span>
				<span class="hljs-tag">&lt;/<span class="hljs-name">tr</span>&gt;</span>
				<span class="hljs-tag">&lt;/<span class="hljs-name">#list</span>&gt;</span>
			<span class="hljs-tag">&lt;/<span class="hljs-name">tbody</span>&gt;</span>
		<span class="hljs-tag">&lt;/<span class="hljs-name">table</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">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span></code></div><small class="shcb-language" id="shcb-language-81"><span class="shcb-language__label">Code language:</span> <span class="shcb-language__name">HTML, XML</span> <span class="shcb-language__paren">(</span><span class="shcb-language__slug">xml</span><span class="shcb-language__paren">)</span></small></pre>


<h2>That&#8217;s all folks</h2>



<p>Run the Spring Boot Freemarker example project by running Spring Boot Application class as Java class or using maven&nbsp;<code>.\mvnw.cmd spring-boot:run</code>&nbsp;command in Windows or <code>./mvnw spring-boot:run</code> in Mac and Linux. Once the application starts, launch the browser and open:&nbsp;<code>http://localhost:8080/</code></p>



<div class="wp-block-image"><figure class="aligncenter"><img width="914" height="597" src="https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-tutorial-example-demo.png" alt="spring boot freemarker tutorial example demo" class="wp-image-3516" srcset="https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-tutorial-example-demo.png 914w, https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-tutorial-example-demo-300x196.png 300w, https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-tutorial-example-demo-768x502.png 768w, https://www.viralpatel.net/app/uploads/2017/09/spring-boot-freemarker-tutorial-example-demo-640x418.png 640w" sizes="(max-width: 914px) 100vw, 914px" /></figure></div>



<h2>Download Source Code – Spring Boot FreeMarker example</h2>



<p>Source code of this Spring Boot FreeMarker Hello World tutorial is available on Github.</p>



<p>Github – <a href="https://github.com/viralpatel/spring-boot-tutorials/tree/master/spring-boot-freemarker-example">spring-boot-freemarker-example</a></p>



<p><strong>Also read:</strong></p>



<ul><li><a href="https://www.viralpatel.net/introduction-to-freemarker-template-ftl/">Getting started with Freemarker</a></li><li><a href="https://www.viralpatel.net/spring-boot-jsp-hello-world-example/">Spring Boot &#8211; Getting started</a></li></ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.viralpatel.net/spring-boot-freemarker-tutorial-with-example/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
