<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: sabyasachi</title>
    <description>The latest articles on DEV Community by sabyasachi (@sabyasachi).</description>
    <link>https://dev.to/sabyasachi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F592995%2F8853b273-33d5-420f-9f5f-111a0d8b614d.jpeg</url>
      <title>DEV Community: sabyasachi</title>
      <link>https://dev.to/sabyasachi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sabyasachi"/>
    <language>en</language>
    <item>
      <title>Set up dev environment with Claude Code</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sat, 10 Jan 2026 21:17:24 +0000</pubDate>
      <link>https://dev.to/sabyasachi/set-up-dev-environment-with-claude-code-2pa7</link>
      <guid>https://dev.to/sabyasachi/set-up-dev-environment-with-claude-code-2pa7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Originally published at &lt;a href="https://blog.sabyasachi.io/posts/prep-for-claude/" rel="noopener noreferrer"&gt;https://blog.sabyasachi.io/posts/prep-for-claude/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As the competition for coding agents intensifies, Claude Code seems one of the popular choices. If you are relatively new to the space and thinking about how to get started, here is my two cents after using Claude Code. &lt;/p&gt;

&lt;h3&gt;
  
  
  Prepare the code so that Claude understands its context
&lt;/h3&gt;

&lt;p&gt;To do that generate &lt;code&gt;CLAUDE.md&lt;/code&gt; file in the repo. It is a file that Claude automatically pulls into the context.&lt;br&gt;
   &lt;code&gt;CLAUDE.md&lt;/code&gt; can contain following information - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An overview of what this repo is all about.&lt;/li&gt;
&lt;li&gt;Important files. &lt;/li&gt;
&lt;li&gt;Bash commands, including commands to test and build. &lt;/li&gt;
&lt;li&gt;Formatting styles.
Claude Code comes with an in-built &lt;code&gt;/init&lt;/code&gt; command which generates an initial &lt;code&gt;CLAUDE.md&lt;/code&gt; file after exploring the codebase. Important is to review, add and update this first version to reflect the information about the codebase.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once we have a baseline &lt;code&gt;CLAUDE.md&lt;/code&gt; file, it is important to keep it updated so that changes made to the codebase can be reflected. We can either automate this part by running some job after each main push or make it using human-in-the-loop, so that a reviewer can mark what needs to be added to the md file.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub Access
&lt;/h3&gt;

&lt;p&gt;Considering majority using GitHub, Claude can access GitHub in two ways &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;using &lt;code&gt;gh&lt;/code&gt; CLI.&lt;/li&gt;
&lt;li&gt;using GitHub MCP server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Often the whole truth about the codebase may not be within the same repo. For example it might be using some shared libs which are in different repo. Or we just simply want to search for usage of a certain pattern. Claude Code can use either &lt;code&gt;gh&lt;/code&gt; CLI or MCP server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup MCP servers
&lt;/h3&gt;

&lt;p&gt;MCP servers are what connects the model with the data it requires. I mentioned about GitHub MCP above, additionally I would recommend to use Context7 for documentation of open source libs, so that Claude can look into the documentation if required. The exact set of MCP is dependent on what you are actually building. In my context who is writing microservices using Java and AWS, my go-to MCP servers are &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GitHub&lt;/li&gt;
&lt;li&gt;Context7&lt;/li&gt;
&lt;li&gt;AWS knowledge MCP
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Some MCP servers can bring too many tools or tool output, which can take up a significant chunk of the context window. GitHub is one of the MCP servers where tool surface area can get big.
  See the https://github.com/github/github-mcp-server/issues/1286
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally MCPs can bring security concerns. Fundamentally, once connected, Claude Code can call whatever tools the server exposes. Make sure to add only well-known, official servers, and use allowlists/denylists and MCP permissions where possible. Also note that project-scoped MCP servers live in &lt;code&gt;.mcp.json&lt;/code&gt; and Claude Code prompts for approval before using them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sub-Agents, Commands, Skills
&lt;/h3&gt;

&lt;p&gt;At this point you have a repo with necessary &lt;code&gt;CLAUDE.md&lt;/code&gt; file and you may have added a few MCP servers. You are already on good fundamentals. Claude can produce better results, from this section onwards we move into more powerful constructs of Claude which will take the experience into next level.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Sub-Agents - Claude Code already runs a main agent loop. Sub-Agents are custom agents for specific workflow. For example, as developer once the feature development is done we can create a &lt;code&gt;code-review&lt;/code&gt; sub agent which does a first phase of check before sending out the PR, or maybe a sub agent which fixes trivial bugs or update dependencies. Sub agents starts with a clean context so this can also be seen as extension of the main context. Sub agents can use tools coming from MCP servers. Claude Code can use a specific agent based on the agent description and context, otherwise we can mention to Claude Code to use the sub agent. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Commands - Once we start using Claude Code regularly for development, we will develop a few prompts which we repeat. For example it can be &lt;code&gt;please tell me about this repo&lt;/code&gt; or &lt;code&gt;review my code&lt;/code&gt; etc. As we repeat the same prompt a time saver is to create commands from them and use &lt;code&gt;/code-review&lt;/code&gt; instead of writing a whole prompt. By doing this we also remain consistent.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   Note- Claude Code comes with a few commands for regular coding tasks like code review and exploring PR. While those work, you may still need to create your own command that fits your code context.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Skills - This is a real game changer. Skills are modular set of instructions, scripts and other resources which can extend the capability of the agent. Skills are model-invoked: Claude decides which Skills to use based on your request. Skills are auto-discoverable, and we can also give Skills to sub agents specifically. Let's take an example - maybe you always need to check for your org specific code formatting and imagine you have a feature-developer sub agent and a code-reviewer sub-agent. We can create a &lt;code&gt;format&lt;/code&gt; skill and add the skill to both the sub agent. Now, skills are also discoverable by the main agent. For first time when I encountered skills my doubt was if main agent can discover skill should I start creating more skills or sub-agents ? The answer is still not clear to me but there are subtle nuances - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Main agent only loads the skill name + description at startup and the full skill is loaded on demand hence saving some context.&lt;/li&gt;
&lt;li&gt;Skills are chosen based on context and here we are dependent on the choice of the main agent.
In recent versions of Claude Code Skills have become more powerful. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Skills can run in a forked context, and can also be run in the context of an agent (including custom ones).&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Skills can be user-invocable too (there is a &lt;code&gt;user-invocable&lt;/code&gt; flag that controls whether the skill appears in the slash command menu).&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Sandbox
&lt;/h3&gt;

&lt;p&gt;So, you may have a few agents, augmented with skills, maybe some command which summons the agent. That's a solid setup. But hey we haven't spoken about security. The next few points I would like stress about it so that we do not end up in yet another "Claude wiped up my prod db" scenario. When we run Claude without a sandbox two things happen - it is running on your hardware directly having access to your filesystem, second, Claude being itself conscious about permissions keep on asking for permissions for any command that it wants to access/do some operations. Sandbox provides an isolated environment for Claude Code to work on. Also note there are sandbox modes (auto-allow vs regular permissions mode), so you can tune how many prompts you get.&lt;/p&gt;

&lt;h3&gt;
  
  
  Permissions
&lt;/h3&gt;

&lt;p&gt;In many scenarios, we may not want Claude Code to access some files or, in an enterprise scenario we might want to restrict fetching from web. For these things set up Permissions. In practice this is Read/Edit/WebFetch rules, so you can restrict what Claude can read, what it can edit, and which domains it can fetch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Env
&lt;/h3&gt;

&lt;p&gt;MCP configs support environment variable expansion in &lt;code&gt;.mcp.json&lt;/code&gt; (useful for machine-specific paths and sensitive values like API keys). Keep secrets out of the repo and wire them via env vars instead.&lt;/p&gt;

&lt;p&gt;Once you are here, you have a pretty solid baseline with Sandbox and Permissions to start with. You can now tweak this based on experience. &lt;/p&gt;

&lt;p&gt;Agentic coding is gaining traction, models are becoming increasingly efficient to generate code, as developers we need to adopt these tools. Consider these agents as your peer programmer or assistant rather than a replacement. The onus now will be on reviewing what the code generates, tweaking the agentic coding environment to match your coding style etc. &lt;br&gt;
Hope this post will help to setup Claude Code and navigate the basic concepts.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>tooling</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Key Considerations for AWS Lambda on production</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Mon, 10 Jul 2023 18:14:32 +0000</pubDate>
      <link>https://dev.to/sabyasachi/key-considerations-for-aws-lambda-on-production-1k08</link>
      <guid>https://dev.to/sabyasachi/key-considerations-for-aws-lambda-on-production-1k08</guid>
      <description>&lt;p&gt;AWS Lambda is an indispensable component of modern cloud architectures. Its serverless nature, low infrastructure requirements, and pay-as-you-go pricing have made it a cornerstone of production workloads. However, while the benefits of AWS Lambda are undeniable, it is crucial to be aware of certain considerations to ensure its successful implementation.&lt;/p&gt;

&lt;p&gt;Monolithic or Individual Lambda&lt;/p&gt;

&lt;p&gt;The first choice we often faced with how much code should be there in one lambda. AWS best practice is against having a monolith lambda &lt;a href="https://docs.aws.amazon.com/lambda/latest/operatorguide/monolith.html"&gt;See here&lt;/a&gt; but if we separate out each functionality to separate lambda wouldn't we end up in an explosion of lambdas? From a pricing perspective, it might not be a problem but what about code organization? do developers jump around in repos for relevant code? how to handle code duplications?&lt;/p&gt;

&lt;p&gt;One approach I find out &lt;a href="https://leonardqmarcq.com/posts/go-project-structure-for-api-gateway-lambda-with-aws-sam"&gt;useful&lt;/a&gt; for me is to have a single repo for related functions but deploy them as separate lambda. In this way, we can keep the common code together and reuse it in all the functions.&lt;/p&gt;

&lt;p&gt;Pros -&lt;/p&gt;

&lt;p&gt;From a readability perspective, it will feel like a single application.&lt;/p&gt;

&lt;p&gt;It will still be deployed as separate functions so we are not introducing monolithic lambda.&lt;/p&gt;

&lt;p&gt;We can keep the common code together hence less duplicity.&lt;/p&gt;

&lt;p&gt;Cons -&lt;/p&gt;

&lt;p&gt;In complex CI/CD, we need to understand which part of the code has changed and act accordingly.&lt;/p&gt;

&lt;p&gt;More fragmented infra&lt;/p&gt;

&lt;p&gt;Continuing from above, if we break down a service into individual lambdas we need to essentially take care of automated deployment for each lambda.A decision that we need to take here is whether we have one infra code or separate infra code for each lambda. It will be beneficial to separate out the infra code for each lambda so that we are not unnecessarily building or updating all lambda.&lt;/p&gt;

&lt;p&gt;One problem often arises here is about which lambda owns a particular infra. We can use tagging to assign ownership.&lt;/p&gt;

&lt;p&gt;But overall we are now managing from one service to multiple functions so it is a challenge nonetheless.&lt;/p&gt;

&lt;p&gt;Cognitive load&lt;/p&gt;

&lt;p&gt;Because it is so easy to integrate lambdas with another service we often feel like adding Lego blocks and before we realize we end up with numbers of different components that work with each other.&lt;/p&gt;

&lt;p&gt;As a developer what we need here is overall visibility of what event is generated by which service consumed by which lambda which in turn triggers other service it soon becomes a cognitive load.&lt;/p&gt;

&lt;p&gt;Create an overall architecture diagram updated and handy we will often need that.I would personally love to have a tool that can visualize the whole topology.&lt;/p&gt;

&lt;p&gt;Testing&lt;/p&gt;

&lt;p&gt;AWS Lambda is an AWS offering and it is often integrated with another service so a question arises of how to test that. There is a whole section in the AWS doc about testing. However, one thing that I differ slightly from here is the usage of a simulator. I personally like usage simulators like localStack. This gives me much higher confidence than mocking out relevant parts. The documentation talks about testing by actually deploying on AWS, which is absolutely fine but if devs can test locally that will be much faster. Localstack alongside test-containers can speed up the process.&lt;/p&gt;

&lt;p&gt;Tracing&lt;/p&gt;

&lt;p&gt;Most of the time Lambdas are part of an overall architecture and not in a standalone way. This means we need tracing, logging, and metrics to work seamlessly when service-to-lambda interactions are happening.&lt;/p&gt;

&lt;p&gt;for tracing While X-Ray is a great tool often organizations do have an existing tracing mechanism or the cost of X-Ray becomes an issue.We need to come up with a unified tracing solution. One option is to depend on a standard library like Opentelemetery to programmatically propagates tracing info.Another option is to run the same logic but using AWS lambda Extension API.In the second approach, we can make the tracing part language agnostic and run as a separate process from lambda.&lt;/p&gt;

&lt;p&gt;Beware about quota&lt;/p&gt;

&lt;p&gt;AWS Lambda by default has a quota of a maximum of 1000 concurrent executions in an account.Initially, this might not be an issue. But as the environment grows we will start to see throttles.Beware of any scenario that can cause unbounded execution of lambda that might eat up quota from other lambdas.If the event producer produces a large number of events considering having an upper bound of how many concurrent lambdas can be spawned at max. One example configuration for SQS mapping can be found &lt;a href="https://aws.amazon.com/blogs/compute/introducing-maximum-concurrency-of-aws-lambda-functions-when-using-amazon-sqs-as-an-event-source/"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In conclusion, AWS Lambda is a powerful and valuable tool for building scalable and cost-effective cloud architectures. However, its adoption requires careful consideration of various factors. With thoughtful planning and the adoption of best practices, AWS Lambda can significantly enhance scalability, reduce TCO, and drive successful deployments in production environments.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Spring Boot 3 meets Graal Native Image</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sat, 29 Oct 2022 10:14:43 +0000</pubDate>
      <link>https://dev.to/sabyasachi/spring-boot-3-meets-graal-native-image-138n</link>
      <guid>https://dev.to/sabyasachi/spring-boot-3-meets-graal-native-image-138n</guid>
      <description>&lt;p&gt;Spring Boot 3 is the upcoming big release for spring boot. Based on Spring Framework 6, this release is packed with many new features. One thing that has generated a lot of interest in dev community is Graal native image support. Spring Boot 3 comes with out of the box support for generating native images, which promises fast startup time. Spring already has an experimental project &lt;code&gt;Spring Native&lt;/code&gt; to support graal native image generation, however from 3.x version it comes out of box with Spring Boot and no new module is needed. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;Spring Native&lt;/code&gt; is going to be discontinued. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How to generate native image
&lt;/h2&gt;

&lt;p&gt;Let's first generate a spring boot project from &lt;code&gt;start.spring.io&lt;/code&gt; . Add &lt;code&gt;GraalVM Native Support&lt;/code&gt; to the list of dependencies. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Currently it requires Graal VM 22.3 version. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are three ways to generate native image - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Using buildpack&lt;/strong&gt; - spring-boot-maven-plugin can make use of buildpacks to generate an image with native executable. The generated pom has the below plugin
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;image&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;buildpacks&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;buildpack&amp;gt;&lt;/span&gt;gcr.io/paketo-buildpacks/bellsoft-liberica:9.9.0-ea&lt;span class="nt"&gt;&amp;lt;/buildpack&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;buildpack&amp;gt;&lt;/span&gt;gcr.io/paketo-buildpacks/java-native-image&lt;span class="nt"&gt;&amp;lt;/buildpack&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/buildpacks&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/image&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;excludes&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;exclude&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.projectlombok&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;lombok&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                        &lt;span class="nt"&gt;&amp;lt;/exclude&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;/excludes&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;it uses liberica buildpack which uses Graal 22.3 support.&lt;/p&gt;

&lt;p&gt;with this if you run &lt;code&gt;spring-boot:build-image&lt;/code&gt; an OCI compatible image will be generated which uses native executable . &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To see how buildpacks work check out my post &lt;a href="https://dev.to/sabyasachi/buildpack-with-spring-boot-300o"&gt;https://dev.to/sabyasachi/buildpack-with-spring-boot-300o&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Using Maven&lt;/strong&gt; - &lt;code&gt;spring-boot-starter-parent&lt;/code&gt; comes with graal &lt;code&gt;native-image-plugin&lt;/code&gt; in profile &lt;code&gt;native&lt;/code&gt;. The below command generates an executable for your local machine architecture -
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mvn -Pnative native:compile
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to have graal 22.3 installed on local machine, &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As of writing this post I could only found &lt;code&gt;22.3.r17.ea-nik&lt;/code&gt; distribution via sdk man. In case you do not see this distribution in sdk list try setting &lt;code&gt;sdkman_beta_channel=true&lt;/code&gt; in &lt;code&gt;~/.sdkman/etc/config&lt;/code&gt; file. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Using aot processed jar&lt;/strong&gt; - Most of us might be transitioning from using uber jar to native image. We might want to support both before we gain enough confidence and operational excellence. If we run &lt;code&gt;mvn package&lt;/code&gt; an aot processed jar will be generated, which then can be used with &lt;code&gt;native-image&lt;/code&gt; tool to generate native executable artifact. I see this option as a great entrypoint to adopt graal native image. &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Graal reachability metadata support
&lt;/h2&gt;

&lt;p&gt;During native image generation, native-image tool does a static analysis. There are classes which might not get accessed during this static analysis and they get left out in the final artifact. To overcome this some extra information can be provided during build time. Creating this extra metadata is cumbersome. There's an effort to consolidate these metadata information for various 3rd party libraries into a shared github repo &lt;a href="https://github.com/oracle/graalvm-reachability-metadata"&gt;https://github.com/oracle/graalvm-reachability-metadata&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;During generation of native image spring makes use of this repo to include already known configs and hence makes the build much easier. &lt;/p&gt;

&lt;h2&gt;
  
  
  Testing with Native image
&lt;/h2&gt;

&lt;p&gt;The official document guides us to write unit and integration test and test it with the JVM version of the application. This will lower the feedback time as compiling native image still takes a lot of time (approx 7-8 min in my 2019 Macbook Pro) . &lt;/p&gt;

&lt;p&gt;However, there's a nice feature to run the aot compiled jar and run some integration test against it . &lt;/p&gt;

&lt;h2&gt;
  
  
  What I like and didn't like
&lt;/h2&gt;

&lt;p&gt;Likes &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Building of graal native image has improved a lot and having it out of the box will really help its adoption. &lt;/li&gt;
&lt;li&gt;GraalVM reachability metadata is a great addition to help compatibility issues. &lt;/li&gt;
&lt;li&gt;Faster startup . &lt;/li&gt;
&lt;li&gt;AOT processed artifact. &lt;/li&gt;
&lt;li&gt;I was able to use flyway with postgres seamlessly , previously when I tried with Spring native image this integration didn't work . &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Things that need to keep in mind-&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As I add spring boot actuator and had jmx enabled, startup of my application failed. I need to disable expose of management endpoint via JMX as JMX is not supported in Graal native image. &lt;/li&gt;
&lt;li&gt;Configartion like &lt;code&gt;@Profile&lt;/code&gt; and &lt;code&gt;@ConditionalOnProperty&lt;/code&gt; is not supported. These are used very frequently .&lt;/li&gt;
&lt;li&gt;Build time is still on a little longer side. On my personal 2019 MacBook Pro it tool approx 7-8min . &lt;/li&gt;
&lt;li&gt;We need to expect compatibility issue with 3rd Party libs. &lt;/li&gt;
&lt;li&gt;no JVMTI or Java Agents support. &lt;/li&gt;
&lt;li&gt;No thread dump,heap dump . &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both Graal native image and Spring's support is still is very early days. Right now I see graal native can be fit very aptly in Serverless world where we need fast startup. Absence of JIT compilation, JVMTI, JMX those does not come into play in a lean serverless world. &lt;/p&gt;

&lt;p&gt;If I compare Spring with  Micronaut or Quarkus support for graal native I must say Spring is catching up very fast. Support for reachability metadata is a nice addition in spring. &lt;/p&gt;

&lt;p&gt;Overall, yes it is promising but my only concern remains with compatibilty with other libs , longer build time and features that are not supported in native image . &lt;/p&gt;

</description>
      <category>springboot</category>
      <category>graal</category>
      <category>native</category>
    </item>
    <item>
      <title>Spring Feign Client</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sun, 28 Aug 2022 06:01:00 +0000</pubDate>
      <link>https://dev.to/sabyasachi/spring-feign-client-3853</link>
      <guid>https://dev.to/sabyasachi/spring-feign-client-3853</guid>
      <description>&lt;p&gt;Often a service needs to call Http endpoints , Feign comes from the OpenFeign project makes it easier to call http endpoints in a declarative fashion.&lt;br&gt;
Spring has openfeign integraton through its &lt;code&gt;Spring Cloud OpenFeign&lt;/code&gt; integration.&lt;/p&gt;
&lt;h2&gt;
  
  
  How To include feign clients
&lt;/h2&gt;

&lt;p&gt;The actual project for feign is &lt;code&gt;OpenFeign&lt;/code&gt; &lt;a href="https://github.com/OpenFeign/feign"&gt;https://github.com/OpenFeign/feign&lt;/a&gt; . Spring comes with it's own starter . Add below dependency to the project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;    &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.cloud&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-cloud-starter-openfeign&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For an example let's create a service named &lt;code&gt;feign-serviceA&lt;/code&gt; which will call &lt;code&gt;feign-serviceB&lt;/code&gt; . &lt;code&gt;feign-serviceB&lt;/code&gt; exposes a &lt;code&gt;GET&lt;/code&gt; endpoint &lt;code&gt;/hello&lt;/code&gt; which returns a simple &lt;code&gt;hello&lt;/code&gt; response body.&lt;/p&gt;

&lt;p&gt;In order to call the endpoint using a feign client from &lt;code&gt;feign-serviceA&lt;/code&gt; we need to do following - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an interface annotated with &lt;code&gt;@FeignClient&lt;/code&gt; like below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@FeignClient&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;host:port for serviceB&amp;gt;"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"serviceB"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ServiceBClient&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hello"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;sayHello&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add &lt;code&gt;@EnableFeignClients&lt;/code&gt; annotation to main class .&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and we are all set we can simply autowire &lt;code&gt;ServiceBClient&lt;/code&gt; and call method &lt;code&gt;sayHello&lt;/code&gt; like any normal method call .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;@EnableFeignClients takes a list of clients if we have many feign clients then it is better to mention the clients as argument otherwise spring will do a classpath scan to find out feign clients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Feign Configuration
&lt;/h2&gt;

&lt;p&gt;Under the hood feign comes with some components which are used to make a call to remote endpoints and encode/decode request response .&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Client - To make HTTP call feign requires http client. By default openfeign comes with a Default Client. We can override it with &lt;code&gt;ApacheHttpClient&lt;/code&gt;, &lt;code&gt;OkHttpClient&lt;/code&gt; or &lt;code&gt;ApacheHC5FeignClient&lt;/code&gt; . These feign clients are wrapper around a delegate client. For example  ApacheHttpClient wraps a httpcomponents httpclient and converts the response to feign response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decoder - Something needs to convert the feign &lt;code&gt;Response&lt;/code&gt; to the actual type of the feign method's return type. Decoders are that instruments. By default spring provides an &lt;code&gt;OptionalDecoder&lt;/code&gt; which delegates to &lt;code&gt;ResponseEntityDecoder&lt;/code&gt; which further delegates to &lt;code&gt;SpringDecoder&lt;/code&gt;. We can override it by defining a bean of &lt;code&gt;Decoder&lt;/code&gt; . &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Encoder - We call feign methods by passing objects to it something needs to convert it to http request body. &lt;code&gt;Encoder&lt;/code&gt; does that job. Again By default spring provides &lt;code&gt;SpringEncoder&lt;/code&gt;. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Along side above components there are also support for caching, metrics provided by spring feign starter . &lt;/p&gt;

&lt;p&gt;We can create a configuration class and override the defaults for the above components. &lt;br&gt;
If we want to override default for single components &lt;code&gt;@Feign&lt;/code&gt; accepts &lt;code&gt;configuration&lt;/code&gt; arguments which we can use to define custom override for default values.&lt;/p&gt;
&lt;h2&gt;
  
  
  Retry
&lt;/h2&gt;

&lt;p&gt;Feign has baked in support for retry mechanism. However by default it uses &lt;code&gt;Retry.NEVER_RETRY&lt;/code&gt; . For example we can create a custom retryer which will retry any status code &amp;gt; 400. Below is the code for our &lt;code&gt;CustomRetryer&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomRetryer&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Retryer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Default&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CustomRetryer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;maxPeriod&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;maxAttempts&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;period&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxPeriod&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxAttempts&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;continueOrPropagate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;RetryableException&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Going to retry for "&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;continueOrPropagate&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Override&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Retryer&lt;/span&gt; &lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;CustomRetryer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="no"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toMillis&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One important fact is feign Retry works either on &lt;code&gt;IOException&lt;/code&gt; or &lt;code&gt;RetryableException&lt;/code&gt; thrown from some &lt;code&gt;errorDecoder&lt;/code&gt; . Below is how a custom decoder looks like -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;ErrorDecoder&lt;/span&gt; &lt;span class="nf"&gt;errorDecoder&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;methodKey&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{};&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toByteArray&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;asInputStream&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
                &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;IOException&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// NOPMD&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="nc"&gt;FeignException&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;FeignException&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BadRequest&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;RetryableException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;reason&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;httpMethod&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt;
                        &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
                        &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Instant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;plus&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;ChronoUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;MILLIS&lt;/span&gt;&lt;span class="o"&gt;)),&lt;/span&gt;
                        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;request&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="o"&gt;};&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Though documentation says feign retries on IOException internally when an IOException occurs it wraps it in a &lt;code&gt;RetryableException&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Support for resiliency
&lt;/h2&gt;

&lt;p&gt;One form of resiliency through retries we saw in last section. Spring has &lt;code&gt;CircuitBreaker&lt;/code&gt; support for feign . It achieves it through a separate Feign builder &lt;code&gt;FeignCircuitBreaker.Builder&lt;/code&gt; . The actual implementation of circuitbreaker comes from &lt;code&gt;resilience4j&lt;/code&gt; library. &lt;/p&gt;

&lt;h2&gt;
  
  
  Interceptor
&lt;/h2&gt;

&lt;p&gt;Sometimes we want to modify the request by adding some extra information. For example we may add some header for each request. We can achieve this by using &lt;code&gt;RequestInterceptor&lt;/code&gt;. For experiment I added below interceptor which populates a header &lt;code&gt;userid&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;RequestInterceptor&lt;/span&gt; &lt;span class="nf"&gt;userIdRequestInterceptor&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;header&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"userid"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"somerandomtext"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;};&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;feign-serviceB&lt;/code&gt; reads this header and returns back as header. If we do a curl we get below response&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt; HTTP/1.1 200
&amp;lt; connection: keep-alive
&amp;lt; date: Sat, 20 Aug 2022 15:27:47 GMT
&amp;lt; keep-alive: timeout=60
&amp;lt; userid: somerandomtext
&amp;lt; Content-Type: text/plain;charset=UTF-8
&amp;lt; Content-Length: 7
&amp;lt;
* transfer closed with 7 bytes remaining to read
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see userid is added to the response. &lt;br&gt;
A very useful application for interceptor is when feign has to send oauth2 access token . Out of the spring provides a &lt;code&gt;OAuth2FeignRequestInterceptor&lt;/code&gt; which adds access token for each request. &lt;/p&gt;

&lt;h2&gt;
  
  
  Client side loadbalancing support
&lt;/h2&gt;

&lt;p&gt;From spring boot 2.4.0 feign has integration with spring-cloud-loadbalancer which can fetch client url info from various service discovery providers and make that info available to feign . &lt;/p&gt;

&lt;p&gt;Usage of feign simplifies various aspect of making http request. In a typical production environment we may need to override several components like clients, decoder, errorDecoder etc . Also within Spring ecosystem feign is nicely integrated with resiliency, loadbalancing , metrics etc which makes it automatic choice when we are working in a microservices architecture . &lt;/p&gt;

</description>
      <category>practicalspringboot</category>
      <category>spring</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Generate application metrics using SpringBoot and Micrometer</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sun, 22 May 2022 11:20:28 +0000</pubDate>
      <link>https://dev.to/sabyasachi/generate-application-metrics-using-springboot-and-micrometer-39mo</link>
      <guid>https://dev.to/sabyasachi/generate-application-metrics-using-springboot-and-micrometer-39mo</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Observability is one of the pillars of modern microservices architecture. Application metrics is one dimension of that observbility. When an application runs on production we may want to know various operational metrics like memory,cpu ,threadpool usage etc as well as buisness metrics for example how many request for a particular operations are made. &lt;br&gt;
Spring boot with the help of micrometer enables application developers to expose various metrices. &lt;/p&gt;

&lt;h2&gt;
  
  
  Setup metrics
&lt;/h2&gt;

&lt;p&gt;To add support for metrics , we need to add actuator dependency&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-actuator&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and we also need to enable the metrics endpoint like following - &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;management&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;web&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;exposure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;metrics&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it our application now set to expose metrics. &lt;/p&gt;

&lt;p&gt;The below curl &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

curl localhost:8080/actuator/metrics | jq .


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;will give response like - &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"names"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"application.ready.time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"application.started.time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"disk.free"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"disk.total"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"executor.active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"executor.completed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"executor.pool.core"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"executor.pool.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"executor.pool.size"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"executor.queue.remaining"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"executor.queued"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.acquire"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.creation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.idle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.pending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.timeout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"hikaricp.connections.usage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"http.server.requests"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jdbc.connections.active"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jdbc.connections.idle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jdbc.connections.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jdbc.connections.min"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.buffer.count"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.buffer.memory.used"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.buffer.total.capacity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.classes.loaded"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.classes.unloaded"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.gc.live.data.size"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.gc.max.data.size"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.gc.memory.allocated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.gc.memory.promoted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.gc.overhead"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.gc.pause"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.memory.committed"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.memory.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.memory.usage.after.gc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.memory.used"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.threads.daemon"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.threads.live"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.threads.peak"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"jvm.threads.states"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"logback.events"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"process.cpu.usage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"process.files.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"process.files.open"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"process.start.time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"process.uptime"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"system.cpu.count"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"system.cpu.usage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"system.load.average.1m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"tomcat.sessions.active.current"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"tomcat.sessions.active.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"tomcat.sessions.alive.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"tomcat.sessions.created"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"tomcat.sessions.expired"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"tomcat.sessions.rejected"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;These are the metrics that spring boot provides out of the box. We can see it includes jvm memory, threads, cpu usage etc.&lt;/p&gt;

&lt;p&gt;The below request will show used jvm memory &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

 &lt;/span&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="err"&gt;/actuator/metrics/jvm.memory.max'|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;jq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;


 &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jvm.memory.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The maximum amount of memory in bytes that can be used for memory management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"baseUnit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bytes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"measurements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"statistic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VALUE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5620367357&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"availableTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"area"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"heap"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"nonheap"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"CodeHeap 'profiled nmethods'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"G1 Old Gen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"CodeHeap 'non-profiled nmethods'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"G1 Survivor Space"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Compressed Class Space"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"Metaspace"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"G1 Eden Space"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"CodeHeap 'non-nmethods'"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A metrics can have multiple dimensions. For example &lt;code&gt;jvm.memory.max&lt;/code&gt; has &lt;code&gt;heap&lt;/code&gt; and &lt;code&gt;nonheap&lt;/code&gt; size. We can drill down to metrics using its tags like . &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="err"&gt;/actuator/metrics/jvm.memory.max?tag=area:heap'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;jq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jvm.memory.max"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The maximum amount of memory in bytes that can be used for memory management"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"baseUnit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bytes"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"measurements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"statistic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VALUE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4294967294&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"availableTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"values"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"G1 Old Gen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"G1 Survivor Space"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="s2"&gt;"G1 Eden Space"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So far we know that spring boot exposes metrics and we can request metric endpoint to get those metrics and if required we can drill down to this metrics using available tags.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Metrics
&lt;/h2&gt;

&lt;p&gt;What if we need more metrics?&lt;/p&gt;

&lt;p&gt;Spring uses &lt;code&gt;Micrometer&lt;/code&gt;(&lt;a href="https://micrometer.io/" rel="noopener noreferrer"&gt;https://micrometer.io/&lt;/a&gt;) underneath which takes care of generating and exposing metrics. &lt;br&gt;
&lt;code&gt;MeterRegistry&lt;/code&gt; is the core concept of micrometer that holds multiple metrices. &lt;/p&gt;

&lt;p&gt;We can simply inject an instance of &lt;code&gt;MeterRegistry&lt;/code&gt; in our custom metrics provider like below - &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="nd"&gt;@Component&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InventoryMetrics&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt; &lt;span class="n"&gt;inventoryCounter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;InventoryMetrics&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MeterRegistry&lt;/span&gt; &lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;inventoryCounter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Product Count"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;register&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meterRegistry&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;inventoryAdded&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;inventoryCounter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;increment&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Here we have created a new metrics named &lt;code&gt;products&lt;/code&gt; , every time we add a new product we will increment the value. &lt;/p&gt;

&lt;p&gt;Now if we curl our metrics endpoint with we get product count&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'http://localhost:&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="err"&gt;/actuator/metrics/products'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;jq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"products"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Product Count"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"baseUnit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"measurements"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"statistic"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"COUNT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"availableTags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Streaming metrics
&lt;/h2&gt;

&lt;p&gt;On production we would like to stream metrices to a data store like elasticsearch, influxdb etc. Spring Boot supports out of the box various data sinks &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.metrics" rel="noopener noreferrer"&gt;https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.metrics&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;For this post I ran a influxdb docker image locally . We can see our custom metrics pushed to influx - &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uacowaircyj538ned6d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8uacowaircyj538ned6d.png" alt="metrics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the application side configuration looks like - &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;management&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;export&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;influx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;uri&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://localhost:8086'&lt;/span&gt;
        &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your-token&amp;gt;'&lt;/span&gt;
        &lt;span class="na"&gt;bucket&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;bucket&amp;gt;'&lt;/span&gt;
        &lt;span class="na"&gt;org&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;your&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;org&amp;gt;'&lt;/span&gt;
        &lt;span class="na"&gt;autoCreateDb&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;&lt;em&gt;NOTE:&lt;/em&gt;&lt;/strong&gt;   Config properties for influxdb 1.x and 2.x different. &lt;br&gt;
The above config is for influxdb 2.x. For 1.x we need to use username , password and db instead of token,bucket and org. Also autoCreateDb should be false as otherwise springboot will try to create a db named mydb . &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Micrometer metric Types
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Counter&lt;/strong&gt; Counters are monotonically increasing metrics. It can be incremented by a fixed amount which is always positive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gauge&lt;/strong&gt; Gauges are instantaneous metrics this can either go up or down. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Timer&lt;/strong&gt; Timers are short duration latencies and frequency of events. &lt;/p&gt;

&lt;p&gt;Our custom metric is a type of counter to measure the added products . &lt;/p&gt;

&lt;p&gt;This is at a very high level how to expose metrics. &lt;/p&gt;

&lt;p&gt;In production though we need to be aware of the volume of metrics, because if volumes and frequency is high our dashboards can become really slow. &lt;/p&gt;

&lt;p&gt;We should also think about a retention policy of data to not to store unecessary old data. This will help saving some storage.&lt;/p&gt;

&lt;p&gt;In conclusion metrics are essential part of our services and spring boot make it easy to gather and expose it to various data sinks. &lt;/p&gt;

</description>
      <category>springboot</category>
      <category>practicalspringboo</category>
      <category>metrics</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Using AWS CDK to bring infra code closer to application developers</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sun, 15 May 2022 09:56:56 +0000</pubDate>
      <link>https://dev.to/sabyasachi/using-aws-cdk-to-bring-infra-code-closer-to-developers-1nf4</link>
      <guid>https://dev.to/sabyasachi/using-aws-cdk-to-bring-infra-code-closer-to-developers-1nf4</guid>
      <description>&lt;p&gt;AWS Summit Berlin 2022 took place on May11-12 there I attended a great talk by &lt;strong&gt;Gregor Hohpe&lt;/strong&gt; and &lt;strong&gt;Luis Morales&lt;/strong&gt; from AWS titled &lt;code&gt;Infrastructure as actual code&lt;/code&gt;. In it they presented AWS CDK. I thought of giving it a try and this post is about my initial impression about AWS CDK. &lt;/p&gt;

&lt;p&gt;Before we go to what AWS CDK does , let's look at why infrastructure as code is important. In current cloud native application architecture ability to deploy infra in an automated, repeatable and consistent way is a must have. Many tools provides a way to achieve that for example CloudFormation by AWS, terraform for Hashicorp to name a few. &lt;/p&gt;

&lt;p&gt;However primarily these tools have it's own DSL to achieve that. Cloudformation uses YAML/Json files, while terraform uses HCL (HashiCorp Configuration Language). &lt;/p&gt;

&lt;p&gt;What if developers  can use their favourite programming language that they are using to write their application and in which they have expertise ? Well this is where AWS CDK shines. &lt;/p&gt;

&lt;p&gt;AWS CDK enables us to use known programming language like Typescript, JavaScript, Java, Python, Java, C#/.Net and Go. &lt;/p&gt;

&lt;p&gt;Below is how a simple Lambda function with Api Gateway integration may look like -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MovieLambdaInfraStack&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Stack&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MovieLambdaInfraStack&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Construct&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MovieLambdaInfraStack&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;Construct&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;StackProps&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;props&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Parameters&lt;/span&gt;
        &lt;span class="nc"&gt;CfnParameter&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CfnParameter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"lambda-version"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Version of lambda app jar"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"String"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// Bucket storing lambda code&lt;/span&gt;
        &lt;span class="nc"&gt;IBucket&lt;/span&gt; &lt;span class="n"&gt;lambdaCodeBucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;createBucket&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Lambda Definition&lt;/span&gt;
        &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;lambdaSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"movie-lambda-app-"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValueAsString&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;".jar"&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
        &lt;span class="nc"&gt;IFunction&lt;/span&gt; &lt;span class="n"&gt;lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Function&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sab-lambda-artifact"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;code&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromBucket&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lambdaCodeBucket&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lambdaSource&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Runtime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;JAVA_11&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;functionName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"sab-lambda-artifact"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"com.sab.LambdaHandler"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;tracing&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Tracing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ACTIVE&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Duration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;memorySize&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Api Gateway&lt;/span&gt;

        &lt;span class="nc"&gt;LambdaIntegration&lt;/span&gt; &lt;span class="n"&gt;lambdaIntegration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LambdaIntegration&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lambda&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;proxy&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;RestApi&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RestApi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;create&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"movies"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultIntegration&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lambdaIntegration&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;apiKeySourceType&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApiKeySourceType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HEADER&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="nc"&gt;Resource&lt;/span&gt; &lt;span class="n"&gt;movies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getRoot&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;addResource&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"movies"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;movies&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addMethod&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@NotNull&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;IBucket&lt;/span&gt; &lt;span class="nf"&gt;createBucket&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromBucketName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"lambda-code-bucket"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"sab-lambda-artifact"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a simple main method that will be run by AWS CDK to deploy this stack&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MovieLambdaInfraStack&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MovieLambdaInfraStack"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;StackProps&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Environment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;account&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xxxxxx"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"xxxx"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                        &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;synth&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS CDK comes with cmd line cli which will deploy this app on AWS. Underneath it generates a cloudformation template.&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS CDK Basic Components
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;App&lt;/strong&gt; - An &lt;code&gt;App&lt;/code&gt; is an component which will be deployed by cdk and will contain one or more than &lt;code&gt;Stacks&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stack&lt;/strong&gt; - A &lt;code&gt;Stack&lt;/code&gt; is what defines our infra. This will contain one or more &lt;code&gt;Constructs&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constructs&lt;/strong&gt; - These are real AWS services . We can also create our custom constructs.&lt;/p&gt;

&lt;p&gt;See more components at &lt;a href="https://docs.aws.amazon.com/cdk/v2/guide/core_concepts.html"&gt;https://docs.aws.amazon.com/cdk/v2/guide/core_concepts.html&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things that I like
&lt;/h2&gt;

&lt;p&gt;I have used cloudformation, which personally I do not prefer mostly because for complex infra it can become real tangled up and hard to read. &lt;/p&gt;

&lt;p&gt;In recent times I have used mostly terraform, and I liked it. It supports multiple cloud. We can create our own modules and components in terraform. HCL language is pretty expressive. It has it's own way to define functions, types, loop of variables which sometimes become a little unintuitive for us developers. &lt;/p&gt;

&lt;p&gt;my first impression With AWS CDK  is that I see below advantages - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;As developer I feel much at ease to be able to use my favourite and known programming constructs to infra.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We can even write Unit tests using good old Junit . Below is an example&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt; &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;itShouldGenerateLambda&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;App&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="nc"&gt;Stack&lt;/span&gt; &lt;span class="n"&gt;lambda&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MovieLambdaInfraStack&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MovieLambdaInfraStack"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Template&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fromStack&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lambda&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resourceCountIs&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS::Lambda::Function"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;hasResourceProperties&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AWS::Lambda::Function"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="s"&gt;"Handler"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"com.sab.LambdaHandler"&lt;/span&gt;
        &lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We can make full use of abstraction in case of using object oriented programming languages. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This ability of creating abstraction will help us to impart same domain driven design thinking that we can apply on application code level.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;More over I see if we use good abstraction level while writing our infra code it will serve as a blue print how different components are interacting to each other. In other word, we can discover the infrastructural architecture of an application . We will have both software level architecture and infra level architecture side by side in a single place . I believe this will give us great insight. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developers get a broader picture how infra components are working together to achieve what their application code try to express. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  On the down side
&lt;/h2&gt;

&lt;p&gt;However on the down side - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Strong tie up with cloudformation means this is AWS cloud specific. Though there are libraries like cdk-tf (&lt;a href="https://github.com/hashicorp/terraform-cdk"&gt;https://github.com/hashicorp/terraform-cdk&lt;/a&gt;) for terraform and cdk8s for Kubernetes is available. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Relatively new so I am yet to judge it's efficiency in large production infrastructure. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But overall I liked the CDK approach and I hope it's adoption will bring infra code closer to application code and break the silos in terms of tools and languages between infra and application code. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>cdk</category>
    </item>
    <item>
      <title>Using Spring Data JPA for data access layer</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Mon, 09 May 2022 19:25:27 +0000</pubDate>
      <link>https://dev.to/sabyasachi/using-spring-data-jpa-for-data-access-layer-1h7f</link>
      <guid>https://dev.to/sabyasachi/using-spring-data-jpa-for-data-access-layer-1h7f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We started with a simple hello world application and we covered up to how to set up our database schema flyway. We are now ready to write some code which will interact with database.&lt;/p&gt;

&lt;p&gt;Before we jump on to code let's look at a bit of history. &lt;br&gt;
Java has a nice JDBC api which helps us query database. Making it a base many ORM tools come into existence, Hibernate, Mybatis, Toplink to name a few. ORMs bridged the gap between JDBC and objet orientedness with how we perform database operations and mapped them to some objects. Though we have many different opinions about penalty of using ORMs but in practical we see a huge adotion of this tools and specially Hibernate.&lt;/p&gt;

&lt;p&gt;JPA is a specification and is an attempt to uniform the APIs used by many ORMs . &lt;/p&gt;

&lt;p&gt;If we look at Java based applications today JPA+Hibernate has become the defacto choice for relational databases. &lt;/p&gt;

&lt;p&gt;Spring brings more utility that makes life a lot easier for developer.&lt;/p&gt;

&lt;p&gt;Now this post is not a Hibernate or JPA tutorial rather it is a simple Spring tutorial on how to use Spring's support for JPA and Hibernate. &lt;/p&gt;
&lt;h2&gt;
  
  
  The dependencies
&lt;/h2&gt;

&lt;p&gt;Like always we have a starter named &lt;code&gt;spring-boot-starter-jpa&lt;/code&gt; . Below is the dependency&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-data-jpa&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What does it bring to the application ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknb4hav52kajp7d9u6gq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknb4hav52kajp7d9u6gq.png" alt="pom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see it brings hibernate core dependencies and JPA dependencies. &lt;/p&gt;




&lt;p&gt;A small note here JPA which was previously used to be known as Java Persistence API has now renamed to Jakarta Persistence API due to naming rights issues. &lt;/p&gt;




&lt;p&gt;What Spring data jpa provides is &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Repository interface to auto generate most boiler plate query pattern.&lt;/li&gt;
&lt;li&gt;Support for  annotation driven transaction mechanism . &lt;/li&gt;
&lt;li&gt;Easy auditing for entities .&lt;/li&gt;
&lt;li&gt;Support for paginations, filter and so on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So now that we have our dependencies in place, let's start with code. &lt;/p&gt;

&lt;p&gt;Our entity class is simple and looks like below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Getter&lt;/span&gt;
&lt;span class="nd"&gt;@Setter&lt;/span&gt;
&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="nd"&gt;@Table&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"inv"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;manufacturer&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
    &lt;span class="nd"&gt;@CreatedDate&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt; &lt;span class="n"&gt;createdOn&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(imports are ommitted for brevity)&lt;/p&gt;

&lt;p&gt;It's a simple JPA entity with id field as identifier. Now comes the best part, we ofcourse need some code to store and retrieve products from database. Good news is Spring has got us covered. All you need to do is define a repository as below - &lt;/p&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Repository&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ProductRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;JpaRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it spring will generate all boiler plate basic query like persists, findAll to name a few . &lt;/p&gt;

&lt;p&gt;JpaRepository also supports generating query to find by some column of the entity for example id, name, stock, manufacturer,created on. All we need is a method named &lt;code&gt;findBy&amp;lt;propertyName&amp;gt;&lt;/code&gt;. For a list of supported methods read &lt;a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation" rel="noopener noreferrer"&gt;https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Let's try to fetch a product by id . &lt;/p&gt;

&lt;p&gt;Below is &lt;code&gt;ProductService&lt;/code&gt; which takes the &lt;code&gt;Product&lt;/code&gt; DTO as input and stores into database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;
&lt;span class="nd"&gt;@RequiredArgsConstructor&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ProductService&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;ProductRepository&lt;/span&gt; &lt;span class="n"&gt;productRepository&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;productDTO&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="nc"&gt;ProductEntity&lt;/span&gt; &lt;span class="n"&gt;productEnity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ProductEntity&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;productEnity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setName&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;productEnity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setManufacturer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getManufacturer&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;productEnity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setStock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productDTO&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStock&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;productEnity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setCreatedOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;

        &lt;span class="nc"&gt;ProductEntity&lt;/span&gt; &lt;span class="n"&gt;savedEntity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;productRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productEnity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;toProductDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedEntity&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="nf"&gt;toProductDTO&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ProductEntity&lt;/span&gt; &lt;span class="n"&gt;productEntity&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;builder&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createdOn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getCreatedOn&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;manufacturer&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getManufacturer&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getName&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stock&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;productEntity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStock&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All we need to do after creating our entity is to call &lt;code&gt;productRepository.save(productEnity)&lt;/code&gt; .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I have not used any transactions, because JpaRepository itself works in a transaction. Also in this simple example I am not lazily loading any properties from the entity so it is fine to ommit the transaction .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Logging
&lt;/h2&gt;

&lt;p&gt;We may want to check what SQL hibernate is generating for that we can use below properties&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;jpa&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;show-sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;hibernate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;format_sql&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In output we will see below logs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;Hibernate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="k"&gt;insert&lt;/span&gt; 
    &lt;span class="k"&gt;into&lt;/span&gt;
        &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;created_on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;manufacturer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;values&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What if we want to see the actual inputs passed in the insert statement. Well there is no direct property but we can enable logs like below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;org.hibernate.type.descriptor.sql.BasicBinder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TRACE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our application will churn out logs -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2022-05-08 12:09:36.682 TRACE 40492 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [1] as [TIMESTAMP] - [2022-05-08T12:09:36.651572+02:00]
2022-05-08 12:09:36.683 TRACE 40492 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [2] as [VARCHAR] - [test-mfg1]
2022-05-08 12:09:36.683 TRACE 40492 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [3] as [VARCHAR] - [test-product5]
2022-05-08 12:09:36.683 TRACE 40492 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [4] as [BIGINT] - [100]
2022-05-08 12:09:36.683 TRACE 40492 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder      : binding parameter [5] as [OTHER] - [dd7d89fa-c201-4338-871f-a00fed464bd5]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's try to get all products - &lt;/p&gt;

&lt;p&gt;We again going to take help from Spring JPA repositories and our code will look something like -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllProducts&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;productRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;toProductDTO&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;collect&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Collectors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toList&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Pagination
&lt;/h2&gt;

&lt;p&gt;Well the above works but there's a basic issue, there may be a huge number of products,  in that case we need pagination support. Spring repositories are here to rescue us again.&lt;br&gt;
We need to modify our &lt;code&gt;ProductRepository&lt;/code&gt; class a little -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Repository&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ProductRepository&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PagingAndSortingRepository&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;ProductEntity&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;{&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our method signatures change this time and most of the method takes an &lt;code&gt;Pageable&lt;/code&gt; type . &lt;br&gt;
The modified method looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;Page&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllProducts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Pageable&lt;/span&gt; &lt;span class="n"&gt;pageRequest&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;productRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;findAll&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageRequest&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
                &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;map&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;toProductDTO&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the return type changes from &lt;code&gt;List&amp;lt;Product&amp;gt;&lt;/code&gt; to &lt;code&gt;Page&amp;lt;Product&amp;gt;&lt;/code&gt; . A Page type contains information like total page count and total items. &lt;/p&gt;

&lt;p&gt;We can also verify in our application log that select queries are not using &lt;code&gt;limit&lt;/code&gt; and &lt;code&gt;offset&lt;/code&gt; instead of doing a select all .&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="n"&gt;Hibernate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
    &lt;span class="k"&gt;select&lt;/span&gt;
        &lt;span class="n"&gt;productent0_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;id1_0_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;productent0_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;created_on&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;created_2_0_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;productent0_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;manufacturer&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;manufact3_0_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;productent0_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;name4_0_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;productent0_&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;stock5_0_&lt;/span&gt; 
    &lt;span class="k"&gt;from&lt;/span&gt;
        &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="n"&gt;productent0_&lt;/span&gt; &lt;span class="k"&gt;limit&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="k"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Response from our controller also needs to be changed to accomodate the new pagination &lt;br&gt;
information.&lt;/p&gt;


&lt;h2&gt;
  
  
  Auditing
&lt;/h2&gt;

&lt;p&gt;If we look into our &lt;code&gt;save&lt;/code&gt; method in ProductService, we are setting the value of &lt;code&gt;createdOn&lt;/code&gt; field to be current date time. Although in this demo context there is nothing wrong in doing that , there is a better way to populate this fields. &lt;/p&gt;

&lt;p&gt;Spring data jpa provides auditing fetaure via &lt;code&gt;AuditingEntityListener&lt;/code&gt;. This provide a bunch of annotations that populate a field before or after an event. &lt;/p&gt;

&lt;p&gt;Let's try to populate our &lt;code&gt;createdOn&lt;/code&gt; field.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We first need to add &lt;code&gt;@EntityListeners(AuditingEntityListener.class)&lt;/code&gt; to our &lt;code&gt;ProductEntity&lt;/code&gt; class. &lt;/li&gt;
&lt;li&gt;We need to provide a bean of type &lt;code&gt;DateTimeProvider&lt;/code&gt; which will be responsible for providing a current time. Because we are using &lt;code&gt;OffsetDatetime&lt;/code&gt; we create a bean like below which gives an &lt;code&gt;OffsetDatetime&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;DateTimeProvider&lt;/span&gt; &lt;span class="nf"&gt;dateTimeProvider&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;()-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;OffsetDateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Finally, we add the following annotation &lt;code&gt;@EnableJpaAuditing(dateTimeProviderRef = "dateTimeProvider")&lt;/code&gt; . &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just like timestamp we can also add an &lt;code&gt;auditorAwareRef&lt;/code&gt; which returns an &lt;code&gt;AuditorAware&amp;lt;T&amp;gt;&lt;/code&gt; . Let's add a new column to our &lt;code&gt;ProductEntity&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@CreatedBy&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;createdBy&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we add a bean like below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;    &lt;span class="nd"&gt;@Bean&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="nc"&gt;AuditorAware&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;auditorAwareRef&lt;/span&gt;&lt;span class="o"&gt;(){&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Optional&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;of&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test-user"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;if we now create a new product we will see &lt;code&gt;test-user&lt;/code&gt; has been set as createdBy in database. &lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;Note&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Adding a constant &lt;code&gt;test-user&lt;/code&gt; is only for example purpose. Getting the real user name may involve getting it from ThreadLocal, SecurityContext, Auth Header or from anything else suitable for your context.&lt;/p&gt;




&lt;p&gt;We also have other annotation &lt;code&gt;LastModifiedBy&lt;/code&gt; and &lt;code&gt;LastModifiedOn&lt;/code&gt; to capture modification auditing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some More features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;@Query&lt;/code&gt; - Sometime even the provided repository methods will not be enough for our usecase. May be we need a more complex query, in that case we can add a method and use &lt;code&gt;@Query&lt;/code&gt; annotation to specify our sql query. If we set &lt;code&gt;native=true&lt;/code&gt; we can provide a native SQL query not a JPQL one.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Specification&lt;/code&gt; - Our repository can also inherit from JpaSpecificationExecutor which provides method that takes an &lt;code&gt;Specification&lt;/code&gt; type . We can make use of JPA &lt;code&gt;Criteria&lt;/code&gt; query to build more nuanced and complex queries. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring data jpa is a big module and not everything can be covered in a single post. However we now can create an entity and know how to persist it and query it. In future posts we will see more features from spring-data-jpa.&lt;/p&gt;

&lt;p&gt;That's it from this post . &lt;/p&gt;

</description>
      <category>spring</category>
      <category>jpa</category>
      <category>hibernate</category>
      <category>practicalspringboot</category>
    </item>
    <item>
      <title>Migrate Database with Flyway</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sun, 01 May 2022 10:47:00 +0000</pubDate>
      <link>https://dev.to/sabyasachi/migrate-database-with-flyway-3f4i</link>
      <guid>https://dev.to/sabyasachi/migrate-database-with-flyway-3f4i</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Most of the services that we generally encounter in our daily job will simply take some input from users and populate database , and read from database&lt;br&gt;
and show it on UI. Each database has a schema, now it is rarely happens that we know each nitty gritty of our domain and come up with a perfect schema at day one. Most of the time we go thorugh an iterative process of modifying our schema as and when requirments change. Now all these migrations can reside separately to the application and can be handled by database teams but what if we can keep this migration script along side of our application in a versioned way and apply them on application startup? That's what flyway does for us. &lt;/p&gt;

&lt;p&gt;Flyway (&lt;a href="https://flywaydb.org/documentation/" rel="noopener noreferrer"&gt;https://flywaydb.org/documentation/&lt;/a&gt;) is an open source database migration tool that is used to migrate your database schema. It can be used standalone but it has nice integration with spring boot. Liquibase in another option for database migration most of the time we will see one of these two being used in production services.&lt;/p&gt;

&lt;p&gt;Flyway supports a vast list of databases check in documentation for more details.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flyway Convention
&lt;/h2&gt;

&lt;p&gt;Flyway favours simplicity and convention over configuration. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each flyway migration script file has the format of &lt;code&gt;V&amp;lt;version&amp;gt;__&amp;lt;description&amp;gt;.sql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;If we want to undo a migration, we can put that script in a file names &lt;code&gt;U&amp;lt;version&amp;gt;__&amp;lt;description&amp;gt;.sql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Flyway also stores the checksum of file. So once a file has been applied the content cannot be changed.&lt;/li&gt;
&lt;li&gt;It tracks the migration history in a table named &lt;code&gt;flyway_schema_history&lt;/code&gt; .&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Flyway with Spring Boot
&lt;/h2&gt;

&lt;p&gt;To show case flyway with spring boot I am going to use our last &lt;code&gt;inventory-service&lt;/code&gt;. So our intention is to start creating a schema and that should be applied by flyway.&lt;/p&gt;

&lt;p&gt;To integrate flyway with spring boot we start with adding below dependency to our service.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-data-jpa&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.flywaydb&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;flyway-core&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.postgresql&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;postgresql&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We start by adding &lt;code&gt;spring-boot-starter-data-jpa&lt;/code&gt; this gives us jpa and hibernate capabilities to our application.&lt;/p&gt;

&lt;p&gt;As we are using here postgresql we need to add &lt;code&gt;postgresql&lt;/code&gt; driver  dependency.&lt;/p&gt;

&lt;p&gt;And last but not the least we need to add &lt;code&gt;flyway-core&lt;/code&gt; dependency.&lt;/p&gt;

&lt;p&gt;Flyway uses spring datasource configuration to find out database uri and credentials. Let's add the details of our database to our application.&lt;/p&gt;

&lt;p&gt;For this blog I have created a db named inventory and a R/W user named &lt;code&gt;inventory_rw&lt;/code&gt; . So our application config looks like as following.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://localhost:5432/inventory&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inventory_rw&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;*****'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So till now flyway knows which database to connect with which credentials. Now we need to provide the migration script.&lt;br&gt;
We name our first migration script as &lt;code&gt;V1__init.sql&lt;/code&gt; and it looks like as following-&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;SCHEMA&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;SET&lt;/span&gt; &lt;span class="n"&gt;search_path&lt;/span&gt; &lt;span class="k"&gt;TO&lt;/span&gt; &lt;span class="n"&gt;inv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;product_name&lt;/span&gt;  &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="nb"&gt;NUMERIC&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="n"&gt;manufacturer&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now if we run the application, the application starts up. We see some logs like below - &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 Successfully applied 1 migration to schema "public", now at version v1 (execution time 00:00.046s)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;if we connect to our database we see the following - &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7na89kla3g7gfa4rnerk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7na89kla3g7gfa4rnerk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So there is our table . We also see the owner is our user .&lt;/p&gt;

&lt;p&gt;if we check in public schema we can say the flyway_schema_history table is also created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ri7tf5n9hfbep0hvnv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs9ri7tf5n9hfbep0hvnv.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And here is how it looks like - &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygi7twws7pzwjg7qhtd4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygi7twws7pzwjg7qhtd4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's try to change our migration script. We get below exception &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Caused by: org.flywaydb.core.api.exception.FlywayValidateException: Validate failed: Migrations have failed validation
Migration checksum mismatch for migration version 1
-&amp;gt; Applied to database : 2071614183
-&amp;gt; Resolved locally    : 387884339. Either revert the changes to the migration, or run repair to update the schema history.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So once your schema is applied by default we cannot change the script. However if we want we can disable this check by &lt;code&gt;spring.flyway.validate-on-migrate=false&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Let's add a column to our table. To do this we need to add a new migration script with version number greater than previous version.&lt;/p&gt;

&lt;p&gt;Let's create a new file name &lt;code&gt;V2_created_on_column.sql&lt;/code&gt; and add the following script.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;

&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;products&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;created_on&lt;/span&gt; &lt;span class="nb"&gt;TIMESTAMP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On logs we see below lines - &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

 Current version of schema "public": 1
 Migrating schema "public" to version "2 - created on"
 Successfully applied 1 migration to schema "public", now at version v2 (execution time 00:00.051s)


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;if we check our table we can see the new column is added. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foj9bwhw4rdyjd0zfx9wo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foj9bwhw4rdyjd0zfx9wo.png" alt="alter-table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing flyway in already existing database
&lt;/h2&gt;

&lt;p&gt;If we already have a database that is not created using flyway and the public schema (or the schema in which we want our flyway-schema-history-table to be created) already has other tables we will see below exception.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Found non-empty schema(s) "public" but no schema history table. Use baseline() or set baselineOnMigrate to true to initialize the schema history table.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Flyway basically refuses to migrate on a non empty database for which it does not have a schema history table.&lt;br&gt;
To overcome this issue, we need to provide a baseline to flyway. A baseline is a way to tell flway that don't care what happended till this version and apply any changes above this version.&lt;br&gt;
With spring config we achieve this by adding below property to our application.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;flyway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;baseline-on-migrate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;baseline-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Now here's a small catch if you don't provide which version to baseline the default value provided is 1. &lt;br&gt;
So here I am providing a custom value 0 so that my scripts like V1 onwards are applied.&lt;/p&gt;

&lt;p&gt;The schema history table will look somehting like below - &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6a4h4dvolwttisbwxk2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6a4h4dvolwttisbwxk2d.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We now have a new entry called &lt;code&gt;&amp;lt;&amp;lt;Flyway Baseline&amp;gt;&amp;gt;&lt;/code&gt; in our schema history table. &lt;/p&gt;

&lt;h2&gt;
  
  
  Flyway custom user
&lt;/h2&gt;

&lt;p&gt;Till now in our configuration, flyway is using the user provided in spring datasource. &lt;br&gt;
However it may be possible that your application uses a read-only user . &lt;br&gt;
In this scenario to provide a different user to flyway we need to specify user for flyway.&lt;/p&gt;

&lt;p&gt;The below config uses a separate R/W user to do the migration - &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;spring&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;datasource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:postgresql://localhost:5432/inventory&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inventory_ro&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;******'&lt;/span&gt;
  &lt;span class="na"&gt;flyway&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;baseline-on-migrate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;baseline-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;0'&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inventory_rw&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;******'&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Flyway integration of spring boot has a lot of properties to configure, for example we can define custom schema where flyway_schema_history table will be created, cherry pick migration script, default schema name etc. A list of these properties can be found &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html" rel="noopener noreferrer"&gt;https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;So that's it from this post. We now know how to iterate over our database and apply migrations using flyway. In next post wit this knowledge I will show how to integrate a database with spring boot application.&lt;/p&gt;

</description>
      <category>spring</category>
      <category>database</category>
      <category>flyway</category>
      <category>practicalspringboot</category>
    </item>
    <item>
      <title>Writing REST API with OpenAPI and SpringBoot</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sun, 24 Apr 2022 07:08:31 +0000</pubDate>
      <link>https://dev.to/sabyasachi/writing-rest-api-with-openapi-and-springboot-34p6</link>
      <guid>https://dev.to/sabyasachi/writing-rest-api-with-openapi-and-springboot-34p6</guid>
      <description>&lt;p&gt;Till now we have seen how to generate a new spring boot application and then how to containerize it. However our application till does not have any functionality. Today we will see how to create a REST API with Spring boot.We will take a schema first approach and we will generate the REST API stub using the schema. This article will show how a OpenAPI specification looks like and how can we generate our REST API stub using the schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAPI Specification
&lt;/h2&gt;

&lt;p&gt;APIs are contract between the application and consumers of the application. These consumers can be machines or humans. OpenAPI is a specification to write your API contract in human and machine readable format. It standardizes the way we can describe our API. The entire specififaction can be found here &lt;code&gt;https://spec.openapis.org/oas/v3.1.0&lt;/code&gt; . &lt;/p&gt;

&lt;h2&gt;
  
  
  Our First API Spec
&lt;/h2&gt;

&lt;p&gt;Let's create a new service, I call it &lt;code&gt;inventory-service&lt;/code&gt;. We now know how to generate a new spring boot application. We add a yml openAPI spec file in &lt;code&gt;src/resources/spec/inventory-api.yml&lt;/code&gt; . A minimal API can look as follows -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;openapi&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.0.3"&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;inventory-api&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;1.0.0&lt;/span&gt;
&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;/products&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get All Products&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;getAllProducts&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;All products are returned&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/ListOfProducts'&lt;/span&gt;
      &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;404'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;No Product returned&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Error'&lt;/span&gt;
    &lt;span class="na"&gt;post&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Add A Product to inventory&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;addProduct&lt;/span&gt;
      &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Product'&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;201'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Product added successfully&lt;/span&gt;
          &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Product'&lt;/span&gt;
      &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;400'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bad Request&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Error'&lt;/span&gt;
  &lt;span class="s"&gt;/products/{id}&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get A Product By ID&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;getProductById&lt;/span&gt;
      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
            &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;uuid&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Get a product by id&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Product'&lt;/span&gt;
      &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;404'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;No Product returned&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Error'&lt;/span&gt;
    &lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update A Product&lt;/span&gt;
      &lt;span class="na"&gt;operationId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;updateProduct&lt;/span&gt;
      &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;path&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
          &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
            &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;uuid&lt;/span&gt;
          &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;requestBody&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Product'&lt;/span&gt;
      &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;200'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Created product is  returned&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Product'&lt;/span&gt;
      &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;400'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bad Request&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Error'&lt;/span&gt;
      &lt;span class="err"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;404'&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Product Does not Exist&lt;/span&gt;
          &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Error'&lt;/span&gt;
&lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schemas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;ListOfProducts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
      &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/components/schemas/Product'&lt;/span&gt;

    &lt;span class="na"&gt;Product&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
          &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UUID&lt;/span&gt;
    &lt;span class="na"&gt;Error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
      &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a very minimal API . We can see in &lt;code&gt;paths&lt;/code&gt; section we have description of our API. Each API endpoint has it's optional request body and response body. We can also define if some custom headers are required, path parameters , query parameters and so on. &lt;br&gt;
In the &lt;code&gt;components&lt;/code&gt; section we define our models and these are referenced in our API. &lt;/p&gt;

&lt;p&gt;I will not go deeper into the OpenAPI spec but because it is very vast but we can always consult the spec for our specific use case . &lt;/p&gt;
&lt;h2&gt;
  
  
  Generating REST API for Spring
&lt;/h2&gt;

&lt;p&gt;Now that we have our OpenAPI spec, there are plugins and tool available to generate code from our spec. We can use the &lt;code&gt;openapi-generator&lt;/code&gt; &lt;a href="https://openapi-generator.tech/docs/installation"&gt;https://openapi-generator.tech/docs/installation&lt;/a&gt; to generate our REST API. We can use cli to generate our REST API. &lt;/p&gt;

&lt;p&gt;There is also a maven plugin &lt;a href="https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin"&gt;https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin&lt;/a&gt; which we will use to generate our source .&lt;/p&gt;

&lt;p&gt;The maven plugin uses the openapi-generator to generate the source code.&lt;/p&gt;

&lt;p&gt;To use the maven-plugin we will add it to the build section like following -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.openapitools&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;openapi-generator-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;5.4.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;executions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;execution&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;goals&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;goal&amp;gt;&lt;/span&gt;generate&lt;span class="nt"&gt;&amp;lt;/goal&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/goals&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;inputSpec&amp;gt;&lt;/span&gt;${project.basedir}/src/main/resources/spec/inventory-api.yml&lt;span class="nt"&gt;&amp;lt;/inputSpec&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;generatorName&amp;gt;&lt;/span&gt;spring&lt;span class="nt"&gt;&amp;lt;/generatorName&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;generateSupportingFiles&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/generateSupportingFiles&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;configOptions&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;basePackage&amp;gt;&lt;/span&gt;com.sab.inventory&lt;span class="nt"&gt;&amp;lt;/basePackage&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;sourceFolder&amp;gt;&lt;/span&gt;src/java/main&lt;span class="nt"&gt;&amp;lt;/sourceFolder&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;interfaceOnly&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/interfaceOnly&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;modelPackage&amp;gt;&lt;/span&gt;com.sab.inventory.dto&lt;span class="nt"&gt;&amp;lt;/modelPackage&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;apiPackage&amp;gt;&lt;/span&gt;com.sab.inventory.api&lt;span class="nt"&gt;&amp;lt;/apiPackage&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;skipDefaultInterface&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/skipDefaultInterface&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;openApiNullable&amp;gt;&lt;/span&gt;false&lt;span class="nt"&gt;&amp;lt;/openApiNullable&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/configOptions&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/execution&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/executions&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both the plugin and the actual openapi-generator has lot of config options we can check it from &lt;a href="https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin"&gt;https://github.com/OpenAPITools/openapi-generator/tree/master/modules/openapi-generator-maven-plugin&lt;/a&gt; and &lt;a href="https://openapi-generator.tech/docs/generators/spring"&gt;https://openapi-generator.tech/docs/generators/spring&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In the above example I have used the bare minimum config . I will explain them below . &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;* `inputSpec` - This is the path to the OpenAPI spec file.
* `generatorName` - ooenapi-generator can produce source code multiple language and framework. Because we want to generate for Spring I chose spring as the generator name.
* `generateSupportingFiles` - When I generated first I saw some unecessary supporting files were generated as I do not need those I turned it to false.
* `configOptions` - Properties that maps directly to the generator options.
   ** `basePackage` - package name for your generated sources
   ** `sourceFolder` - folder where your generated sources will be placed
   **  `interfaceOnly` - We can either generate only REST API interface or we can generate some default code. I make it true as I want to generate only REST API interface.
   ** `modelPackage` - package name for your generated model/dto classes.
   ** `apiPackage` - package name for your generated API classes.
   **   `skipDefaultInterface` - We can skip the genration of default methods in the interface.
   ** `openApiNullable` - With the value true it will generate an import of `org.openapitools.jackson.nullable.JsonNullable` however I didn't need it so I make it false.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So what is the output of the above code ? Below is how our REST API stub looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (5.4.0).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.sab.inventory.api&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.sab.inventory.dto.Error&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;com.sab.inventory.dto.Product&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.UUID&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.Operation&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.Parameter&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.Parameters&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.media.Content&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.media.Schema&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.responses.ApiResponse&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.security.SecurityRequirement&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.swagger.v3.oas.annotations.tags.Tag&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.http.HttpStatus&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.http.MediaType&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.http.ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.validation.annotation.Validated&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.bind.annotation.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.context.request.NativeWebRequest&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.springframework.web.multipart.MultipartFile&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.validation.Valid&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.validation.constraints.*&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Map&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.Optional&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.annotation.Generated&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Generated&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"org.openapitools.codegen.languages.SpringCodegen"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;date&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"2022-04-23T22:00:49.464591+02:00[Europe/Berlin]"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Validated&lt;/span&gt;
&lt;span class="nd"&gt;@Tag&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"products"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"the products API"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ProductsApi&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * POST /products
     * Add A Product to inventory
     *
     * @param product  (optional)
     * @return All products are returned (status code 201)
     *         or No Product returned (status code 400)
     */&lt;/span&gt;
    &lt;span class="nd"&gt;@Operation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;operationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"addProduct"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"201"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"All products are returned"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))),&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"400"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"No Product returned"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;POST&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/products"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt; &lt;span class="o"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;consumes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;addProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Parameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Product"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nd"&gt;@RequestBody&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;


    &lt;span class="cm"&gt;/**
     * GET /products
     * Get All Products
     *
     * @return All products are returned (status code 200)
     *         or No Product returned (status code 404)
     */&lt;/span&gt;
    &lt;span class="nd"&gt;@Operation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;operationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"getAllProducts"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"200"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"All products are returned"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))),&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"404"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"No Product returned"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/products"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getAllProducts&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;

    &lt;span class="o"&gt;);&lt;/span&gt;


    &lt;span class="cm"&gt;/**
     * GET /products/{id}
     * Get A Product By ID
     *
     * @param id  (required)
     * @return All products are returned (status code 200)
     *         or No Product returned (status code 404)
     */&lt;/span&gt;
    &lt;span class="nd"&gt;@Operation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;operationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"getProductById"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"200"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"All products are returned"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))),&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"404"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"No Product returned"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;GET&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/products/{id}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getProductById&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Parameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="nd"&gt;@PathVariable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;


    &lt;span class="cm"&gt;/**
     * PUT /products/{id}
     * Update A Product
     *
     * @param id  (required)
     * @param product  (optional)
     * @return Created product is  returned (status code 200)
     *         or Error (status code 400)
     *         or Product Does not Exist (status code 404)
     */&lt;/span&gt;
    &lt;span class="nd"&gt;@Operation&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;operationId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"updateProduct"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;responses&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"200"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Created product is  returned"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))),&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"400"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Error"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;))),&lt;/span&gt;
            &lt;span class="nd"&gt;@ApiResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responseCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"404"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Product Does not Exist"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Content&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;)))&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nd"&gt;@RequestMapping&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RequestMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PUT&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"/products/{id}"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;produces&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt; &lt;span class="o"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;consumes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="nc"&gt;ResponseEntity&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Product&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;updateProduct&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;
        &lt;span class="nd"&gt;@Parameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="nd"&gt;@PathVariable&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
        &lt;span class="nd"&gt;@Parameter&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Product"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;@Schema&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="nd"&gt;@Valid&lt;/span&gt; &lt;span class="nd"&gt;@RequestBody&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nc"&gt;Product&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
    &lt;span class="o"&gt;);&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have our API interface , we can now create our controller and implement the methods. &lt;/p&gt;

&lt;p&gt;So that's it for this post, I will actually implement the API using tests so watch out for the next post. &lt;/p&gt;

</description>
      <category>springboot</category>
      <category>openapi</category>
      <category>practicalspringboot</category>
    </item>
    <item>
      <title>Containerize Your Spring Boot App</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sat, 16 Apr 2022 11:16:29 +0000</pubDate>
      <link>https://dev.to/sabyasachi/containerize-your-spring-boot-app-47cm</link>
      <guid>https://dev.to/sabyasachi/containerize-your-spring-boot-app-47cm</guid>
      <description>&lt;p&gt;In my previous post &lt;a href="https://dev.to/sabyasachi/spring-boot-first-steps-25nl"&gt;https://dev.to/sabyasachi/spring-boot-first-steps-25nl&lt;/a&gt; we saw how to create a simple spring boot application which actually does nothing much. I also touched about how to package that as jar file and run locally. However currently in production environment docker is hugely adopted. In this post we will see how to containerize our spring boot application. &lt;/p&gt;

&lt;h2&gt;
  
  
  First Step, just works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; ubuntu:18.04&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; MAVEN_VERSION=3.8.5&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; BASE_URL=https://downloads.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries&lt;/span&gt;
&lt;span class="c"&gt;# Install Java&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; curl&lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; openjdk-17-jdk ca-certificates-java&lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get clean &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; update-ca-certificates &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; JAVA_HOME /usr/lib/jvm/java-17-openjdk-amd64&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;JAVA_HOME
&lt;span class="c"&gt;# Install Maven&lt;/span&gt;
&lt;span class="k"&gt;RUN  &lt;/span&gt;curl &lt;span class="nt"&gt;-OLs&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /usr/local/ &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /usr/local/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/bin/mvn /usr/bin/mvn &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;mvn clean package
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; target/*.jar app.jar&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java","-jar","app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a new image by running &lt;code&gt;docker build -t spring-first-web-app:1.0.0&lt;/code&gt; and then we run our application by running &lt;code&gt;docker run  spring-first-web-app:1.0.0&lt;/code&gt;.&lt;br&gt;
So far so good. We see application starting up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FOC5FNDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/om65xu6ikjfh9dyljy0i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FOC5FNDb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/om65xu6ikjfh9dyljy0i.png" alt="startup" width="880" height="182"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  First Improvement
&lt;/h2&gt;

&lt;p&gt;While the above image works just fine, we can see some issues. First one is of size.&lt;br&gt;
If we run &lt;code&gt;docker images spring-first-web-app:1.0.0&lt;/code&gt; we see that the image is about 1 GB.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ITEeC9_h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3mpb38y620cuyf93p8e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ITEeC9_h--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x3mpb38y620cuyf93p8e.png" alt="docker1" width="781" height="39"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is huge for an application which has basically nothing.&lt;br&gt;
First thing we can do to move to a smaller base image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; openjdk:17&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; MAVEN_VERSION=3.8.5&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; BASE_URL=https://downloads.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries&lt;/span&gt;

&lt;span class="k"&gt;RUN  &lt;/span&gt;curl &lt;span class="nt"&gt;-OLs&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /usr/local/ &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /usr/local/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/bin/mvn /usr/bin/mvn &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;mvn clean package
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; target/*.jar app.jar&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java","-jar","app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We moved to a new base image. OpenJDK which is the open source branch of Java provides many base images. These images has its advantage that we do not need to manually install Java, also these images time to time get security patches and updates. So one task is off our list.&lt;/p&gt;

&lt;p&gt;Now when we build our image we can see that the size is reduced to about 600MB&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lc2NXJQ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ishf02m7nt6riww8xvar.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lc2NXJQ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ishf02m7nt6riww8xvar.png" alt="docker2" width="780" height="48"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There is also another base image available which is based on alpine linux. Generally Alpine based images are even smaller but as per OpenJDK alpine based images are only supported in EA versions. More see https://hub.docker.com/_/openjdk .
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Second Improvement
&lt;/h2&gt;

&lt;p&gt;Can we do better ? If we follow carefully we have two stage , in first stage we download maven and compile our java source code. In second stage we run our packaged application. Once we have our packaged application we do not need anymore mvn and JDK . All we need is a JRE. &lt;br&gt;
Here comes the idea of multistage docker build. In a multistage docker build we can pick and chose artifacts from previous stages and throw away anything from all previous stages.&lt;br&gt;
Below is how we can do this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; eclipse-temurin:17 as build&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; MAVEN_VERSION=3.8.5&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; BASE_URL=https://downloads.apache.org/maven/maven-3/${MAVEN_VERSION}/binaries&lt;/span&gt;

&lt;span class="k"&gt;RUN  &lt;/span&gt;curl &lt;span class="nt"&gt;-OLs&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;tar&lt;/span&gt; &lt;span class="nt"&gt;-xzf&lt;/span&gt; apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /usr/local/ &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; /usr/local/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/bin/mvn /usr/bin/mvn &lt;span class="se"&gt;\
&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; /tmp/apache-maven-&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;MAVEN_VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;-bin&lt;/span&gt;.tar.gz

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;mvn clean package
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; target/*.jar app.jar&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; eclipse-temurin:17-jre-alpine as production&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build app.jar .&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java","-jar","app.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above docker file we have two stages. First stage &lt;code&gt;build&lt;/code&gt; is build stage. In build stage we download maven and compile our java source code. In second stage &lt;code&gt;production&lt;/code&gt; we run our packaged application. Learn more about multistage docker build from &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;https://docs.docker.com/develop/develop-images/multistage-build/&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;Let's see how much is the docker size now - &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--guZqX0hi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/92y2wdzk6vxe3ixk4fgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--guZqX0hi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/92y2wdzk6vxe3ixk4fgk.png" alt="multistage" width="786" height="86"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see a huge reduction in size. Point to note here is I have moved to a different base image. Reason is , for production stage I want a JRE only image. However for newer versions of Java the upsteam OpenJDK project didn't produce anymore JREs hence there is no JRE only image. There are a lot of discussion in github about this. For example see &lt;a href="https://github.com/docker-library/openjdk/issues/468"&gt;https://github.com/docker-library/openjdk/issues/468&lt;/a&gt; . &lt;/p&gt;

&lt;p&gt;There is also another provider Adoptium (previously known as AdoptopenJDK) which under their version of Java called Temurin still provides a JRE image. You can find a nice article about their decision &lt;a href="https://blog.adoptium.net/2021/12/eclipse-temurin-jres-are-back/"&gt;https://blog.adoptium.net/2021/12/eclipse-temurin-jres-are-back/&lt;/a&gt; . Hence I moved to using temurin. &lt;/p&gt;

&lt;h2&gt;
  
  
  Are there still room for improvements ?
&lt;/h2&gt;

&lt;p&gt;Indeed! though not much about size(Well you can try some distroless image).But I would like to focus on below two topic - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Layered image &lt;/li&gt;
&lt;li&gt;Spring Buildpack .&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring buildpack provides support for creating image for spring application without needing to write Dockerfile I have alteady written a post about this &lt;a href="https://dev.to/sabyasachi/buildpack-with-spring-boot-300o"&gt;https://dev.to/sabyasachi/buildpack-with-spring-boot-300o&lt;/a&gt; . This also touched a little about layering. &lt;/p&gt;

&lt;p&gt;In a separate posts I will explain how to create a spring layered image. &lt;/p&gt;

&lt;p&gt;So, that's it from this post. We now know how to create a bare minimum spring application and how to create an image. &lt;/p&gt;

</description>
      <category>docker</category>
      <category>springboot</category>
    </item>
    <item>
      <title>Spring-Boot ,First Step</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Sat, 16 Apr 2022 11:07:11 +0000</pubDate>
      <link>https://dev.to/sabyasachi/spring-boot-first-steps-25nl</link>
      <guid>https://dev.to/sabyasachi/spring-boot-first-steps-25nl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;I have been using Spring framework ecosystem since 2012. Overtime many new modules has been added and the adoption of the framework has increased. As of today it is I can say most popular framework in the industry. But one problem remains for new users of Spring that because Spring does a lot of work under-the-hood, it is sometimes feels like magic and generally production systems differ a lot from your getting started guide it is even more important to not only rely on what is coming out of the box but also to understand how it works. I will be sharing a series of blog post aiming to start with very basics and then move to more advanced topics but focusing with underlying details. I hope this series will help beginners o tip their toes in this beautiful framework. &lt;/p&gt;

&lt;p&gt;In this blog we will see how to create your first Spring Boot application. Spring Boot is another offering in Spring framework universe which makes it easy to create a Spring application. It has been highly adopted in todays microservices world.&lt;/p&gt;

&lt;p&gt;Spring Boot applications are simple java application with some spring specific dependencies. We can use your own dependency management like maven or gradle to create our application. In this blog I will be using Maven as dependency manager.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Step
&lt;/h2&gt;

&lt;p&gt;So how to start. There are a few options -&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can use mvn archetype to create a new spring boot application. It can be a simple maven based project.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another option and which I use very often is to visit the site &lt;code&gt;start.spring.io&lt;/code&gt; and create a project from there . Below is a screenshot of how it looks &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpk4k543t67qil106qud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhpk4k543t67qil106qud.png" alt="start.spring.io"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As we see in the screenshot there are various options . On the left we can use Maven or Gradle as build tool.&lt;/p&gt;

&lt;p&gt;We can also chose Java or kotlin or Groovy as our application language. Spring Boot has currently two main version branch 2.x and upcoming  3.x version.&lt;/p&gt;

&lt;p&gt;After that we can provide your application name and other details . &lt;/p&gt;

&lt;p&gt;It offers to package the application as Jar or War. As of now we will chose Jar . More on how to package your application later.&lt;/p&gt;

&lt;p&gt;And finally the Java version, we can chose upto Java 18. For this blog I will stick with Java 17 . &lt;/p&gt;

&lt;p&gt;Now lets look at the right side there is something called dependencies. Here is what the first magic happens with Spring Boot applications. As I mentioned earlier, Spring Boot applications are based on spring framework. So there are a few dependencies that are required to run the application. We can either manually provide those dependencies or we can use something called &lt;code&gt;spring-boot-starters&lt;/code&gt; these are curated set of dependencies focusing to add some specific feature to applications.&lt;/p&gt;

&lt;p&gt;The first dependency that we will use to create a web application is called &lt;code&gt;spring-boot-starter-web&lt;/code&gt;. This will give us an embedded tomcat server and enable us to run our application as a web application. After adding it we click on Generate. This will download a zip file with a maven project.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Application
&lt;/h2&gt;

&lt;p&gt;The generated project structure looks like below &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcjf7n5kt2m396y4zac1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzcjf7n5kt2m396y4zac1.png" alt="generated project structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A typical maven project , the pom.xml looks like below &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xacyu8h82hwh5xqo3zi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8xacyu8h82hwh5xqo3zi.png" alt="pom.xml"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, we see we have two depedencies, &lt;code&gt;spring-boot-starter-web&lt;/code&gt; and &lt;code&gt;spring-boot-starter-test&lt;/code&gt;. The later one is used for unit testing and fetches junit5. &lt;/p&gt;

&lt;p&gt;Important thing to notice here apart from the dependencies, there is a parent pom which is inherited. The parent pom is &lt;code&gt;spring-boot-starter-parent&lt;/code&gt;. This parent pom contains all build plugins and due to which when we do a simple mvn package command we get a runnable jar. It contains many configuration regarding configuration properties and other stuff. &lt;/p&gt;

&lt;p&gt;This parent starter in turn inherits from &lt;code&gt;spring-boot-dependencies&lt;/code&gt; which contains compatible curated set of dependecies for spring boot. &lt;/p&gt;

&lt;p&gt;In your favourite editor you can go inside each of these parent poms and see what they actually fetch, but it is not absolutely necessary to understand each of them as most of the time you need not to configure them.&lt;/p&gt;

&lt;p&gt;So now we have a spring boot project we saw what are the dependencies we have. Let's see how to run our very new application and what is the output. &lt;/p&gt;

&lt;p&gt;There are many ways to run the application - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Running the jar file. Spring boot applications produce a runnable uber jar with all dependencies inside it, which can be run directly. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using IDE , every Spring boot application has a main method and we can just run the main method from IDE . &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can also containerize the application and run the docker instant. More of it later. But spring has support for something called buildpack also which will produce an image even without a Dockerfile. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So lets first see running the uber jar . First we package the application using &lt;code&gt;mvn package&lt;/code&gt;. Then simply run &lt;code&gt;java -jar &amp;lt;your-jar-file&amp;gt;&lt;/code&gt;. For my case the output looks like below &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6l4wvd1f76bd5idgwru.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6l4wvd1f76bd5idgwru.png" alt="output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From the output we can see it has started a tomcat server and it is listening on port 8080. This is the default settings. We can also use Jetty server instead of tomcat server. Also we can change the default port to some other port. &lt;/p&gt;

&lt;h2&gt;
  
  
  What's Inside Your Jar
&lt;/h2&gt;

&lt;p&gt;We can extract the created jar file to see what is inside. To extract or unzip the jar file we can use command &lt;code&gt;jar -xvf &amp;lt;your-jar-file&amp;gt;&lt;/code&gt;. The output looks like below &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjpz7giejoyfedpwibgs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frjpz7giejoyfedpwibgs.png" alt="extracted jar"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It is important to look inside the jar because a lot of worthy optimization can be done which we will see in later that can contribute in faster builds and startup.&lt;/p&gt;

&lt;p&gt;Now at this point we have a running application. We know how to run it locally. Let's see some quick configuration. &lt;/p&gt;

&lt;h2&gt;
  
  
  Changing the default port
&lt;/h2&gt;

&lt;p&gt;The default port of 8080 is fine may be if we are running a single application, but what if we wanted to run another application ? In a typical production environment a single physical/virtual server may host multiple applications.&lt;br&gt;
We can use &lt;code&gt;server.port&lt;/code&gt; property in &lt;code&gt;application.properties&lt;/code&gt; to change the port.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using Jetty instead of tomcat
&lt;/h2&gt;

&lt;p&gt;Tomcat comes out of the box however we can use Jetty as embedded server. To do that we need to use below pom config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;exclusions&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;exclusion&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-tomcat&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/exclusion&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/exclusions&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-boot-starter-jetty&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For details we can see &lt;a href="https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.webserver" rel="noopener noreferrer"&gt;https://docs.spring.io/spring-boot/docs/current/reference/html/howto.html#howto.webserver&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;So that's it from this post. We have just taken a tiny step to create a simple spring boot application. In the next post we will deep dive on how to package our application.&lt;/p&gt;

</description>
      <category>springboot</category>
      <category>java</category>
    </item>
    <item>
      <title>Deploy model with FastAPI and Heroku</title>
      <dc:creator>sabyasachi</dc:creator>
      <pubDate>Tue, 15 Mar 2022 20:22:03 +0000</pubDate>
      <link>https://dev.to/sabyasachi/deploy-model-with-fastapi-and-heroku-1b5h</link>
      <guid>https://dev.to/sabyasachi/deploy-model-with-fastapi-and-heroku-1b5h</guid>
      <description>&lt;p&gt;In this blog we will see how we can deploy our model with FastAPI and Heroku. Below technologies will be used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;FastAPI&lt;/li&gt;
&lt;li&gt;Heroku&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Github workflow&lt;/li&gt;
&lt;li&gt;AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our model will classify images of dogs and cats.&lt;/p&gt;

&lt;h3&gt;
  
  
  First Generating the model
&lt;/h3&gt;

&lt;p&gt;We use the data from &lt;a href="https://www.kaggle.com/c/dogs-vs-cats"&gt;https://www.kaggle.com/c/dogs-vs-cats&lt;/a&gt; . A model is creted using pretrained resnet model. The kaggle notebook is available &lt;a href="https://github.com/njoysubho/datascience/blob/master/dog-vs-cat.ipynb"&gt;here&lt;/a&gt;. Not really a SOTA model but it is good enough for our purposes.&lt;br&gt;
We saved the model in AWS S3. We will use the model in our FastAPI server.&lt;/p&gt;
&lt;h3&gt;
  
  
  The FastAPI service
&lt;/h3&gt;

&lt;p&gt;Our FastAPI server will be a simple REST API. It has one enpoint &lt;code&gt;/pet&lt;/code&gt; which will accept an image file and return the prediction. Our code look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@app.post("/pet")
async def predict(file: UploadFile=File(...)):
    image = read_imagefile(await file.read())
    tfms= transforms.Compose([
                                            transforms.Resize((224,224)),
                                            transforms.RandomRotation(20),
                                            transforms.RandomVerticalFlip(p=0.1),
                                            transforms.ToTensor(),
                                            transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
                                            ])
    image = tfms(image)
    image = image[None,:]
    dcModel = DogCatModel(models.resnet34(pretrained=False))
    dcModel.load_state_dict(torch.load('/code/model.pth',map_location=torch.device('cpu')))
    dcModel.eval()
    with torch.no_grad():
        prediction= dcModel(image)
        val,label = torch.max(prediction,dim=1)
        log.info(f"Prediction: {label.item()} with val {val.item()}")
        if val &amp;gt; 0.7:
            label = label.item()
            return {"prediction": label}
        else:
            return {"prediction": "Unknown"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see the code is a pretty straight forward. We read the image file and transform it to a tensor. We load the model and make a prediction.&lt;br&gt;
The complete code can be found &lt;a href="https://github.com/njoysubho/fastapi-dog-cat"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now that we have our model and the FastApi service we can now deploy it.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Deployment.
&lt;/h3&gt;

&lt;p&gt;First an application need to be created on heroku. I named the application &lt;code&gt;dog-cat-fastapi&lt;/code&gt;.&lt;br&gt;
We can upload the whole code as zip and heroku will automatically deploy the code, however I decided to use docker image as I also wanted to run the code locally.&lt;/p&gt;

&lt;p&gt;The dockerFile looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM ubuntu:20.04

WORKDIR /code

# install utilities
RUN apt-get update &amp;amp;&amp;amp; \
    apt-get install --no-install-recommends -y curl &amp;amp;&amp;amp; \
    apt-get install -y python3.8 python3-distutils python3-pip python3-apt
# Installing python dependencies
RUN python3 -m pip --no-cache-dir install --upgrade pip &amp;amp;&amp;amp; \
    python3 --version &amp;amp;&amp;amp; \
    pip3 --version
# pip install aws cli
RUN pip3 install awscli 
ARG MODEL_NAME
ARG AWS_ACCESS_ID
ARG AWS_ACCESS_SECRET
ENV AWS_ACCESS_KEY_ID=$AWS_ACCESS_ID
ENV AWS_SECRET_ACCESS_KEY=$AWS_ACCESS_SECRET
ENV AWS_DEFAULT_REGION=eu-west-1
# Copy model files
RUN aws s3 cp s3://datascience-sab/${MODEL_NAME}.pth .

COPY requirements.txt .

RUN pip3 install --no-cache-dir --upgrade -r /code/requirements.txt

COPY ./app /code/app 

EXPOSE $PORT

CMD gunicorn -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:$PORT app.main:app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things to notice here - &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;RUN aws s3 cp s3://datascience-sab/${MODEL_NAME}.pth .&lt;/code&gt; command will pull the model file from S3 bucket.&lt;/li&gt;
&lt;li&gt;In order to access aws S3 it needs credential, for this worklfow we are passing the credential from github secret and set those in ENV. &lt;/li&gt;
&lt;li&gt;When I first deployed the app I could not connect to it , turned out that Heroku does not support the &lt;code&gt;EXPOSE&lt;/code&gt; command and it sets the random port as env variable named &lt;code&gt;PORT&lt;/code&gt;an we can use that to expose the port. the belo command will make the app avilable in  the port
&lt;code&gt;CMD gunicorn -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:$PORT app.main:app&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally we make our github workflow below is the step to deploy on heroku&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;....
....
- name: Build and push
      env:
        HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
        AWS_ACCESS_ID: ${{ secrets.AWS_ACCESS_ID }}
        AWS_ACCESS_SECRET: ${{ secrets.AWS_ACCESS_SECRET }}
      run: heroku container:push web --app=${{ secrets.HEROKU_APP_NAME }} --arg AWS_ACCESS_ID=${{ secrets.AWS_ACCESS_ID }},AWS_ACCESS_SECRET=${{ secrets.AWS_ACCESS_SECRET }},MODEL_NAME=model
    - name: Release
      env:
        HEROKU_API_KEY: ${{ secrets.HEROKU_API_KEY }}
      run: heroku container:release web --app=${{ secrets.HEROKU_APP_NAME }}  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;we pass app name, secrets the model name as build args to &lt;code&gt;heroku container:push&lt;/code&gt; command.&lt;br&gt;
After this we use &lt;code&gt;heroku container:release&lt;/code&gt; command to release the app.&lt;br&gt;
The complete github workflow can be found &lt;a href="https://github.com/njoysubho/fastapi-dog-cat/blob/main/.github/workflows/build-release-deploy.yml"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With this we can deploy our app to heroku. &lt;/p&gt;

&lt;p&gt;Below are some improvements that can be done&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhance the model .&lt;/li&gt;
&lt;li&gt;Introduce model versioning. &lt;/li&gt;
&lt;li&gt;Improved logging, tracing and metrics for the service.&lt;/li&gt;
&lt;li&gt;Also clean up docker image and stream line all RUN and pip commands.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thats it for now. It was really satisfying for me to learn about the fastapi framework and deploy a model on heroku.&lt;/p&gt;

</description>
      <category>fastapi</category>
      <category>heroku</category>
      <category>github</category>
      <category>machinelearning</category>
    </item>
  </channel>
</rss>
