<?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>Forem: Mark Dsouza</title>
    <description>The latest articles on Forem by Mark Dsouza (@markbdsouza).</description>
    <link>https://forem.com/markbdsouza</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%2F317759%2F51732368-4943-4bf3-951e-e1147f6d6cd4.jpg</url>
      <title>Forem: Mark Dsouza</title>
      <link>https://forem.com/markbdsouza</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/markbdsouza"/>
    <language>en</language>
    <item>
      <title>Jackson's @JsonView with SpringBoot Tutorial</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Thu, 16 Jun 2022 04:57:43 +0000</pubDate>
      <link>https://forem.com/markbdsouza/jacksons-jsonview-with-springboot-tutorial-56ba</link>
      <guid>https://forem.com/markbdsouza/jacksons-jsonview-with-springboot-tutorial-56ba</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;If you are a SpringBoot dev and you work on a large project, you ought to know about the annotation provided by Jackson -&lt;code&gt;@JsonView&lt;/code&gt;, because it is extremely powerful and elegant. &lt;code&gt;@JsonView&lt;/code&gt; by Jackson helps selectively serialize and de-serialize objects. By doing so it reduces your code base by a ton by avoiding unnecessary classes and also those irritating getters and setters to copy the values of one object to another.&lt;/p&gt;

&lt;h3&gt;
  
  
  Real Time Example
&lt;/h3&gt;

&lt;p&gt;Look at the below JSON Object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "userId": "markbdsouza",
  "firstName": "Mark",
  "lastName": "Dsouza",
  "socialMediaAccount: {
     "twitterUrl": "https://twitter.com/MarkBDsouza",
     "githubUrl": "https://github.com/markbdsouza",
     "devUrl": "",
     "hashNodeUrl":""
  },
  "articles": [
     {
        "summary": "JS: Sort an Array of Objects on multiple columns/keys",
        "url": "https://dev.to/markbdsouza/js-sort-an-array-of-objects-on-multiple-columns-keys-2bj1"
     },
     {
        "summary": "Spring Cloud Config Server: Step by Step",
        "url": "https://dev.to/markbdsouza/spring-cloud-config-server-step-by-step-14fd"
     }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we have a Json Object User. &lt;br&gt;
We see one User has a single SocialMediaAccount Object(OneToOne Relationship) and one Customer has multiple articles (OneToMany Relationship). &lt;br&gt;
In Java, for this structure, we would need 3 Classes - User, SocialMediaAccount, Article.&lt;br&gt;
The 3 Classes would be as below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class User{
  private String userId;
  private String firstName;
  private String lastName;
  private SocialMediaAccount socialMediaAccount;
  private List&amp;lt;Article&amp;gt; articles;
  // excluding getters and setters for brevity
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class SocialMediaAccount {
  private String twitterUrl;
  private String githubUrl;
  // excluding getters and setters for brevity
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Article{
  private String summary;
  private String url;
  // excluding getters and setters for brevity
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  How JSonView Helps
&lt;/h4&gt;

&lt;p&gt;Now with this one structure, we can JSON Objects containing any combination of fields to form the below JSON from endpoint 2&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "userId": "markbdsouza",
  "socialMediaAccount: {
     "twitterUrl": "https://twitter.com/MarkBDsouza"     
  },
  "articles": [
     {
        "summary": "JS: Sort an Array of Objects on multiple columns/keys",
        "url": "https://dev.to/markbdsouza/js-sort-an-array-of-objects-on-multiple-columns-keys-2bj1"
     },
     {
        "summary": "Spring Cloud Config Server: Step by Step",
        "url": "https://dev.to/markbdsouza/spring-cloud-config-server-step-by-step-14fd"
     }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR the below structure from end point 3&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "userId": "markbdsouza",
  "firstName": "Mark", 
  "socialMediaAccount: {
     "twitterUrl": "https://twitter.com/MarkBDsouza",
     "githubUrl": "https://github.com/markbdsouza",
     "devUrl": "",
     "hashNodeUrl"
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OR any other structure consisting of the same variables in whatsoever permutation/combination.&lt;br&gt;
The business logic for all endpoints can be exactly the same. The only difference is the annotation that needs to be provided such that when converting POJO to JSON or vice versa, Jackson will check which fields need to included when serializing/de-serializing. That way we do not have to create any new Class with the specific structure and then copy the data from the original object to the new class object for each endpoint. &lt;/p&gt;
&lt;h2&gt;
  
  
  Summary of Important Points regarding JsonView
&lt;/h2&gt;

&lt;p&gt;The below points serve as a quick summary of everything you probably need to know about JsonView to get started with implementation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A View in JsonView defines how you want to expose a Class when it is converted from POJO to JSON by the Jackson package. Jackson will serialize/de-serialize only the fields with the corresponding &lt;code&gt;@JsonView&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create a simple Java class(no class level annotation required) that will hold with interfaces/child classes which are our View Names. We can use inheritance so View 2 also includes everything present in View 1. This is helpful when you are building a new View that extends the fields visible in an already existing View.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class Views{
    public interface Public{}
    public interface CustomerDetails extends Public{}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;Once the View class is created, annotation is required at 2 places. 
1) The Class itself or the instance variables of the Class that needs to be serialized/de-serialized. 
2) At the endpoints in your controller so Jackson knows where to apply the View. &lt;/li&gt;
&lt;li&gt;At the Class level(of what we are serialzing/ de-serializing), we need to annotate the required instance variable with &lt;code&gt;@JsonView(Views.Public.class)&lt;/code&gt; where &lt;code&gt;Views&lt;/code&gt; is the class created in the above step and &lt;code&gt;Public&lt;/code&gt; is the interface/subclass created in it. This is what tells Jackson which instance variable of the class to serialize/de-serialize. 
Example :
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @JsonView(Views.Public.class)
    private String firstName;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;One instance variable can have any number of JsonViews attached to it. 
Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @JsonView({Views.Public.class, Views.UserDetails.class})
    private String email;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;If we have an object of Class B as an instance variable of class A. And have attached &lt;code&gt;@JsonView&lt;/code&gt; to the object, it will internally also serialize/de-serialize only the annotated instance variables in class B.
Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class A{
    @JsonView(Views.Public.class)
    private B b;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class B{
    private String password; // will not be included by jackson
    @JsonView(Views.Public.class)
    private String username;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we do not use the &lt;code&gt;@JsonView&lt;/code&gt; in class B, then no field will get serialized/de-serialized of B and it would be an empty object when A gets serialized/de-serialized. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alternatively, we can assign the annotation to the entire class as well.&lt;/li&gt;
&lt;li&gt;In the controllers, we need to annotate the endpoints accordingly so Jackson knows which endpoints have the logic while converting POJO to JSON or vice versa.&lt;/li&gt;
&lt;li&gt;For GET endpoints, if we are returning a class and want to provide only visible fields, we annotate the end point with
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @JsonView(Views.Public.class)
    @GetMapping("/1")
    public Customer getDetails() {
            // business logic to return customer 
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;If we are returning the same class in another endpoint, it is not necessary that we have &lt;code&gt;@JsonView&lt;/code&gt;. If your controller does not have &lt;code&gt;@JsonView&lt;/code&gt;, all fields of the POJO returned will be converted to JSON.&lt;/li&gt;
&lt;li&gt;If it is a HTTP POST call and we are sending the class in our body, using &lt;code&gt;@JsonView&lt;/code&gt; we can accept only the fields mentioned in our View. To do this
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@PostMapping
public Student postLevelTwoBasic(@RequestBody @JsonView(LevelTwoViews.Public.class) Student student) {
    // some POST implementation
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Detailed Implementation and Tutorial
&lt;/h2&gt;

&lt;p&gt;In the below section, we will walk through some code and set up JsonView and see how we can use it. You can find the github link with the entire code : &lt;a href="https://github.com/markbdsouza/jsonview-springboot-tutorial" rel="noopener noreferrer"&gt;https://github.com/markbdsouza/jsonview-springboot-tutorial&lt;/a&gt;&lt;br&gt;
The tutorial has been split into 3 levels. We will increasingly use more features and explore other uses of JsonView.&lt;/p&gt;
&lt;h3&gt;
  
  
  Level 1 : JsonView with a Single Class
&lt;/h3&gt;

&lt;p&gt;To start off, we will create a Single JAVA Class and use JsonView annotation on it. We will be checking both GET as well as POST requests and see how it all works together. In future levels, we will try multiple classes and even entities.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1.1 : Create JsonView Class
&lt;/h4&gt;

&lt;p&gt;Create the Class containing the different views that need to be created.&lt;br&gt;
Observe how we use inheritance in these interfaces. Public is kept as the base View. We have 2 different views that inherit Public - UserNameDetails and OtherDetails. And UserDetails extends UserNameDetails so it extends Public inherently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class LevelOneViews {
    /*
     * Any variable associated with Public will be picked up by this view
     */
    public interface Public {
    }

    /*
     * Any variable associated with UserNameDetails or Public will be picked up by this view
     */
    public interface UserNameDetails extends Public {
    }

    /*
     * Any variable associated with UserDetails, UserNameDetails or Public(since UserNameDetails internally
     *  extends Public)  will be picked up by this view
     */
    public interface UserDetails extends UserNameDetails {
    }

    /*
     * Any variable associated with OtherDetails or Public will be picked up by this view.
     * Note: Will not pick up variables associated with UserNameDetails or UserDetails
     */
    public interface OtherDetails extends Public {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have created 4 views here. Take a minute to see the inheritance and understand the inheritance tree. &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1.2 : Create Java Class with the @JsonView on required variables
&lt;/h4&gt;

&lt;p&gt;Create User class with instance variables with the Views created in the above step&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Data
@ToString
public class User {
    @JsonView({LevelOneViews.Public.class})
    private int userId;
    @JsonView(LevelOneViews.UserNameDetails.class)
    private String firstName;
    @JsonView(LevelOneViews.UserNameDetails.class)
    private String lastName;
    @JsonView({LevelOneViews.UserDetails.class, LevelOneViews.OtherDetails.class})
    private String email;
    @JsonView({LevelOneViews.UserDetails.class, LevelOneViews.OtherDetails.class})
    private String organization;
    private Boolean isActive;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 1.3 : Create Controller and GET Endpoints
&lt;/h4&gt;

&lt;p&gt;Create endpoints with the 4 views created. We have a private static method to create an Object of User. Note that for all methods the implementation is the same. We only call the createUser() method. The only difference in all methods is which View we are using. For each of these GET mappings using JsonView we need to annotate the entire method with &lt;code&gt;@JsonView&lt;/code&gt; with the view. Example: &lt;code&gt;@JsonView(LevelOneViews.UserNameDetails.class)&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;@RestController
public class UserController {

    /**
     * GET without any view
     *
     * @return created User
     */
    @GetMapping("/levelOne/default")
    public User getLevelOneUser() {
        return createUser();
    }

    /**
     * GET with Public View
     *
     * @return created User
     */
    @JsonView(LevelOneViews.Public.class)
    @GetMapping("/levelOne/public")
    public User getLevelOnePublicUser() {
        return createUser();
    }

    /**
     * GET with UserNameDetails View which extends Public
     *
     * @return created User
     */
    @JsonView(LevelOneViews.UserNameDetails.class)
    @GetMapping("/levelOne/name")
    public User getLevelOneNameUser() {
        return createUser();
    }

    /**
     * GET with UserDetails  View which extends UserNameDetails and also Public
     *
     * @return created User
     */
    @JsonView(LevelOneViews.UserDetails.class)
    @GetMapping("/levelOne/details")
    public User getLevelDetailsUser() {
        return createUser();
    }

    /**
     * GET with OtherDetails View which extends Public
     *
     * @return created User
     */
    @JsonView(LevelOneViews.OtherDetails.class)
    @GetMapping("/levelOne/other")
    public User getLevelOneOther() {
        return createUser();
    }

    /**
     * @return created user
     */
    private static User createUser() {
        User user = new User();
        user.setUserId(1);
        user.setFirstName("Mark");
        user.setLastName("Dsouza");
        user.setEmail("mark.benjamin.dsouza@google.com");
        user.setIsActive(true);
        user.setOrganization("DEV.TO");
        return user;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 5 endpoints. 1 without a view and 4 with.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 1.4 : Test the GET Endpoints
&lt;/h4&gt;

&lt;p&gt;Run the springboot application and lets test out our endpoints. &lt;/p&gt;

&lt;h5&gt;
  
  
  Endpoint 1: Without any View
&lt;/h5&gt;

&lt;p&gt;All fields of our User Object will get deserailized&lt;br&gt;
&lt;a href="http://localhost:8080/levelOne/default" rel="noopener noreferrer"&gt;http://localhost:8080/levelOne/default&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.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%2Ftihdkzjf5zud1g8sjsky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ftihdkzjf5zud1g8sjsky.png" alt="Endpoint 1.1" width="347" height="157"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 2: With Public View
&lt;/h5&gt;

&lt;p&gt;Public View is our basic default view that has the least number of variables&lt;br&gt;
&lt;a href="http://localhost:8080/levelOne/public" rel="noopener noreferrer"&gt;http://localhost:8080/levelOne/public&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.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%2Fimyd546k56ilgls45fb3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fimyd546k56ilgls45fb3.png" alt="Endpoint 1.2" width="122" height="64"&gt;&lt;/a&gt; &lt;br&gt;
Notice how only the userId column is returned even though the code for both endpoint 1 and 2 are exactly the same. This is done through JsonView.&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 3: With UserNameDetails View
&lt;/h5&gt;

&lt;p&gt;&lt;a href="http://localhost:8080/levelOne/name" rel="noopener noreferrer"&gt;http://localhost:8080/levelOne/name&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.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%2Ffhfextl8rrfjs3v0amfj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffhfextl8rrfjs3v0amfj.png" alt="Endpoint 3" width="182" height="102"&gt;&lt;/a&gt; UserNameDetails extends Public. So, through inheritance, it displays all fields with UserNameDetails  as well as Public. So we see 3 fields in our response.&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 4: With UserDetails View
&lt;/h5&gt;

&lt;p&gt;&lt;a href="http://localhost:8080/levelOne/details" rel="noopener noreferrer"&gt;http://localhost:8080/levelOne/details&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.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%2Femdeurzb8wl4bzn40abl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Femdeurzb8wl4bzn40abl.png" alt="Endpoint 1.4" width="342" height="140"&gt;&lt;/a&gt; UserDetails  extends UserNameDetails which through inheritance means UserDetails extends Public as well. So all fields with UserDetails,UserNameDetails and Public will be available in the response. &lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 5: With OtherDetails View
&lt;/h5&gt;

&lt;p&gt;&lt;a href="http://localhost:8080/levelOne/other" rel="noopener noreferrer"&gt;http://localhost:8080/levelOne/other&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.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%2F0dpidfwsct7t0zgu2qv1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0dpidfwsct7t0zgu2qv1.png" alt="Endpoint 1.5" width="347" height="103"&gt;&lt;/a&gt; OtherDetails does bit extend the above views, instead only the Public View. So Only fields with either OtherDetails or Public will be available in the response.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 1.5 : Add POST Endpoints
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Logger log = LoggerFactory.getLogger(UserController.class);
    /**
     * POST without any view
     *
     * @param user
     */
    @PostMapping("/levelOne/default")
    public User postLevelOneDefault(@RequestBody User user) {
        log.info(String.valueOf(user));
        return user;
    }

    /**
     * POST with Public view
     *
     * @param user
     */
    @PostMapping("/levelOne/name")
    public User postLevelOneDetails(@RequestBody @JsonView(LevelOneViews.UserNameDetails.class) User user) {
        log.info(String.valueOf(user));
        return user;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Step 1.6 : Test the POST Endpoints
&lt;/h4&gt;
&lt;h5&gt;
  
  
  Endpoint 1: Without any Views
&lt;/h5&gt;

&lt;p&gt;Post call to URL:&lt;a href="http://localhost:8080/levelOne/default" rel="noopener noreferrer"&gt;http://localhost:8080/levelOne/default&lt;/a&gt;&lt;br&gt;
Request Body: &lt;br&gt;
&lt;a href="https://media2.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%2Fwxumkaz1n4bav29z7qwv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fwxumkaz1n4bav29z7qwv.png" alt="1.6.1 Request Body" width="357" height="152"&gt;&lt;/a&gt; We are sending the entire structure.&lt;br&gt;
Logger: &lt;code&gt;User(userId=1, firstName=Mark, lastName=Dsouza, email=mark.benjamin.dsouza@google.com, organization=DEV.TO, isActive=true)&lt;/code&gt;&lt;br&gt;
All data gets logged.&lt;br&gt;
&lt;a href="https://media2.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%2F0zdi5g1sz46qqwyoq1sk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2F0zdi5g1sz46qqwyoq1sk.png" alt="1.6.1 Response Body" width="345" height="150"&gt;&lt;/a&gt;&lt;br&gt;
All data gets returned.&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 2: With JsonView
&lt;/h5&gt;

&lt;p&gt;Let us not try this with JsonView endpoint&lt;br&gt;
Post call to URL: &lt;a href="http://localhost:8080/levelOne/name" rel="noopener noreferrer"&gt;http://localhost:8080/levelOne/name&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.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%2Fauxhiisk03nf4aet7tb1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fauxhiisk03nf4aet7tb1.png" alt="1.6.2 Request Body" width="348" height="151"&gt;&lt;/a&gt; &lt;br&gt;
Logger: &lt;code&gt;User(userId=1, firstName=Mark, lastName=Dsouza, email=null, organization=null, isActive=null)&lt;/code&gt;&lt;br&gt;
Notice how even though we sent an entire object only 3 fields got de-serialized. &lt;br&gt;
&lt;a href="https://media2.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%2Fdiavykfqpks8xyo0mozf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fdiavykfqpks8xyo0mozf.png" alt="1.6.2 Response" width="183" height="151"&gt;&lt;/a&gt;  The response is what we saw in the logs. The controller itself did not recieve all fields, so only some fields which are linked with the corresponding view got de-serialized. &lt;/p&gt;
&lt;h3&gt;
  
  
  Takeaway from Level 1
&lt;/h3&gt;

&lt;p&gt;We saw what classes are needed for implementing JsonView and how we can use it for HTTP GET as well as POST requests. We needed to add annotation to the Class that is being serialized/de-serialized as well as the controller endpoint/API. Also, when defining views and using them, inheritance can be used such that one field is associated with multiple views easily. &lt;/p&gt;
&lt;h3&gt;
  
  
  Level 2 : JsonView with multiple classes
&lt;/h3&gt;

&lt;p&gt;In this level, we are going to see how things work when it isn't just a simple Java Class with just Strings and numbers. Let's see how it works when we have objects of other classes as well. These are generally OneToOne(Single Object) and OneToMany(List of Object) relationships.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2.1 : Create JsonView Class
&lt;/h4&gt;

&lt;p&gt;Create the Class containing the different views that need to be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public class LevelTwoViews {
    /*
     * Any variable associated with Public will be picked up by this view
     */
    public interface Public {
    }

    /*
     * Any variable associated with BasicStudentDetails or Public will be picked up by this view
     */
    public interface BasicStudentDetails extends Public {
    }

    /*
     * Any variable associated with BasicStudentDetails, AllStudentDetails or Public will be picked up by this view
     */
    public interface AllStudentDetails extends BasicStudentDetails {
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, again we have used inheritance and created 3 views of increasing access. &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2.2 : Create multiple Java Classes with the @JsonView  on required variables
&lt;/h4&gt;

&lt;p&gt;In Level2, we will be creating multiple classes to illustrate how it works&lt;/p&gt;

&lt;h5&gt;
  
  
  Create Student
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Data
@ToString
public class Student {
    @JsonView(LevelTwoViews.Public.class)
    private String fullName;
    @JsonView(LevelTwoViews.BasicStudentDetails.class)
    private float height;
    @JsonView(LevelTwoViews.BasicStudentDetails.class)
    private float weight;
    @JsonView(LevelTwoViews.Public.class)
    private int age;
    @JsonView(LevelTwoViews.BasicStudentDetails.class)
    private String className;
    // One to Many Relationship
    @JsonView(LevelTwoViews.AllStudentDetails.class)
    private List&amp;lt;SubjectScore&amp;gt; scores;
    // One to One Relationship
    @JsonView(LevelTwoViews.BasicStudentDetails.class)
    private School school;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Create School
&lt;/h5&gt;

&lt;p&gt;One Student has One School - One To One Relationship&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Data
@ToString
public class School {

    @JsonView(LevelTwoViews.BasicStudentDetails.class)
    private String schoolName;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Create SubjectScore
&lt;/h5&gt;

&lt;p&gt;One Student has multiple Subject Scores - One to Many Relationship&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Data
@ToString
public class SubjectScore {
    @JsonView(LevelTwoViews.AllStudentDetails.class)
    private String subject;
    @JsonView(LevelTwoViews.AllStudentDetails.class)
    private int score;
    private String teacher;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that teacher has no view. So irrespective of what JsonView we provide at the controller level, teacher will never get serialized/de-serialized&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2.3 : Create Controller and GET Endpoints
&lt;/h4&gt;

&lt;p&gt;Create endpoints for the views created. We have a few private static methods to create a dummy Object. Here also for all methods the implementation is the same and the only difference is which View we are using.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
public class StudentController {

    /**
     * GET without any json view
     *
     * @return created Student
     */
    @GetMapping("/levelTwo/default")
    public Student getLevelTwoDefault() {
        return createStudent();
    }

    /**
     * GET with lowest view Public
     *
     * @return created Student
     */
    @JsonView(LevelTwoViews.Public.class)
    @GetMapping("/levelTwo/public")
    public Student getLevelTwoPublic() {
        return createStudent();
    }

    /**
     * GET with BasicStudentDetails View which extends Public
     *
     * @return created Student
     */
    @JsonView(LevelTwoViews.BasicStudentDetails.class)
    @GetMapping("/levelTwo/basic")
    public Student getLevelTwoBasicDetails() {
        return createStudent();
    }

    /**
     * GET with AllStudentDetails View which extends BasicStudentDetails,Public
     *
     * @return created Student
     */
    @JsonView(LevelTwoViews.AllStudentDetails.class)
    @GetMapping("/levelTwo/all")
    public Student getLevelTwoAllDetails() {
        return createStudent();
    }

    private static Student createStudent() {
        Student student = new Student();
        student.setAge(15);
        student.setFullName("Mark Dsouza");
        student.setWeight(49);
        student.setHeight(150);
        student.setClassName("VIII");
        student.setSchool(createSchool());
        student.setScores(createSubjectScoreList());
        return student;
    }
    private static School createSchool() {
        School school = new School();
        school.setSchoolName("Indian Public School");
        return school;
    }
    private static List&amp;lt;SubjectScore&amp;gt; createSubjectScoreList() {
        List&amp;lt;SubjectScore&amp;gt; subjectScoreList = new ArrayList&amp;lt;&amp;gt;();
        SubjectScore mathScore = new SubjectScore();
        mathScore.setScore(80);
        mathScore.setSubject("Math");
        mathScore.setTeacher("Mr. John Watts");
        SubjectScore englishScore = new SubjectScore();
        englishScore.setScore(80);
        englishScore.setSubject("English");
        englishScore.setTeacher("Mrs. Mary Johnson");
        subjectScoreList.add(mathScore);
        subjectScoreList.add(englishScore);
        return subjectScoreList;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have created 4 GET Endpoints, one with no view and 3 with the views we created.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 2.4 : Test the GET Endpoints
&lt;/h4&gt;

&lt;p&gt;Run the SpringBoot application and let us test out our endpoints for level 2 GET methods. &lt;/p&gt;

&lt;h5&gt;
  
  
  Endpoint 1: Without any View
&lt;/h5&gt;

&lt;p&gt;Http Method: GET&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelTwo/default" rel="noopener noreferrer"&gt;http://localhost:8080/levelTwo/default&lt;/a&gt;&lt;br&gt;
Response: &lt;br&gt;
&lt;a href="https://media2.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%2Fxpxqw3zrfg7h63v9aw9o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fxpxqw3zrfg7h63v9aw9o.png" alt="2.4.1" width="323" height="402"&gt;&lt;/a&gt; &lt;br&gt;
Here we get back all the data of the object and objects children as well.&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 2: With Public View
&lt;/h5&gt;

&lt;p&gt;Http Method: GET&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelTwo/public" rel="noopener noreferrer"&gt;http://localhost:8080/levelTwo/public&lt;/a&gt;&lt;br&gt;
Response: &lt;br&gt;
&lt;a href="https://media2.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%2Fa5tyjnmq5unjyv9uyb69.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fa5tyjnmq5unjyv9uyb69.png" alt="2.4.2" width="220" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see only data with Public View&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 3: With BasicStudentDetails
&lt;/h5&gt;

&lt;p&gt;Http Method: GET&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelTwo/basic" rel="noopener noreferrer"&gt;http://localhost:8080/levelTwo/basic&lt;/a&gt;&lt;br&gt;
Response: &lt;br&gt;
&lt;a href="https://media2.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%2Fbib2hsq34uod6r8dv2yh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fbib2hsq34uod6r8dv2yh.png" alt="2.4.3" width="323" height="197"&gt;&lt;/a&gt;&lt;br&gt;
Notice how scores isnt included in this view as we have not given the required view for that object in our main class Student.&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 4: With AllStudentDetails View
&lt;/h5&gt;

&lt;p&gt;Http Method: GET&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelTwo/all" rel="noopener noreferrer"&gt;http://localhost:8080/levelTwo/all&lt;/a&gt;&lt;br&gt;
Response: &lt;br&gt;
&lt;a href="https://media2.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%2Fjcieonz29r1gn99ntb6j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fjcieonz29r1gn99ntb6j.png" alt="2.4.4" width="323" height="368"&gt;&lt;/a&gt;&lt;br&gt;
Similarly, here the teacher of class Score is not present as the view wasnt defined. &lt;/p&gt;
&lt;h4&gt;
  
  
  Step 2.5 : Add POST Endpoints
&lt;/h4&gt;

&lt;p&gt;Now create the POST Endpoints&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    Logger log = LoggerFactory.getLogger(StudentController.class);
    /**
     * POST Mapping without any views
     *
     * @param student
     * @return same student
     */
    @PostMapping("/levelTwo/default")
    public Student postLevelTwoDefault(@RequestBody Student student) {
        log.info(student.toString());
        return student;
    }

    /**
     * POST Mapping with Public View. Instance variables of Student without Public view will not be deserialized
     *
     * @param student
     * @return same student
     */
    @PostMapping("/levelTwo/public")
    public Student postLevelTwoBasic(@RequestBody @JsonView(LevelTwoViews.Public.class) Student student) {
        log.info(student.toString());
        return student;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Step 2.6 : Test the POST Endpoints
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Endpoint 5: POST without a view
&lt;/h5&gt;

&lt;p&gt;Http Method: POST&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelTwo/default" rel="noopener noreferrer"&gt;http://localhost:8080/levelTwo/default&lt;/a&gt;&lt;br&gt;
Request Body: &lt;br&gt;
&lt;a href="https://media2.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%2Fch7gln9j3ol377m8u2ys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fch7gln9j3ol377m8u2ys.png" alt="2.4.1 Request Body" width="337" height="406"&gt;&lt;/a&gt; &lt;br&gt;
Logger: &lt;code&gt;Student(fullName=Mary Jane, height=137.0, weight=34.0, age=16, className=X, scores=[SubjectScore(subject=Math, score=90, teacher=Mr. John Watts), SubjectScore(subject=English, score=40, teacher=Mrs. Mary Johnson)], school=School(schoolName=New York Public School))&lt;/code&gt;&lt;br&gt;
We have logged what is recieved by the controller and see all fields hav valid data.&lt;br&gt;
Response: &lt;br&gt;
&lt;a href="https://media2.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%2Fotg27nfoq0c66whj6bep.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fotg27nfoq0c66whj6bep.png" alt="2.4.1 response" width="339" height="402"&gt;&lt;/a&gt;&lt;br&gt;
We see the same data that is sent is returned completely.&lt;/p&gt;
&lt;h5&gt;
  
  
  Endpoint 6: POST with a view
&lt;/h5&gt;

&lt;p&gt;Http Method: POST&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelTwo/public" rel="noopener noreferrer"&gt;http://localhost:8080/levelTwo/public&lt;/a&gt; &lt;br&gt;
Request Body: &lt;a href="https://media2.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%2Fch7gln9j3ol377m8u2ys.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fch7gln9j3ol377m8u2ys.png" alt="2.4.2 Request Body" width="337" height="406"&gt;&lt;/a&gt; We use the same request as earlier&lt;br&gt;
Logger: &lt;code&gt;Student(fullName=Mary Jane, height=0.0, weight=0.0, age=16, className=null, scores=null, school=null)&lt;/code&gt;&lt;br&gt;
Notice the difference here, almost EVERYTHING(except fullName and age) is defaulted even though we sent the entire data as the request body. This is where JsonView works its magic. Even though we send all the data, JsonView de-serializes ONLY the data mentioned with the appropriate view(in this case Public, which is givne only to two fields). &lt;br&gt;
Response: &lt;br&gt;
&lt;a href="https://media2.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%2Ffsrxopeqmkpz5xejm7q9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Ffsrxopeqmkpz5xejm7q9.png" alt="2.4.2 Response" width="210" height="176"&gt;&lt;/a&gt;&lt;br&gt;
Since the controller itself didnt get the data, the data returned also is only what was made visible by JsonView. &lt;/p&gt;
&lt;h4&gt;
  
  
  Takeaway from Level 2
&lt;/h4&gt;

&lt;p&gt;In Level 2, we saw how we can work with multiple Classes and how we can use views across them to achieve the data structure that we need.&lt;/p&gt;
&lt;h3&gt;
  
  
  Level 3: Using Entities with JsonView
&lt;/h3&gt;

&lt;p&gt;In Level 3, we will use a H2 Database to pick data from instead of just some dummy data. And we will directly use the &lt;code&gt;@JsonView&lt;/code&gt; on the Entity itself. This helps us eliminate the use of any DTO, RequestModel, ResponseModel. &lt;br&gt;
Note: The Github code has included data.sql and schema.sql in the src/main/resources folder and some properties in application.properties which will automatically create the schema and insert data into the H2 DB. &lt;/p&gt;
&lt;h4&gt;
  
  
  Step 3.1 : Create JsonView Class
&lt;/h4&gt;

&lt;p&gt;Create the Class containing the different views that need to be created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/**
 * List of Views for LevelThree functionality.
 */
public class LevelThreeViews {
    /*
     * Any variable associated with Public will be picked up by this view
     */
    public interface Public {
    }

    /*
     * Any variable associated with CustomerDetails or Public will be picked up by this view
     */
    public interface CustomerDetails extends Public {
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have created 2 views, Public and CustomerDetails.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3.2 : Create Java Entity with the @JsonView on required variables
&lt;/h4&gt;

&lt;p&gt;While creating our Entity, add additional &lt;code&gt;@JsonView&lt;/code&gt; for the required instance variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Entity
@Table(name = "customer")
@Data
public class Customer {
    @Id
    @GeneratedValue
    private Long id;
    @Column(name = "CUSTOMER_ID", nullable = false)
    @JsonView(LevelThreeViews.Public.class)
    private String customerId;
    @Column(name = "FIRST_NAME", nullable = false, length = 50)
    @JsonView(LevelThreeViews.CustomerDetails.class)
    private String firstName;
    @Column(name = "LAST_NAME", nullable = false, length = 50)
    @JsonView(LevelThreeViews.CustomerDetails.class)
    private String lastName;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The 'id' column does not have any view associated with it. We do not want to expose our DB's Primary Key to any client of our API. Instead we only expose the CUSTOMER_ID which a String value. &lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3.3 : Create Controller and GET Endpoints
&lt;/h4&gt;

&lt;p&gt;Create endpoints with the multiple views created. Here for all methods, we fetch the data from the DB. The code is exactly the same for all APIs, the only difference is which View we are using.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
public class CustomerController {
    @Autowired
    private CustomerRepository customerRepository;

    /**
     * GET Mapping without JsonView
     * @return List of Customer inserted in the DB
     */
    @GetMapping("/levelThree/default")
    public List&amp;lt;Customer&amp;gt; getLevelThree() {
        return customerRepository.findAll();
    }

    /**
     * GET Mapping with Public JsonView
     * @return List of Customer inserted in the DB
     */
    @JsonView(LevelThreeViews.Public.class)
    @GetMapping("/levelThree/public")
    public List&amp;lt;Customer&amp;gt; getLevelThreePublic() {
        return customerRepository.findAll();
    }

    /**
     * GET Mapping with CustomerDetails JsonView which extends Public as well
     * @return List of Customer inserted in the DB
     */
    @JsonView(LevelThreeViews.CustomerDetails.class)
    @GetMapping("/levelThree/details")
    public List&amp;lt;Customer&amp;gt; getLevelThreeDetails() {
        return customerRepository.findAll();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Overall we have 3 endpoints to see the difference between NoView, PublicView and CustomerDetailsView.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 3.4 : Test the GET Endpoints
&lt;/h4&gt;

&lt;p&gt;Run the springboot application and lets test out our endpoints. &lt;/p&gt;

&lt;h5&gt;
  
  
  Endpoint 1: Without any View
&lt;/h5&gt;

&lt;p&gt;Http Method: GET &lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelThree/default" rel="noopener noreferrer"&gt;http://localhost:8080/levelThree/default&lt;/a&gt;&lt;br&gt;
Response: &lt;a href="https://media2.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%2Fmmhwamn9xhm3d1yah26j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fmmhwamn9xhm3d1yah26j.png" alt="3.4.1 Response" width="451" height="580"&gt;&lt;/a&gt;&lt;br&gt;
All fields are returned since there is no view for this API&lt;/p&gt;

&lt;h5&gt;
  
  
  Endpoint 2: With Public View
&lt;/h5&gt;

&lt;p&gt;Http Method: GET&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelThree/public" rel="noopener noreferrer"&gt;http://localhost:8080/levelThree/public&lt;/a&gt;&lt;br&gt;
Response: &lt;a href="https://media2.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%2Fcmp8ywfmr0uz0lwnt8t1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fcmp8ywfmr0uz0lwnt8t1.png" alt="3.4.2 Response" width="441" height="308"&gt;&lt;/a&gt;&lt;br&gt;
Notice that only fields with Public View are returned. &lt;/p&gt;

&lt;h5&gt;
  
  
  Endpoint 3: With CustomerDetailsView
&lt;/h5&gt;

&lt;p&gt;Http Method: GET&lt;br&gt;
URL: &lt;a href="http://localhost:8080/levelThree/details" rel="noopener noreferrer"&gt;http://localhost:8080/levelThree/details&lt;/a&gt;&lt;br&gt;
Response: &lt;a href="https://media2.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%2Frvv26tpu3zhokahydu80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Frvv26tpu3zhokahydu80.png" alt="3.4.3 Response" width="448" height="493"&gt;&lt;/a&gt;&lt;br&gt;
Notice that fields with Public and CustomerDetailsView are returned. But it does not contain the id column since we havent given the annotation and view name for the id column.&lt;/p&gt;

&lt;h4&gt;
  
  
  Takeaway from Level 3
&lt;/h4&gt;

&lt;p&gt;Level 3 showed us how we can use entities directly and securely hide data that we dont want exposed in any APIs. This includes any sequence generated columns or audit columns or any other column as well. Similar to what we saw in Level 2, we can have related entities as well with OneToOne, OneToMany and ManyToOne Annotations. &lt;br&gt;
Side Note: If you are implementing this in your code and have multiple relationships, you could run into a cyclic reference issue during deserialization. Check out JsonManagedReference and JsonBackReference on StackOverflow to solve the issue. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Throughout this tutorial, we have seen different instances of how we can use &lt;code&gt;@JsonView&lt;/code&gt; for HTTP calls when it the object is part of a response or the object is part of the request body. We also saw how we can use multiple classes and entities with JsonView.&lt;br&gt;
I hope you find this useful and let me know in the comments or DM me on twitter if you have any questions. Cheers and Happy Coding!&lt;/p&gt;

</description>
      <category>jsonview</category>
      <category>springboot</category>
      <category>java</category>
      <category>jackson</category>
    </item>
    <item>
      <title>Apache Airflow for Beginners</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Thu, 28 Apr 2022 12:04:48 +0000</pubDate>
      <link>https://forem.com/markbdsouza/apache-airflow-for-beginners-16o</link>
      <guid>https://forem.com/markbdsouza/apache-airflow-for-beginners-16o</guid>
      <description>&lt;p&gt;In this blog post, we are going to take a look at how we can setup Apache Airflow on our systems and get you as a developer, started off with just the bare minimum so you can start working on it.&lt;br&gt;
For detailed documentation please always refer the &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/concepts/index.html" rel="noopener noreferrer"&gt;Airflow official Documentation&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Introduction to Airflow
&lt;/h1&gt;

&lt;p&gt;Airflow is a workflow management platform for data engineering pipelines. It helps define workflows with python code and provides a rich UI to manage and monitor these workflows. Airflow supports easy integration with all popular external interfaces like DBs(SQL and MongoDB), SSH, FTP, Cloud providers etc. It sounds like it does a lot and it does, and can be intimidating, but it is really easy to get started.&lt;br&gt;
The biggest plus point about Airflow is its user friendly UI. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Common Terms used in Airflow
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;DAG (Directed acyclic graph)
A DAG is a python(.py) file that defines what the steps are in our workflow. Each DAG has some common configuration and details of what task needs to be done at each step. Note: You do not need to know advanced python to start working on DAGs but should know the basics. &lt;/li&gt;
&lt;li&gt;Tasks - 
Each step of our workflow is called a Task. We can provide different relationship/dependencies between tasks. 
Example: Task2 should run after Task1. And Task3 should run after Task2. Task4 should run if Task1, Task2 and Task3 are successful only. Task5 should run if either Task1, Task2 or Task3 fail. &lt;/li&gt;
&lt;li&gt;Operators - 
Now tasks are executed using certain Airflow operators. There are around &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/_api/airflow/operators/index.html" rel="noopener noreferrer"&gt;50 Operators&lt;/a&gt; defined. Each operator has configuration that can be done to suit our requirement. We can even call python functions and use the output
2 or a bash operator and execute a specific command. &lt;/li&gt;
&lt;li&gt;Connections &amp;amp; Hooks - 
There is a layer between the code and the connection details. Airflow already has integration with many external interfaces so you do not need write low level code. For example if you need a DB connection, in the Airflow UI you will create a connection with the host name, port, username and password of the connection and provide a conn_id(connection id). And in your DAG(Python code) you will ONLY use the conn_id as a reference. This segregates your code from the connection configuration and makes it reusable across environments as well.&lt;/li&gt;
&lt;li&gt;XComs - 
XCom(Cross Communication) is basically the data that flows between Task1 and Task2. Note: the data passed between tasks should be very minimal and we should not pass large objects.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Installing Airflow with Docker Compose
&lt;/h2&gt;

&lt;p&gt;Now that we have seen the popular concepts, let us get airflow up and running on our local machine. &lt;br&gt;
You can follow the &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/start/index.html" rel="noopener noreferrer"&gt;official documentation for installation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will go through a very simple setup here. &lt;br&gt;
Prerequisite: docker and docker compose should already be installed. &lt;br&gt;
Download the &lt;a href="https://airflow.apache.org/docs/apache-airflow/stable/docker-compose.yaml" rel="noopener noreferrer"&gt;Airflow docker compose file&lt;/a&gt; created by the Airflow team: &lt;br&gt;
Save it on your local machine in a folder of your choice and run&lt;/p&gt;

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

docker-compose up


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

&lt;/div&gt;

&lt;p&gt;You should see the various images being downloaded(takes a lot of time the very first you run the command) and you will see containers starting up. &lt;br&gt;
After a while all your containers will be up. &lt;br&gt;
To check this open a new terminal in parallel and run &lt;/p&gt;

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

docker container ls


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

&lt;/div&gt;

&lt;p&gt;You should see 7 containers running&lt;br&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%2F59ka4slifnfxqyqte0i2.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%2F59ka4slifnfxqyqte0i2.png" alt="Airflow docker containers"&gt;&lt;/a&gt;&lt;br&gt;
Now go to localhost:8080 and you have the below page opening up&lt;br&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%2Fbxqki3ehs9n7xrm0s5a5.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%2Fbxqki3ehs9n7xrm0s5a5.png" alt="Airflow Login Page"&gt;&lt;/a&gt;&lt;br&gt;
Username: airflow&lt;br&gt;
Password: airflow &lt;br&gt;
This will open up your home screen&lt;/p&gt;

&lt;h1&gt;
  
  
  Explore features of Airflow
&lt;/h1&gt;

&lt;p&gt;Let us now see the various features of Airflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Home Screen
&lt;/h2&gt;

&lt;p&gt;Our Home Screen shows &lt;br&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%2Ftqqf39alk63orkwco4l6.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%2Ftqqf39alk63orkwco4l6.png" alt="Airflow home"&gt;&lt;/a&gt;&lt;br&gt;
 Your home screen is auto loaded with a bunch of pre-defined DAGs. This is for your reference and you to play around with when creating your own DAG!! &lt;/p&gt;

&lt;h2&gt;
  
  
  DAG Views
&lt;/h2&gt;

&lt;p&gt;Let's look at the first DAG - example bash operator&lt;/p&gt;

&lt;h3&gt;
  
  
  Tree View
&lt;/h3&gt;

&lt;p&gt;Click on the DAG to bring up the details&lt;br&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%2Fn9jvvitmlhh620a7qvrn.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%2Fn9jvvitmlhh620a7qvrn.png" alt="Tree View"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This brings up the Tree view and shows how the steps are linked in a tree like structure.&lt;br&gt;
Make sure that you Activate the DAG by clicking the switch button on the top right. This can be done for the home page as well if you noticed. &lt;br&gt;
Once you click it, you can click on the Run button on the top right to execute the DAG. On clicking Run, choose 'Run DAG' option. The Run DAG w/ config option is if you have some custom configuration for the DAG which is not required in this case. &lt;br&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%2Fw7cc82g85qw9wy9dn23y.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%2Fw7cc82g85qw9wy9dn23y.png" alt="Run DAG"&gt;&lt;/a&gt;&lt;br&gt;
Congrats, you've run your very first DAG.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code View
&lt;/h3&gt;

&lt;p&gt;A lot of the different views are for monitoring purposes once the code is deployed. To see the code itself click on the last view the Code View.&lt;br&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%2Fb5b5080exihop9telqvz.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%2Fb5b5080exihop9telqvz.png" alt="Code View"&gt;&lt;/a&gt; The airflow team has given us a couple of DAGs pre built and we can now check what is written.&lt;br&gt;
Below is the code for this particular DAG &lt;/p&gt;

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

#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

"""Example DAG demonstrating the usage of the BashOperator."""

import datetime

import pendulum

from airflow import DAG
from airflow.operators.bash import BashOperator
from airflow.operators.dummy import DummyOperator

with DAG(
    dag_id='example_bash_operator',
    schedule_interval='0 0 * * *',
    start_date=pendulum.datetime(2021, 1, 1, tz="UTC"),
    catchup=False,
    dagrun_timeout=datetime.timedelta(minutes=60),
    tags=['example', 'example2'],
    params={"example_key": "example_value"},
) as dag:
    run_this_last = DummyOperator(
        task_id='run_this_last',
    )

    # [START howto_operator_bash]
    run_this = BashOperator(
        task_id='run_after_loop',
        bash_command='echo 1',
    )
    # [END howto_operator_bash]

    run_this &amp;gt;&amp;gt; run_this_last

    for i in range(3):
        task = BashOperator(
            task_id='runme_' + str(i),
            bash_command='echo "{{ task_instance_key_str }}" &amp;amp;&amp;amp; sleep 1',
        )
        task &amp;gt;&amp;gt; run_this

    # [START howto_operator_bash_template]
    also_run_this = BashOperator(
        task_id='also_run_this',
        bash_command='echo "run_id={{ run_id }} | dag_run={{ dag_run }}"',
    )
    # [END howto_operator_bash_template]
    also_run_this &amp;gt;&amp;gt; run_this_last

# [START howto_operator_bash_skip]
this_will_skip = BashOperator(
    task_id='this_will_skip',
    bash_command='echo "hello world"; exit 99;',
    dag=dag,
)
# [END howto_operator_bash_skip]
this_will_skip &amp;gt;&amp;gt; run_this_last

if __name__ == "__main__":
    dag.cli()


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

&lt;/div&gt;

&lt;p&gt;Well you do need to know a bit of Python to understand the syntax and coding. But just the basics is more than enough to get started with DAGs.&lt;br&gt;
Note: You CANNOT change the DAG in the UI directly. You need to do modify the Python file containing the DAG code and place it in the appropriate folder to do so&lt;/p&gt;

&lt;h3&gt;
  
  
  Graph View
&lt;/h3&gt;

&lt;p&gt;Another important view is the graph view&lt;br&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%2Fti0oks2x9gbkqgrzz0pi.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%2Fti0oks2x9gbkqgrzz0pi.png" alt="DAG Graph View"&gt;&lt;/a&gt;&lt;br&gt;
By clicking one of the steps, you will get a popup which gives you many step level options&lt;br&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%2Fadv5x8ohz5mv6ihxobfv.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%2Fadv5x8ohz5mv6ihxobfv.png" alt="Step details"&gt;&lt;/a&gt;&lt;br&gt;
Probably the most important is the Log Option. This will give you all the details of the logs on the machine when the particular step was executed &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%2F3nsa82hlt08fzcpmzxdy.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%2F3nsa82hlt08fzcpmzxdy.png" alt="Log of DAG Step"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Make sure you go through the other views and see what can be used for your project. &lt;/p&gt;

&lt;h3&gt;
  
  
  DAGS Active Filter
&lt;/h3&gt;

&lt;p&gt;On navigating back to the home screen you will notice that there  are 3 tabs on the top. &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%2Fv70xoy5pp0lhr8r1rghk.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%2Fv70xoy5pp0lhr8r1rghk.png" alt="Active DAGs"&gt;&lt;/a&gt; &lt;br&gt;
Always remember that even if you try and run a DAG, it won't run until it is 'Active'&lt;/p&gt;

&lt;h2&gt;
  
  
  Admin
&lt;/h2&gt;

&lt;p&gt;Another important place to keep an eye out for is the Admin dropdown. &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%2Fim0c3a293oi791ch1kn5.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%2Fim0c3a293oi791ch1kn5.png" alt="Admin dropdown"&gt;&lt;/a&gt;&lt;br&gt;
Lets look at 3 of these options&lt;/p&gt;

&lt;h3&gt;
  
  
  Variables
&lt;/h3&gt;

&lt;p&gt;Variables allow you to have global level variables used across the application&lt;/p&gt;

&lt;h3&gt;
  
  
  Connections
&lt;/h3&gt;

&lt;p&gt;Almost always you will want your airflow workflow to talk to some external service. Connections provides an interface between the actual connection string/details and the code you need to write. In the code you can refer the connection name and the details of connection can vary in each environment of airflow. This can even be a HTTP Connection for a REST API Call. &lt;br&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%2Fm1ppa9mhgz16uwn8iddb.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%2Fm1ppa9mhgz16uwn8iddb.png" alt="Image description"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  XComs
&lt;/h3&gt;

&lt;p&gt;You can view the data passed between steps in your DAG.&lt;br&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%2Fawombx0voalmqeeeb8y9.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%2Fawombx0voalmqeeeb8y9.png" alt="XComs"&gt;&lt;/a&gt;&lt;br&gt;
It provides the DAG id and task id and you can easily debug runs here instead of checking the logs of multiple runs. &lt;/p&gt;

&lt;p&gt;With these views you probably get the most important features of Airflow from a developers point of view. &lt;/p&gt;

&lt;h2&gt;
  
  
  Creating and Running our own DAG
&lt;/h2&gt;

&lt;p&gt;Now, lets create a simple simple DAG and run it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Create the .py file
&lt;/h3&gt;

&lt;p&gt;On navigating back to your docker-compose folder. You should see 3 folders automatically created. dags, logs and plugins.&lt;br&gt;
To add a DAG to the airflow instace, create a .py file ib the dags folder. Below is a sample file&lt;/p&gt;

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

from airflow import DAG
from datetime import datetime
from airflow.operators.http_operator import SimpleHttpOperator


with DAG("http_test_dag", start_date=datetime(2021, 1, 1), schedule_interval="@daily", catchup=False) as dag:
    http_call = SimpleHttpOperator(
        task_id="HttpCall",
        http_conn_id='springboot-http',
        endpoint='',
        method='GET',
        headers={"Content-Type": "application/json"},
        data=None,
        log_response=True,
        response_check=lambda response: response.ok)


http_call


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

&lt;/div&gt;

&lt;p&gt;This DAG uses a simple Http operator that makes a call to the connection - 'springboot-http'. This is a connection that is expected to be generated in the admin&amp;gt;connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating Airflow
&lt;/h3&gt;

&lt;p&gt;Airflow automatically will pick up your new DAG file if placed in the folder. You do not need to do anything to deploy. &lt;br&gt;
A common mistake is looking at the Code tab of a deployed DAG and refreshing and expecting to see your new code but it doesn't get updated. You might be inclined to think something is wrong with airflow and you need to stop and restart the docker containers. But the issue is with the modifications you have made in the DAG. If the code doesn't compile, the code in the code tab won't get updated. &lt;br&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%2Fjvh0gtrf77ym5760emvq.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%2Fjvh0gtrf77ym5760emvq.png" alt="Updated home page"&gt;&lt;/a&gt;&lt;br&gt;
Now you can activate the DAG and run it!!&lt;/p&gt;

&lt;p&gt;I hope this post is helpful for anyone trying to learn about Airflow and just get quickly started so you can play around with it.&lt;/p&gt;

</description>
      <category>airflow</category>
      <category>datascience</category>
      <category>python</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Pagination(with Hateoas), Filtering &amp; Sorting with Spring Boot and JPA</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Thu, 07 Apr 2022 08:04:02 +0000</pubDate>
      <link>https://forem.com/markbdsouza/paginationwith-hateoas-filtering-sorting-with-spring-boot-and-jpa-1mpp</link>
      <guid>https://forem.com/markbdsouza/paginationwith-hateoas-filtering-sorting-with-spring-boot-and-jpa-1mpp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this blog post we are going to look at how we can implement pagination with hateoas while supporting filtering and sorting in a spring boot application. We will first start off implementing filtering, and then iteratively page, sorting and finally pagination wtih Hateoas. &lt;/p&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;p&gt;Below are the list of languages, frameworks and libraries used in this tutorial&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Java 11&lt;/li&gt;
&lt;li&gt;Maven&lt;/li&gt;
&lt;li&gt;h2 in memory database&lt;/li&gt;
&lt;li&gt;REST apis&lt;/li&gt;
&lt;li&gt;SpringBoot 2.6.6&lt;/li&gt;
&lt;li&gt;Spring Data jpa&lt;/li&gt;
&lt;li&gt;Hateoas &lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Usecase for Hateoas with pagination and filterin/sorting
&lt;/h3&gt;

&lt;p&gt;When fetching data from a table you probably implement your response object as a &lt;code&gt;List&amp;lt;Object&amp;gt;&lt;/code&gt;. This works perfectly fine if it is a small data set. &lt;br&gt;
When you have a data set that is 'large', you do not want to send the data to the client all at once. Imagine you have 100k rows in your table and each row has 10 columns. If the user is only vieweing maybe 50 rows in the UI(our client) at a specific time, why send 100k rows? &lt;br&gt;
Unless it a specific export functionality, you shouldn't send back all the data to the user. Instead you should send a subset of the data only.&lt;br&gt;
At the same time, we do not want to restrict the user from seeing all the data. If the user wants to add a filter or sort some data out of these 100k rows, he should be able to do it.&lt;br&gt;
From a front end perspective, if the user clicks on the next page, they will do another call to the backend to get the next set of data. &lt;br&gt;
This is where Pagination + Filtering + Sorting becomes very very helpful. &lt;br&gt;
Hateoas also provides links to other pages which is extremely helpful as we will see. &lt;/p&gt;

&lt;h3&gt;
  
  
  What will our end result look like
&lt;/h3&gt;

&lt;p&gt;Before we get into the details, take a look at our request URL and the Response format we finally end up with. We will create a long url because we are allowing a high level of customization. &lt;/p&gt;

&lt;p&gt;Request URL: &lt;code&gt;http://localhost:8080/api/v4/customers?firstNameFilter=R&amp;amp;lastNameFilter=S&amp;amp;page=0&amp;amp;size=10&amp;amp;sortList=firstName&amp;amp;sortOrder=ASC&lt;/code&gt;&lt;br&gt;
Response: &lt;/p&gt;

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

{
   "_embedded": {
      "customerModelList": [
         {
         "id": 971,
         "customerId": "de6b8664-ba90-41fc-a9f4-da7d0b89c106",
         "firstName": "Rabi",
         "lastName": "Dufour"
         },
         {
         "id": 339,
         "customerId": "44b5c01d-c379-4f66-b8ed-0fda4837db4e",
         "firstName": "Rachelle",
         "lastName": "Fleischer"
         },
         {
         "id": 838,
         "customerId": "443b06fd-7160-4234-9102-93afb0f6d9ad",
         "firstName": "Rafaelia",
         "lastName": "Bladen"
         }
      ]
   },
   "_links": {
      "first": {
         "href": "http://localhost:8080/api/v4/customers?firstNameFilter=R&amp;amp;sortList=firstName&amp;amp;sortOrder=ASC&amp;amp;page=0&amp;amp;size=3&amp;amp;sort=firstName,asc"
      },
      "self": {
         "href": "http://localhost:8080/api/v4/customers?firstNameFilter=R&amp;amp;sortList=firstName&amp;amp;sortOrder=ASC&amp;amp;page=0&amp;amp;size=3&amp;amp;sort=firstName,asc"
      },
      "next": {
        "href": "http://localhost:8080/api/v4/customers?firstNameFilter=R&amp;amp;sortList=firstName&amp;amp;sortOrder=ASC&amp;amp;page=1&amp;amp;size=3&amp;amp;sort=firstName,asc"
      },
      "last": {
        "href": "http://localhost:8080/api/v4/customers?firstNameFilter=R&amp;amp;sortList=firstName&amp;amp;sortOrder=ASC&amp;amp;page=19&amp;amp;size=3&amp;amp;sort=firstName,asc"
      }
   },
   "page": {
      "size": 3,
      "totalElements": 60,
      "totalPages": 20,
      "number": 0
   }
}


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

&lt;/div&gt;

&lt;p&gt;As you can see in this case, the endpoint provides you links on how you can access the other data. It also tells you how much data is there, how many pages and the elements per page and more. This is extremely helpful for any client accessing our API to traverse through the data. &lt;/p&gt;

&lt;h3&gt;
  
  
  Github link
&lt;/h3&gt;

&lt;p&gt;The entire code discussed below is available on Github&lt;br&gt;
&lt;a href="https://github.com/markbdsouza/hateoas-with-pagination" rel="noopener noreferrer"&gt;https://github.com/markbdsouza/hateoas-with-pagination&lt;/a&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  Create a Base spring boot app
&lt;/h1&gt;

&lt;p&gt;First before we get to the actual code, let's walk through our base code and set up a simple controller, service, entity and repository. Something you'd do for any spring boot application. Then let's also set up the Database and insert some data. &lt;br&gt;
&lt;strong&gt;NOTE:&lt;/strong&gt; Skip this section if you just need to see how the implementation is done. This is only for anyone following along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create base app
&lt;/h2&gt;

&lt;p&gt;You can create the base application by using the start.spring.io website. &lt;br&gt;
Enter your app details and add the below dependencies&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;Spring Data JPA&lt;/li&gt;
&lt;li&gt;H2 Database&lt;/li&gt;
&lt;li&gt;Spring HATEOAS
&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%2Fr6vizw8riyabwgtpmysx.PNG" alt="Spring Initializr for hateoas"&gt;
This will auto create your pom.xml and project folders &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Create Entity and Repository
&lt;/h2&gt;

&lt;p&gt;We will be creating 1 Entity-customer with 4 fields - id(sequence generated), customerId(unique string), first name and last name. We will also keep getters and setters for encapsulation&lt;/p&gt;

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

@Entity
@Table(name="customer")
public class Customer {
    @Id
    @GeneratedValue
    private Long id;
    @Column(nullable = false, unique = true)
    private String customerId;
    @Column(nullable = false, length = 50)
    private String firstName;
    @Column(nullable = false, length = 50)
    private String lastName;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getCustomerId() {
        return customerId;
    }
    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}


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

&lt;/div&gt;

&lt;p&gt;Create a repoistory interface for the entity. We will update this later.&lt;/p&gt;

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

@Repository
public interface CustomerRepository extends JpaRepository&amp;lt;Customer, Long&amp;gt; {}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Create Service
&lt;/h2&gt;

&lt;p&gt;Now create a simple service file to fetch the data&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

@Service
public class CustomerService {
    @Autowired
    private CustomerRepository customerRepository;

    public List&amp;lt;Customer&amp;gt; fetchCustomerDataAsList() {
        // Fetch all customers using findAll
        return customerRepository.findAll();
    }
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Create Controller
&lt;/h2&gt;

&lt;p&gt;Now lets create a basic controller with a GET request that calls the service method &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

@RestController
public class CustomerController {
    @Autowired
    private CustomerService customerService;
    /**
     * @return List of all customers
     */
    @GetMapping("/api/v0/customers")
    public List&amp;lt;Customer&amp;gt; fetchCustomersAsList() {
        return customerService.fetchCustomerDataAsList();
    }
}


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

&lt;/div&gt;

&lt;p&gt;Now we have all our base code setup. Let's move on to configuring our Database and getting some data inserted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup our Database
&lt;/h2&gt;

&lt;p&gt;Update the application.properties to map our H2 DB &lt;/p&gt;

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

spring.h2.console.enabled=true
spring.h2.console.settings.web-allow-others=true
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.initialization-mode=always
spring.datasource.initialize=true
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=update


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

&lt;/div&gt;

&lt;p&gt;Now with our DB setup, we can use the springboot auto configuration to run scripts on our DB when the application is started.&lt;br&gt;
Create a &lt;code&gt;schema.sql&lt;/code&gt; file&lt;/p&gt;

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

CREATE TABLE customer (
   id INT NOT NULL,
   first_name VARCHAR(100) NOT NULL,
   last_name VARCHAR(100) NOT NULL,
   customer_id VARCHAR(100) NOT NULL
);


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

&lt;/div&gt;

&lt;p&gt;And create a &lt;code&gt;data.sql&lt;/code&gt; file&lt;/p&gt;

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

insert into customer values(1,'Dorine','McGrouther','6252fcab-a17e-4af4-aa70-0fda826e67cf');
insert into customer values(2,'Gerianna','Capstack','f787ce02-06b7-4fc6-be83-408c652e924b');
insert into customer values(3,'Rosemarie','Salerno','4ac787e6-2534-43ea-a86e-16957b7410a2');


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

&lt;/div&gt;

&lt;p&gt;The script in the Github repository has around 1000 customers in the file. &lt;br&gt;
Each time the application runs, since we are using a h2 database, it will run the &lt;code&gt;schema.sql&lt;/code&gt; script and then the &lt;code&gt;data.sql&lt;/code&gt; script which will set up our database environment. &lt;/p&gt;

&lt;h2&gt;
  
  
  Test our base app
&lt;/h2&gt;

&lt;p&gt;To test it out launch the spring boot application with your IDE and use your browser and enter the URL &lt;br&gt;
&lt;code&gt;http://localhost:8080/api/v0/customers&lt;/code&gt;&lt;br&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%2Fhxwrtcinxztysoovlwbp.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%2Fhxwrtcinxztysoovlwbp.png" alt="Data as a json list"&gt;&lt;/a&gt;&lt;br&gt;
If you've used the insert script in the repository, you will get 1000 records in this JSON output.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementing Filtering
&lt;/h1&gt;

&lt;p&gt;Now let us first implement basic filtering in our code. We will allow the user to filter on 2 fields - firstName and/or lastName. For this we will create a new endpoint and pass in these 2 variables as Request parameters with a default value of ""&lt;/p&gt;

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

&lt;p&gt;Add the below query to our CustomerRepository Interface&lt;/p&gt;

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

     String FILTER_CUSTOMERS_ON_FIRST_NAME_AND_LAST_NAME_QUERY = "select b from Customer b where UPPER(b.firstName) like CONCAT('%',UPPER(?1),'%') and UPPER(b.lastName) like CONCAT('%',UPPER(?2),'%')";

    @Query(FILTER_CUSTOMERS_ON_FIRST_NAME_AND_LAST_NAME_QUERY)
    List&amp;lt;Customer&amp;gt; findByFirstNameLikeAndLastNameLike(String firstNameFilter, String lastNameFilter);


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

&lt;/div&gt;

&lt;p&gt;We have written a custom query that will filter based on first name and last name.&lt;br&gt;
Now all we need to do is call it from our service.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Service
&lt;/h2&gt;

&lt;p&gt;Add a new method to our service &lt;/p&gt;

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

    public List&amp;lt;Customer&amp;gt; fetchFilteredCustomerDataAsList(String firstNameFilter, String lastNameFilter) {
        // Apply the filter for firstName and lastName
        return customerRepository.findByFirstNameLikeAndLastNameLike(firstNameFilter, lastNameFilter);
    }


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

&lt;/div&gt;

&lt;p&gt;Notice that we are still returning a &lt;code&gt;List&amp;lt;Customer&amp;gt;&lt;/code&gt;. It is a filtered list though.&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Controller
&lt;/h2&gt;

&lt;p&gt;Add a new endpoint that accepts 2 fields as filter conditions&lt;/p&gt;

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

    /**
     * @param firstNameFilter Filter for the first Name if required
     * @param lastNameFilter  Filter for the last Name if required
     * @return List of filtered customers
     */
    @GetMapping("/api/v1/customers")
    public List&amp;lt;Customer&amp;gt; fetchCustomersAsFilteredList(@RequestParam(defaultValue = "") String firstNameFilter,
                                                       @RequestParam(defaultValue = "") String lastNameFilter) {
        return customerService.fetchFilteredCustomerDataAsList(firstNameFilter, lastNameFilter);
    }


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;Run the application and this hit the v1 URL which we created&lt;br&gt;
&lt;code&gt;http://localhost:8080/api/v1/customers?firstNameFilter=ur&amp;amp;lastNameFilter=as&lt;/code&gt;&lt;br&gt;
Try this out with different filters. Instead of all 1000 customers we will get only the filtered list of customers &lt;br&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%2Fsnuk454qn3tiw4h7gz0e.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%2Fsnuk454qn3tiw4h7gz0e.png" alt="Data as a filtered list"&gt;&lt;/a&gt;&lt;br&gt;
In this case there are only 2 customers with first name containing 'ur' and last name containing 'as'.  &lt;/p&gt;
&lt;h1&gt;
  
  
  Implementing Page with Filtering
&lt;/h1&gt;

&lt;p&gt;Page is a common interface used to fetch data in a page format from our database. Though the format doesnt necessarily contain pertinent information, it still is limited data set and we can apply our filtering logic to it. &lt;/p&gt;
&lt;h2&gt;
  
  
  Update Repository
&lt;/h2&gt;

&lt;p&gt;Add the below query to our CustomerRepository Interface&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    @Query(FILTER_CUSTOMERS_ON_FIRST_NAME_AND_LAST_NAME_QUERY)
    Page&amp;lt;Customer&amp;gt; findByFirstNameLikeAndLastNameLike(String firstNameFilter, String lastNameFilter, Pageable pageable);


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

&lt;/div&gt;

&lt;p&gt;The only difference is that we are also passing a pageable object with the filters and returning a &lt;code&gt;Page&amp;lt;Customer&amp;gt;&lt;/code&gt; instead of &lt;code&gt;List&amp;lt;Customer&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Service
&lt;/h2&gt;

&lt;p&gt;Add a new method to our service &lt;/p&gt;

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

    public Page&amp;lt;Customer&amp;gt; fetchCustomerDataAsPageWithFiltering(String firstNameFilter, String lastNameFilter, int page, int size) {
        // create Pageable object using the page and size
        Pageable pageable = PageRequest.of(page, size);
        // fetch the page object by additionally passing pageable with the filters
        return customerRepository.findByFirstNameLikeAndLastNameLike(firstNameFilter, lastNameFilter, pageable);
    }


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

&lt;/div&gt;

&lt;p&gt;Here we need 2 additional inputs- page and size. Page indicates which page we want to fetch from the DB. And size referes to the number of objects we want on each page. &lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; Page starts at 0 so be careful. &lt;br&gt;
So if there are 1000 objects and we give a page of 2 and size of 50. We will get the third set of 101-150 objects. &lt;/p&gt;

&lt;h2&gt;
  
  
  Update Controller
&lt;/h2&gt;

&lt;p&gt;Add a new endpoint that accepts 2 fields as filter conditions and 2 fields for page functionality&lt;/p&gt;

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

    /**
     * @param firstNameFilter Filter for the first Name if required
     * @param lastNameFilter  Filter for the last Name if required
     * @param page            number of the page returned
     * @param size            number of entries in each page
     * @return Page object with customers after filtering
     */
    @GetMapping("/api/v2/customers")
    public Page&amp;lt;Customer&amp;gt; fetchCustomersWithPageInterface(@RequestParam(defaultValue = "") String firstNameFilter,
                                                          @RequestParam(defaultValue = "") String lastNameFilter,
                                                          @RequestParam(defaultValue = "0") int page,
                                                          @RequestParam(defaultValue = "30") int size) {
        return customerService.fetchCustomerDataAsPageWithFiltering(firstNameFilter, lastNameFilter, page, size);
    }


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

&lt;/div&gt;

&lt;p&gt;Notice that we have kept the default page as 0 and size as 30.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;Run the application and this hit the v2 URL which we created with additional parameters&lt;br&gt;
&lt;code&gt;http://localhost:8080/api/v2/customers?firstNameFilter=Ar&amp;amp;lastNameFilter=sp&amp;amp;page=0&amp;amp;size=30&lt;/code&gt;&lt;br&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%2Flkhk4lh567pzxbtjivhk.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%2Flkhk4lh567pzxbtjivhk.png" alt="Data as a json list with page interface"&gt;&lt;/a&gt;&lt;br&gt;
We can see more information being displayed but it doesn't seem to be too relevant. If required, you could do some custom coding to convert the format. &lt;/p&gt;

&lt;h1&gt;
  
  
  Implementing Page with Filtering and Sorting
&lt;/h1&gt;

&lt;p&gt;Now we will implement sorting to the above logic.&lt;/p&gt;

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

&lt;p&gt;No update in repository is required. We will reuse the previous method that returns a &lt;code&gt;Page&amp;lt;Customer&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Update Service
&lt;/h2&gt;

&lt;p&gt;Add a new method to our service &lt;/p&gt;

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

    public Page&amp;lt;Customer&amp;gt; fetchCustomerDataAsPageWithFilteringAndSorting(String firstNameFilter, String lastNameFilter, int page, int size, List&amp;lt;String&amp;gt; sortList, String sortOrder) {
        // create Pageable object using the page, size and sort details
        Pageable pageable = PageRequest.of(page, size, Sort.by(createSortOrder(sortList, sortOrder)));
        // fetch the page object by additionally passing pageable with the filters
        return customerRepository.findByFirstNameLikeAndLastNameLike(firstNameFilter, lastNameFilter, pageable);
    }

    private List&amp;lt;Sort.Order&amp;gt; createSortOrder(List&amp;lt;String&amp;gt; sortList, String sortDirection) {
        List&amp;lt;Sort.Order&amp;gt; sorts = new ArrayList&amp;lt;&amp;gt;();
        Sort.Direction direction;
        for (String sort : sortList) {
            if (sortDirection != null) {
                direction = Sort.Direction.fromString(sortDirection);
            } else {
                direction = Sort.Direction.DESC;
            }
            sorts.add(new Sort.Order(direction, sort));
        }
        return sorts;
    }


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

&lt;/div&gt;

&lt;p&gt;We have 2 methods. 1 public method that we will call from our controller which has 2 additional inputs - sortList and sortOrder. &lt;br&gt;
SortList takes in the list of string on which we need to sort it and sortOrder takes either ASC or DESC. &lt;br&gt;
The second private method creates the Sort.Order list object which is used in creating the Page object. &lt;/p&gt;

&lt;h2&gt;
  
  
  Update Controller
&lt;/h2&gt;

&lt;p&gt;Add a new endpoint that accepts 2 fields as filter conditions, 2 fields for page functionality and 2 for sort functionality&lt;/p&gt;

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

        /**
     * @param firstNameFilter Filter for the first Name if required
     * @param lastNameFilter  Filter for the last Name if required
     * @param page            number of the page returned
     * @param size            number of entries in each page
     * @param sortList        list of columns to sort on
     * @param sortOrder       sort order. Can be ASC or DESC
     * @return Page object with customers after filtering and sorting
     */
    @GetMapping("/api/v3/customers")
    public Page&amp;lt;Customer&amp;gt; fetchCustomersWithPageInterfaceAndSorted(@RequestParam(defaultValue = "") String firstNameFilter,
                                                                   @RequestParam(defaultValue = "") String lastNameFilter,
                                                                   @RequestParam(defaultValue = "0") int page,
                                                                   @RequestParam(defaultValue = "30") int size,
                                                                   @RequestParam(defaultValue = "") List&amp;lt;String&amp;gt; sortList,
                                                                   @RequestParam(defaultValue = "DESC") Sort.Direction sortOrder) {
        return customerService.fetchCustomerDataAsPageWithFilteringAndSorting(firstNameFilter, lastNameFilter, page, size, sortList, sortOrder.toString());
    }



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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;Run the application and this hit the v3 URL which we created with additional parameters&lt;br&gt;
&lt;code&gt;http://localhost:8080/api/v3/customers?firstNameFilter=Ria&amp;amp;lastNameFilter=ss&amp;amp;page=0&amp;amp;size=5&amp;amp;sortList=firstName&amp;amp;sortOrder=ASC&lt;/code&gt;&lt;br&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%2F6vd9qe9spfyhyu5nvkql.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%2F6vd9qe9spfyhyu5nvkql.png" alt="Data as a json list with page interface sorted and filtered"&gt;&lt;/a&gt;&lt;br&gt;
The only advantage here compared to our last version is that we can sort the data now. &lt;/p&gt;
&lt;h1&gt;
  
  
  Implementing Pagination with HATEOAS
&lt;/h1&gt;

&lt;p&gt;Coming to our final step - implementing hateoas with filtering and sorting.&lt;/p&gt;
&lt;h2&gt;
  
  
  Update Repository
&lt;/h2&gt;

&lt;p&gt;No update in repository is required. We will reuse the already created method returning &lt;code&gt;Page&amp;lt;Customer&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Update Service
&lt;/h2&gt;

&lt;p&gt;No update is required. We will reuse the method returning &lt;code&gt;Page&amp;lt;Customer&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Create files to support Hateoas
&lt;/h2&gt;

&lt;p&gt;Now to use hateoas we convert the page format to a hateoas PagedModel format. To do so we need 2 additional files&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Customer Model (extends RepresentationModel&amp;lt;&amp;gt;)&lt;/li&gt;
&lt;li&gt;Customer Model Assembler(extends RepresentationModelAssemblerSupport&amp;lt;,&amp;gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Create CustomerModel
&lt;/h3&gt;

&lt;p&gt;First off we need to create Customer Model that extends the hateoas RepresentationModel which is part of the body of the response we send. We also create getters and setters for the object variables.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

/**
 * The CustomerModel class extends the Hateoas Representation Model and is required if we want to convert the Customer
 * Entity to a pagination format
 */
public class CustomerModel extends RepresentationModel&amp;lt;CustomerModel&amp;gt; {
    private Long id;
    private String customerId;
    private String firstName;
    private String lastName;

    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getCustomerId() {
        return customerId;
    }
    public void setCustomerId(String customerId) {
        this.customerId = customerId;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
}


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

&lt;/div&gt;

&lt;p&gt;If we dont want the sequence generated id to be returned we can remove it from this object itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create CustomerModelAssembler
&lt;/h3&gt;

&lt;p&gt;Now we need the assembler which extends RepresentationModelAssemblerSupport and we pass in the from object which is our entity and to object which is our newly created Model. We are forced to override the &lt;code&gt;toModel()&lt;/code&gt; method in which we copy the values of the entity to the model.&lt;/p&gt;

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

/**
 * This class extends RepresentationModelAssemblerSupport which is required for Pagination.
 * It converts the Customer Entity to the Customer Model and has the code for it
 */
@Component
public class CustomerModelAssembler extends RepresentationModelAssemblerSupport&amp;lt;Customer, CustomerModel&amp;gt; {
    public CustomerModelAssembler() {
        super(CustomerController.class, CustomerModel.class);
    }

    @Override
    public CustomerModel toModel(Customer entity) {
        CustomerModel model = new CustomerModel();
        // Both CustomerModel and Customer have the same property names. So copy the values from the Entity to the Model
        BeanUtils.copyProperties(entity, model);
        return model;
    }
}


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Update Controller
&lt;/h2&gt;

&lt;p&gt;Autowire 2 components required&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

    @Autowired
    private CustomerModelAssembler customerModelAssembler;

    @Autowired
    private PagedResourcesAssembler&amp;lt;Customer&amp;gt; pagedResourcesAssembler;


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

&lt;/div&gt;

&lt;p&gt;and add a new endpoint that will call the Page&lt;/p&gt;

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

    /**
     * @param firstNameFilter Filter for the first Name if required
     * @param lastNameFilter  Filter for the last Name if required
     * @param page            number of the page returned
     * @param size            number of entries in each page
     * @param sortList        list of columns to sort on
     * @param sortOrder       sort order. Can be ASC or DESC
     * @return PagedModel object in Hateoas with customers after filtering and sorting
     */
    @GetMapping("/api/v4/customers")
    public PagedModel&amp;lt;CustomerModel&amp;gt; fetchCustomersWithPagination(
            @RequestParam(defaultValue = "") String firstNameFilter,
            @RequestParam(defaultValue = "") String lastNameFilter,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "30") int size,
            @RequestParam(defaultValue = "") List&amp;lt;String&amp;gt; sortList,
            @RequestParam(defaultValue = "DESC") Sort.Direction sortOrder) {
        Page&amp;lt;Customer&amp;gt; customerPage = customerService.fetchCustomerDataAsPageWithFilteringAndSorting(firstNameFilter, lastNameFilter, page, size, sortList, sortOrder.toString());
        // Use the pagedResourcesAssembler and customerModelAssembler to convert data to PagedModel format
        return pagedResourcesAssembler.toModel(customerPage, customerModelAssembler);
    }


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

&lt;/div&gt;

&lt;p&gt;Notice how we are using the autowired components. Using the assembler we are converting the &lt;code&gt;Page&amp;lt;Customer&amp;gt;&lt;/code&gt; to &lt;code&gt;PagedModel&amp;lt;Customer&amp;gt;&lt;/code&gt; by calling the &lt;code&gt;toModel()&lt;/code&gt; method&lt;/p&gt;

&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;Run the application and this hit the v4 URL which we created with additional parameters&lt;br&gt;
&lt;code&gt;http://localhost:8080/api/v4/customers?firstNameFilter=R&amp;amp;lastNameFilter=S&amp;amp;page=0&amp;amp;size=4&amp;amp;sortList=firstName&amp;amp;sortOrder=ASC&lt;/code&gt;&lt;br&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%2Fvtj5f34rbyp6qb2my32f.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%2Fvtj5f34rbyp6qb2my32f.png" alt="Data as a hateoas pagination"&gt;&lt;/a&gt;&lt;br&gt;
Taking a closer look at our output we notice some really beneficial information.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;"_links" - this key contains an object with links to the first,self,next and last page. These links can be used from the frontend team to use pagination in the UI. &lt;/li&gt;
&lt;li&gt;"page" - this tells us how many elements, totaly elements after filtering and sorting, total pages and current page number.&lt;/li&gt;
&lt;li&gt;"_embedded" - contains the list of CustomerModels. The actual data that is converted from the entity to the model.&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;I spent a lot of time figuring this out when i needed to implement it at a work project and I hope this helps someone out there needing to do the same. &lt;br&gt;
Check out the Github link and play around with it and see if it works in your project as well. &lt;br&gt;
&lt;a href="https://github.com/markbdsouza/hateoas-with-pagination" rel="noopener noreferrer"&gt;https://github.com/markbdsouza/hateoas-with-pagination&lt;/a&gt; &lt;br&gt;
Feel free to leave a comment, if you have any questions or need any help.&lt;/p&gt;

</description>
      <category>java</category>
      <category>springboot</category>
      <category>jpa</category>
      <category>hateoas</category>
    </item>
    <item>
      <title>Polymorphism in Java - A Quiz on things you probably didn't know</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Wed, 26 Jan 2022 12:29:43 +0000</pubDate>
      <link>https://forem.com/markbdsouza/polymorphism-in-java-a-quiz-on-things-you-probably-didnt-know-24l3</link>
      <guid>https://forem.com/markbdsouza/polymorphism-in-java-a-quiz-on-things-you-probably-didnt-know-24l3</guid>
      <description>&lt;p&gt;Well if you're reading this, you probably know Java and have worked with a Java Framework. The below post is for all levels of Java 8 developers, anyone looking to improve. I'll try and cover some more advanced concepts of how polymorphism works and some gotchas that exist through some questions and answers!&lt;/p&gt;

&lt;h2&gt;
  
  
  Questions
&lt;/h2&gt;

&lt;p&gt;See if you can answer the below questions. They are in increasing order of difficulty. Take your time and answer them. Some will have compilation errors/run time errors. &lt;br&gt;
Write down your answer on a notepad and check them all at once. The answers and their explanations are in the second section of this post. &lt;/p&gt;
&lt;h3&gt;
  
  
  Level 1
&lt;/h3&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;br&gt;
Concepts: Polymorphism&lt;br&gt;
Question: Which lines when commented will the code successfully compile?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.markbdsouza.polymorphism;

interface Movable{ void move();}
interface Eats{ void eat();}
interface Vertebrae extends Movable, Eats{}
class Dog implements Vertebrae {
    public void move() {
        System.out.println("Dog moves on 4 legs");
    }
    public void eat() {
        System.out.println("Dog eats food");
    }
}
public class Level1 {
    public static void main(String[] args) {
        // which lines when commented will the code successfully compile ?
        Movable a = new Dog(); // line 17
        a.move(); // line 18
        a.eat(); // line 19
        Eats b = new Dog(); // line 20
        b.move();// line 21
        b.eat();// line 22
        Vertebrae c = new Dog(); // line 23
        c.move();// line 24
        c.eat();// line 25
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Level 2
&lt;/h3&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;br&gt;
Concepts: Polymorphism &lt;br&gt;
Question: What is the output of the below program?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.markbdsouza.polymorphism;

interface Movable {
   void move();
}
class Fish implements Movable {
   void move(){System.out.println("swims");}
}
public class Level2 {
    public static void main(String[] args) {
        Movable fish = new Fish();
        fish.move();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Level 3
&lt;/h3&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;br&gt;
Concepts : Overriding + Polymorphism&lt;br&gt;
Question: Given that FileNotFoundException and EOFException are child exceptions of IOException, will the below code compile?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.markbdsouza.polymorphism;

import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;

class Animal{
    public void move() throws FileNotFoundException { System.out.println("moves in some way");}
}
class Fish extends Animal{
    public void move() throws FileNotFoundException, EOFException {System.out.println("swims");}
}
public class Level3 {
    public static void main(String[] args) throws IOException {
        Animal z = new Fish(); z.move();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Level 4
&lt;/h3&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;br&gt;
Concept: Polymorphism + Overloading &lt;br&gt;
Question: What is the output of the below program?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.markbdsouza.polymorphism;

class Car {}
class Audi extends Car {}
public class Level4 {
    public void drive(Car car) {
        System.out.println("Using a Car");
    }
    public void drive(Audi audi) {
        System.out.println("Using an Audi");
    }
    public static void main(String[] args) {
        Car car = new Car();
        Audi audi = new Audi();
        Car audiCar = new Audi();
        Level4 myTestClass = new Level4();
        myTestClass.drive(car);
        myTestClass.drive(audi);
        myTestClass.drive(audiCar);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Level 5
&lt;/h3&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;br&gt;
Concepts: Overloading + Overriding + Polymorphism&lt;br&gt;
Question: What is the output of the below code?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.markbdsouza.polymorphism;

class Car {
    public int getSpeed() {return 100;}
}
class Audi extends Car {
    // overridden method as it already exists in the Car class
    public int getSpeed() {return 500;}
}
public class Level5 {
    public void drive(Car car) {
        System.out.println("Using a Car and driving at " + car.getSpeed());
    }
    // overloaded version of drive method
    public void drive(Audi audi) {
        System.out.println("Using an Audi and driving at " + audi.getSpeed());
    }
    public static void main(String[] args) {
        // Create 3 objects
        Car car = new Car();
        Audi audi = new Audi();
        Car audiCar = new Audi();
        // Testing overloading and overriding with polymorphism
        Level5 myTestClass = new Level5();
        myTestClass.drive(car);
        myTestClass.drive(audi);
        myTestClass.drive(audiCar);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Answers to the Quiz
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Level 1
&lt;/h3&gt;

&lt;p&gt;This was simple and straight forward - Line 19 and Line 21 have issues. &lt;br&gt;
Since Dog, in its hierarchy chain implements Vertebrae, Eats and Movable, any of them can be used a reference variable and be assigned to an instance of Dog. But that does not mean they can access all Dog methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        Movable a = new Dog(); 
        a.move(); 
        // a.eat(); // Compile Error - Moveable interface has only a move method
        Eats b = new Dog(); 
        // b.move(); // Compile Error -  Eats interface has only the eat method
        b.eat();
        Vertebrae c = new Dog(); 
        c.move(); // Has access to move method because Vertebrae exteds Movable 
        c.eat();  // Has access to eat method because Vertebrae exteds Eats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go back to Question-1&lt;/p&gt;

&lt;h3&gt;
  
  
  Level 2
&lt;/h3&gt;

&lt;p&gt;This was a trick question! If you guessed &lt;code&gt;swims&lt;/code&gt; you're mistaken. You actually get a compiler error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;move() in com.markbdsouza.polymorphism.Fish cannot implement move() in com.markbdsouza.polymorphism.Movable
  attempting to assign weaker access privileges; was public
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In an interface all methods are public and abstract by default. When a class tries to implement the method in the interface, it HAS to be PUBLIC as well. When overridding a method, we cannot make the method more restrictive. So the class implementation of the method has to be public. There are no 2 ways about it. &lt;/p&gt;

&lt;p&gt;Go back to Question-2&lt;/p&gt;

&lt;h3&gt;
  
  
  Level 3
&lt;/h3&gt;

&lt;p&gt;The code does not compile. We get the error&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;move() in com.markbdsouza.polymorphism.Fish cannot override move() in com.markbdsouza.polymorphism.Animal
  overridden method does not throw java.io.EOFException
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can NOT throw checked exceptions(non Runtime exceptions) that are NEW or BROADER than those declared in the original overridden method. In this case the overridden method had a FileNotFoundException and the overriding method additionally has an EOFException. This is not allowed.&lt;br&gt;
The overriding method can also throw narrower or fewer exceptions just not more! Note that the overriding method can however throw any unchecked (Runtime exception) that it wants. &lt;br&gt;
Go back to Question-3&lt;/p&gt;
&lt;h3&gt;
  
  
  Level 4
&lt;/h3&gt;

&lt;p&gt;You might be surprised to see that the output is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Using a Car
Using an Audi
Using a Car
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The choice of which overloaded that should be called is decided at compile time itself. The reference type (Type of the reference variable and not the actual type of the object it is pointing to) decides which overloaded method is invoked. &lt;br&gt;
When we use a reference type of Car, during compilation it is decided which overloaded method is invoked. This is why &lt;code&gt;Using a Car is picked up&lt;/code&gt; &lt;br&gt;
Go back to Question-4&lt;/p&gt;
&lt;h3&gt;
  
  
  Level 5
&lt;/h3&gt;

&lt;p&gt;Similar to Level 4 with a slight twist!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Using a Car and driving at 100
Using an Audi and driving at 500
Using a Car and driving at 500
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't believe me run the code yourself and check ! &lt;br&gt;
Well you probably guessed line 1 and 2 correctly. In Line 3, what happens is even though the actual Object at runtime is an Audi Object and not just a Car object, the choice of which overloaded method that should be called is decided at compile time itself and not runtime. The reference type (Type of the reference variable and not the actual type of the object it is pointing to) decides which overloaded method is invoked. - &lt;em&gt;All similar to question 4&lt;/em&gt;&lt;br&gt;
So now we know that &lt;code&gt;Car audiCar = new Audi();&lt;/code&gt; will invoke the below method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public void drive(Car car) {
        System.out.println("Using a Car and driving at " + car.getSpeed());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We see that car.getSpeed() is called in the method and the compiler will throw no error during compilation because this method does in fact exist in the Car object.&lt;br&gt;
But now during run time, the method that gets executed is the object type (type of the object that is used and not type of the reference variable). For our &lt;code&gt;Car audiCar = new Audi();&lt;/code&gt; the type of the object is Audi. So during runtime the code that gets invoked is the below method&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public int getSpeed() {return 500;}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Merging these 2 concepts together of overloading and overriding we get the 3rd line as &lt;code&gt;Using a Car and driving at 500&lt;/code&gt; !! Hope that all made sense&lt;br&gt;
Go back to Question-5&lt;/p&gt;

&lt;p&gt;You will probably not use this sort of overloading + overriding with polymorphism in real life, so don't kill yourself if you didn't know the answer to the questions&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I hope you learnt something from this article!! If you know any java devs, ask them these questions and see if they get all of them right!!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>polymorphism</category>
      <category>tutorial</category>
      <category>oop</category>
    </item>
    <item>
      <title>Spring Cloud Config Server - Encryption and Decryption</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Tue, 07 Sep 2021 18:01:21 +0000</pubDate>
      <link>https://forem.com/markbdsouza/spring-cloud-config-server-encryption-and-decryption-2ejc</link>
      <guid>https://forem.com/markbdsouza/spring-cloud-config-server-encryption-and-decryption-2ejc</guid>
      <description>&lt;p&gt;While using Spring Cloud Config Server, we also have the feature to encrypt sensitive information that is otherwise stored as plain text in our external git repository. This prevents anyone who has read access to the external repository from accessing confidential information and is highly highly recommended if you are using a Spring Cloud Config Server. &lt;br&gt;
Note: If you haven't set up Spring Cloud Config Server yet check out my other article on &lt;a href="https://dev.to/markbdsouza/spring-cloud-config-server-step-by-step-14fd"&gt;how to set up a spring cloud config server&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are 2 types of encryption provided&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Symmetric - Quicker to setup and easier to use. Uses a unique alphanumeric set of characters to both encrypt and decrypt the properties.&lt;/li&gt;
&lt;li&gt;Asymmetric - Higher security and harder to set up. It requires you to use java command line utility called keytool which creates a key store file (containing private and public keys). Encryption is done with the public key and the private key is used to decrypt the data.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Pre-requisite - JCE
&lt;/h3&gt;

&lt;p&gt;If you use OpenJDK11 you can skip this step as JCE comes along with it. &lt;br&gt;
If you are on Java 8, Go ahead and download JCE which we will need to encrypt data : &lt;a href="https://www.oracle.com/in/java/technologies/javase-jce8-downloads.html" rel="noopener noreferrer"&gt;https://www.oracle.com/in/java/technologies/javase-jce8-downloads.html&lt;/a&gt;&lt;br&gt;
This includes 2 jars, which need to be added to our runtime environment : local_policy.jar and US_export_policy.jar&lt;br&gt;
You can read the README and proceed with install JCE. All you basically need to do is navigate to your JDK installation path and place these 2 jars under lib/security. Once done, make sure you close all java apps and reopen them. If you still see errors while performing the below steps, try and restart your machine once.&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Using Symmetric Encryption
&lt;/h2&gt;

&lt;p&gt;I have set up my config server, so I can do a GET request to : &lt;a href="http://localhost:8888/all-ms/default" rel="noopener noreferrer"&gt;http://localhost:8888/all-ms/default&lt;/a&gt;&lt;br&gt;
where all-ms is an micro service name and default is the spring profile to get the configured values in my external git repository&lt;br&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%2F1ijeqxz7n8hof2ivvqx1.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%2F1ijeqxz7n8hof2ivvqx1.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.1) Enable Asymmetric Encryption
&lt;/h3&gt;

&lt;p&gt;To enable encryption all you need to do is add a property to application.properties of your config server.&lt;/p&gt;

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

encrypt.key=APODNU3093r2rbjzxcn09u213asdhy08WRFH


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

&lt;/div&gt;

&lt;p&gt;Your key can be any long random alphanumeric string.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2) End points for encryption/decryption
&lt;/h3&gt;

&lt;p&gt;Now let us encrypt your data first. Launch your config server spring boot application and send a HTTP POST request to your server with endpoint /encrypt and in the body send the data that needs to be encrypted. &lt;br&gt;
localhost:8888/encrypt&lt;br&gt;
The response will contain the encrypted value in the body.&lt;br&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%2Fvy3bnhq2j8576med1s5c.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%2Fvy3bnhq2j8576med1s5c.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
You can also check the decrpytion by sending a HTTP post request to localhost:8888/decrypt , this time the body should have the encrypted value.&lt;br&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%2F8q9kfad172ya5zrmtsw2.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%2F8q9kfad172ya5zrmtsw2.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
To use this encryption in your application, check the secret data that you have in your remote git repository. This could be a data base password/a token.&lt;br&gt;
e.g. spring.datasource.password=DatabasePassword&lt;br&gt;
I will use the above endpoint to encrypt this.&lt;br&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%2Fqozc6ohjb4q7szw2ev2a.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%2Fqozc6ohjb4q7szw2ev2a.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3) Configure your repository
&lt;/h3&gt;

&lt;p&gt;Now in my external properties file, I will replace &lt;/p&gt;

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

 spring.datasource.password=DatabasePassword


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

&lt;/div&gt;

&lt;p&gt;with&lt;/p&gt;

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

spring.datasource.password={cipher}4ae0e7516ba2688519d46a09ec147a96badd9c9e34ffa5c778c26a9d608ad58d2cbfba7a38c87934692ceff4f2ca4bfc


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

&lt;/div&gt;

&lt;p&gt;Note the prefix of {cipher} which tells your server that decryption needs to be done for this particular property. In my repo, I am using a JWT token. I encrypted the token and set the value in my repo to &lt;/p&gt;

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

token.secret={cipher}a0098f22f7fe1d0ca4dc0e03a95c9a721173b4486e9e51c9180c5afb3ff1a773dcba1fc3f4fcbc7060e7d93a8d312d1e


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  1.4) Test it out
&lt;/h3&gt;

&lt;p&gt;When I test out my config by accessing my properties, it automatically decrypts my token given the encryption key in the config server even though in my external repository I have stored the encrypted value. &lt;br&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%2Fiorssmzkdwighbcc4g28.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%2Fiorssmzkdwighbcc4g28.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  2) Asymmetric Encryption
&lt;/h2&gt;

&lt;p&gt;Firstly we need to generate a keystore file which contains the 2 keys. The public key is used to encrypt information and the private key is used to decrypt information.&lt;/p&gt;
&lt;h3&gt;
  
  
  2.1 Creating the key store file
&lt;/h3&gt;

&lt;p&gt;In your command prompt, type out &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

keytool -genkeypair -alias myApiTutorialKey -keyalg RSA -dname "CN=Mark Dsouza,OU=MyApiDev,O=markbdsouza.com,L=Bangalore,S=KA,C=IN" -keypass a1b2c3d4 -keystore myApiTutorialKey.jks -storepass a1b2c3d4 


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

&lt;/div&gt;

&lt;p&gt;Here a1b2c3d4 is the password and myApiTutorialKey.jks is the file created.&lt;br&gt;
If you can’t find keytool on executing, go to the bin folder of your JDK and you should see it there. &lt;br&gt;
If you are on windows, make sure you run command prompt in admin mode if you face any issues.&lt;br&gt;
Please check online for more details on configuring this&lt;br&gt;
&lt;a href="https://docs.oracle.com/cd/E19683-01/806-4078/6jd6cjru7/index.html" rel="noopener noreferrer"&gt;https://docs.oracle.com/cd/E19683-01/806-4078/6jd6cjru7/index.html&lt;/a&gt;&lt;br&gt;
This will create a myApiTutorialKey.jks with the password a1b2c3d4.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Add the file to your project
&lt;/h3&gt;

&lt;p&gt;I now place this file in my resources folder to easily access this file in my spring boot application.&lt;br&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%2Fqpj4acgznuy5m5enh8b0.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%2Fqpj4acgznuy5m5enh8b0.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Enable Asymmetric Encryption
&lt;/h3&gt;

&lt;p&gt;Now for the configuration in application.properties of your spring cloud config server add the below properties.&lt;/p&gt;

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

encrypt.keystore.location=classpath:key/myApiTutorialKey.jks
encrypt.keystore.password=a1b2c3d4
encrypt.keystore.alias=myApiTutorialKey


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

&lt;/div&gt;

&lt;p&gt;Make sure you use the same password and alias you have given when creating the keystore file. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.4 End points for encryption/decryption
&lt;/h3&gt;

&lt;p&gt;Launch your app and similar to the symmetric way of doing things, you can send a POST request to localhost:8888/encrypt with the body being the value you want to encrypt.&lt;br&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%2Fkdiibhte6v5ymfphdwnx.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%2Fkdiibhte6v5ymfphdwnx.png" alt="image"&gt;&lt;/a&gt;&lt;br&gt;
Similarly we can decrypt using the decrypt endpoint.&lt;br&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%2Fpav99pgagba36y4i7aet.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%2Fpav99pgagba36y4i7aet.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.5 Configure your repository
&lt;/h3&gt;

&lt;p&gt;To encrypt data in our remote git repository, add {cipher} as a prefix for the property so that the server knows that it needs to be decrypted when being fetched.&lt;br&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%2Fup585pptq6cxlmjkqeg7.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%2Fup585pptq6cxlmjkqeg7.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2.6 Test it out
&lt;/h3&gt;

&lt;p&gt;When I test out my config by accessing my properties, it automatically decrypts my property with the key store file.&lt;br&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%2Fbojofr9czjts6ex9shsp.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%2Fbojofr9czjts6ex9shsp.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's about it. It honestly is a very short process to encrpyt your data and I hope this tutorial helped you on your spring cloud journey!&lt;/p&gt;

</description>
      <category>java</category>
      <category>microservices</category>
      <category>springboot</category>
      <category>springcloud</category>
    </item>
    <item>
      <title>Getting started with Apache NiFi</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Mon, 16 Aug 2021 18:19:58 +0000</pubDate>
      <link>https://forem.com/markbdsouza/getting-started-with-apache-nifi-42oh</link>
      <guid>https://forem.com/markbdsouza/getting-started-with-apache-nifi-42oh</guid>
      <description>&lt;p&gt;If you're looking to get a quick understanding about Apache NiFi, how you can get started, some key concepts, tips and tricks, and other resources on the open source tool, you've come to the right place&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Apache NiFi and why should I use it?
&lt;/h3&gt;

&lt;p&gt;"An easy to use, powerful, and reliable system to process and distribute data." - NiFi official website&lt;br&gt;
NiFi is a great open source tool. With NiFi you can build a data flow from anywhere to anywhere - local file system, cloud, HDFS, nosql, rdbms, kafka. Litereally Anywhere to Anywhere. &lt;br&gt;
If you have a fixed flow of steps with no computation in between or complex business logic that you need to do - NiFi makes a lot of sense.&lt;br&gt;
A simple use case: You want to transport your data at the end of each day from a DB to say HDFS - you can easily do this with NiFi. This is a fixed set of steps that need to be done.&lt;/p&gt;
&lt;h4&gt;
  
  
  NiFi is EASY to use!
&lt;/h4&gt;

&lt;p&gt;You do not need to be a technical person to use NiFi. It has a very robust interactive web browser UI and all you need to do is drag and drop in processors (actions to be done using data) and link them to each other. All you need to know is the configuration of that processor.&lt;br&gt;
For instance, if you are connecting to the Database, you need to know the details of how you can connect to your Database. &lt;br&gt;
For certain use cases you might need to know a little bit of the NiFi Expression Language. After building a few flows this becomes pretty easy to understand. &lt;br&gt;
Docs link : &lt;a href="https://nifi.apache.org/docs/nifi-docs/html/expression-language-guide.html" rel="noopener noreferrer"&gt;https://nifi.apache.org/docs/nifi-docs/html/expression-language-guide.html&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Getting NiFi running on your machine
&lt;/h1&gt;
&lt;h2&gt;
  
  
  Where do I download NiFi?
&lt;/h2&gt;

&lt;p&gt;The team releases updates every few months. So get the latest version here. &lt;br&gt;
Make sure to download the binary : &lt;a href="https://nifi.apache.org/download.html" rel="noopener noreferrer"&gt;https://nifi.apache.org/download.html&lt;/a&gt;&lt;br&gt;
There is even a docker image if you have docker installed on your machine &lt;br&gt;
&lt;a href="https://hub.docker.com/r/apache/nifi/" rel="noopener noreferrer"&gt;https://hub.docker.com/r/apache/nifi/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Launching NiFi
&lt;/h2&gt;

&lt;p&gt;For windows users navigate to bin and run the run-nifi.bat file. You need to have java installed on your machine and added to the PATH variable. &lt;br&gt;
For linux or mac run the command - ```bin/nifi.sh&lt;br&gt;
&lt;br&gt;
 run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;This will launch your NiFi server on https://localhost:8443/nifi/
![Login Screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f4vr2iyq9c713rqm7gj3.PNG)To get your credentials, go to logs/nifi-app.txt and search for your username and password.
![Login credentials in the log file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3080ch387gtqeaa0i58m.PNG)After a successful log in, you will see your home screen where you can start building
![Nifi Home Screen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z0njbx7w88xqbfipohey.PNG)For any issues : https://nifi.apache.org/docs/nifi-docs/html/getting-started.html

# Key Features of NiFi
## Flow Files
The data itself is referred to as a Flow File. It has 2 key parts. The content (raw data of the file) and Attributes which would contain some metadata about the flow file.
For example when you send a HTTP Request, the body of the HTTP request would be the Flow File Content and the headers would be the attributes.
The flow data does not get copied each step. It is temporarily stored on the NiFi server and an auto clean up happens once the flow file is finished processing. The flow file works sort of like a pointer as the file flows through your entire flow. 
## Processors
A processor is the task that you want to execute on the data/flow file.
Do you want to Read from HDFS Or read a file from a location on your machine? Do a HTTP GET Request? Generate a File? Insert into a NoSQL or RDBMS Database? Each of this is can be done with a processor. Overall there are 288 processors as of today that you can use. ![All Processors](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f6ai94p0qxx3hkss0j5g.PNG)And if you don't find the EXACT processor you need? You can write your own with custom code as well. The NiFi teams keeps adding new processors as well.
Once you drag in a processor, it will need to be configured. For example If you are generating a file - you can provide the data in the file. ![Configure Generate Flow File](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3juunj1x29r1ds8kryw.PNG) Not all configuration is mandatory. 
If you miss a mandatory configuration you will see a warning across the processor with descriptions of what is missing
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcnsb4097gvrsb5x6hxe.png)
Note: Any processor can use any flow file which is what makes NiFi so powerful. 
## Linking processors with connectors
We can connect processors to each other using a connector. Depending on the processor, you may have multiple outcomes of the processor doing the intended action.
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ism1w8539c1taomrub8y.png) In the example, I have a consume Kafka processor and there can be 2 outcomes - parse.failure or success. You can easily create different flow File paths for either outcome. Maybe you want to log the failure and not proceed further and if it is a success you might have 2 3 additional steps. 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d3w3tspn6xzpqrzub4m4.png) If a processor is the end of a flow, we need to explicitly tell NiFi that it is the end. Otherwise NiFi expects us to keep going and will throw a warning message. 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6hqd3nn13y0cfh5rn8kh.png)Moment you link 2 processors, there is a Queue created. If your 2nd processor is paused or has an error in the configuration, the flow Data will enter the queue in this connector. 
TIP: If you are linking 2 different relationships between processorA and processorB draw 2 different lines creating 2 different connectors. This specially helps in debugging.

## Controller Services
Controller Services in NiFi are centrally stored. If you have 10 different calls for various CRUD Operations depending on some business logic, you do not need to provide 10 different connections to the DB. All you need to do is create the Service once and then reference the service for each of your processors
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/76zprv2siehrqxkixmp4.png) You will also need to provide a jar file for a driver (if required) so NiFi can make the appropriate connection 

## Other concepts
**Process Groups** - You can group a part of a flow helping you segregate different parts of your flow logically
**Input Port/Output Port** - An input to your Process Group is in the form of an input port (not the server port). This is how data enters the Process group. Similarly, in the group, there can be multiple path terminating in multiple output ports. One group can have multiple input ports.
**Templates** - You can create a template containing the entire or part of your flow. This can then be shared with other developers. You can save/import/delete templates.
**Funnel** - You can combine data from different sources with funnel
**Label** - For better visualization. Has no impact on the data.

## Conditional Statements in Nifi
### If Else Logic based on attributes/content
The most useful processor to implement dynamic behavior is the RouteOnAttribute/RouteOnContent processor. This basically helps you implement IF ELSE statements while the data flows. Say NiFi is reading a HTTP request, you can do some routing based on the type of request (a different route for POST and DELETE to the same HTTP endpoint). 

### For Loops in Nifi
NiFi isn't great for working with loops. But there are ways to do it. You can split one file into many files based on some condition. Say you have a list of fileNames as an attribute. FileA,FileB,FileC. Now you want to create 3 files and place them in a target folder. You can split your first FlowFile and create 3 flow files(or X Flow files) with each flow file with an attribute of the individual file name. 
But things that might be just 2 3 lines in JS, Java or any other language, might take a little thinking to implement using NiFi Processors. Example: I had an array of strings. and wanted to remove 1 string based on some business logic - this was extremely hard to do and took way too many steps to implement which is otherwise 1 array filter function in any programming language. (You can opt to go for custom coding in NiFi as well which is ideal for these more complicated scenarios) 
Note: you can remerge your flow files after splitting them up as well.

## Scheduling 
There are 2 ways of scheduling - Time Driven or CRON driven 
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zgfeqhewdhj19elzs7uv.png)

## Data Provenance
Data provenance is the documentation of where a piece of data comes from and the processes and methodology by which it was produced. NiFi lets you easily track data at the application level
![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/34eqogg9y8lxf7e2zzwp.png)![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7znqn8tl4qq8dzv1u1ex.png) 
## Tips on debugging
Let’s say you have a simple flow but you need to see the data that is coming to create your flow easily. You can create your connections and stop the processor you haven’t configured yet![Queue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qwspvm353rvz1viybll.PNG)I have a simple Generate log file connected to a Log Attribute
As you can see, the connector has a Queue count displayed.
![Queue Options](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8c0d8s0puvjstd05kho.png)Right click to view the Queue
![List Queue](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3s3zmt8a1zc1x0obdfiy.PNG)Now you can see all flow files that are currently in this queue. You can view the attributes and metadata of the file and even see the raw content.    
![Queue View](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i8qyfc8l50yefqrd1piz.PNG)
![Queue Content](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1molym42y6t3bwvjuajk.PNG)This helps you code and see the data as it progresses through the entire flow. 

## When not to use NiFi
NiFi isn’t great for computation. Basic transformation? That’s fine. But if you want to do something like take a SUM of a column or Aggregations - NiFi isn’t meant for that.

## Other Resources
### Where can I get help?
I have to point you to the official docs first
https://nifi.apache.org/docs.html
https://nifi.apache.org/docs/nifi-docs/html/getting-started.html
https://nifi.apache.org/developer-guide.html
https://cwiki.apache.org/confluence/display/NIFI/FAQs
For a good quick read
https://www.guru99.com/apache-nifi-tutorial.html
Though these docs are pretty great, there aren't any real examples of how to use a processor. The 2 great forums you'll find your answers are Cloudera and Stack overflow. I found a lot of useful use cases in the Cloudera forums. So don't overlook those results in your google searches

### Are there any good videos on NiFi?
When it comes to tools, I find it a lot easier to grasp things by watching unlike code which can be read since there is UI interaction and not static code. 
A set of well curated videos touching many essential features of NiFi with plenty of hands on: https://www.youtube.com/watch?v=VVnFt54jUQ8&amp;amp;list=PL55symSEWBbMBSnNW_Aboh2TpYkNIFMgb
A long (bits can be skipped) overview with hands on: 
https://www.youtube.com/watch?v=fblkgr1PJ0o

If you have any other suggestions/content for NiFi beginners, please share them in the comments section.
Happy Learning !!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>opensource</category>
      <category>nifi</category>
      <category>apache</category>
      <category>datascience</category>
    </item>
    <item>
      <title>Write better Java Code</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Sat, 22 May 2021 13:56:17 +0000</pubDate>
      <link>https://forem.com/markbdsouza/write-better-java-code-32oi</link>
      <guid>https://forem.com/markbdsouza/write-better-java-code-32oi</guid>
      <description>&lt;p&gt;&lt;em&gt;Clean Code is under rated.&lt;/em&gt; If you've ever got frustrated with the way some code was written or spent way too much trying to understand what some function is doing, it probably means that code could be written better. &lt;/p&gt;

&lt;p&gt;You can surely build great things without following the principles of clean code. But it becomes a LOT LOT easier for you and your team to maintain the same code if it is easily understandable and written well. This is a continuous process that should be taken into account with each line of code you write and is not a retrospective action you work on at the end of the week/sprint.&lt;/p&gt;

&lt;p&gt;Java projects especially can get really big and complex, and clean code helps your team build, enhance and fix bugs faster and more efficiently. And if you're a beginner, this can be a lot to take in but it surely helps to get started off on the right foot. &lt;/p&gt;

&lt;p&gt;In the below sections, I'll go over points/best practices to keep in mind while writing java code. &lt;/p&gt;

&lt;h3&gt;
  
  
  All about naming
&lt;/h3&gt;

&lt;p&gt;Thumb rule - always be as specific as possible with all names.&lt;/p&gt;

&lt;h4&gt;
  
  
  Naming Classes
&lt;/h4&gt;

&lt;p&gt;Class Names should ideally be nouns or can be abstract and are written in PascalCase. Example: AudioTransmitter, SalaryCalculator. &lt;br&gt;
As much as possible try and make it specific to what your use case is. If you have a FileReader class to read xml files, a better way of naming it would be XmlFileReader. That way if there is an enhancement later to have a JSON or CSV FileReader, you can have separate classes for it instead of having all the logic in one class.&lt;/p&gt;

&lt;h5&gt;
  
  
  Naming Variables
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Written in camelCase, variable names should be descriptive yet concise. &lt;/li&gt;
&lt;li&gt;Avoid naming variables with alphabets such as a,b,x,y,z unless it is a temp variable like an index. 
*When using booleans start it with 'is'. Example: isValid instead of valid.&lt;/li&gt;
&lt;li&gt;For Constants use ALL_CAPS_WITH_UNDERSCORES. Example: MAX_CUSTOMER_COUNT
Basically, if we see the variable in a random piece of code, we should be able to understand what type of data it holds.
Example: customerAccountDetails&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Naming Methods
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;The name of the method should describe 'what' is done by the method (it doesn't matter how). eg: generateSalaryReport(). The method tells us it is creating the salary report. We don't care how it is being done internally. &lt;/li&gt;
&lt;li&gt;A method should ideally have only 1 purpose. If the method does more than 1 thing, you should ideally split it up such that each method does exactly what it says.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  All about Methods
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Avoid writing huge methods. Each method should be specific and do just one thing. Keep in mind if multiple methods have the same code in them, you are repeating yourself. Instead create a small private method in the class and call the method wherever the duplication is observed.&lt;/li&gt;
&lt;li&gt;When returning an object, avoid returning null. When we do so we are assuming that all clients of the method expect null and handle it. If they are aware they need to add an extra try catch every single time your method is called. This is just repetitive code. Instead return an empty Collection or throw an error if appropriate. &lt;/li&gt;
&lt;li&gt;Avoid having too many arguments in a method. Too many arguments also increase complexity and might show that you need to split your method into multiple parts each doing a small part of the logic. Or are a few of those arguments very cohesive and do they actually need a class of their own? If yes, it might mean more code and an extra class but it's a lot easier and more scale-able. &lt;/li&gt;
&lt;li&gt;Avoid flag arguments which are boolean in nature. This points to the fact that you have too much logic for the function again. Split the true and false part into two separate methods and call them accordingly.&lt;/li&gt;
&lt;li&gt;Fail Fast &amp;amp; Return Early. Check for invalid arguments right at the start and throw an error instead of executing code that will ultimately fail for the same reason. This will save on execution time and make it easier to debug. Return early is the way of writing methods so that the expected positive result is returned at the end of the function and the rest of the code terminates the execution (by returning or throwing an exception) when conditions are not met.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Constructors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;If you have a Class that has many variables that need to be assigned and multiple combinations of these variables therefore needing many constructors, a good way to organize your code is to use the &lt;a href="https://www.geeksforgeeks.org/builder-design-pattern/"&gt;Builder Design Pattern&lt;/a&gt;. This is a Creational design pattern and you dynamically assign variables when creating the object.&lt;/li&gt;
&lt;li&gt;Another way to avoid duplication of code in constructors is using &lt;a href="https://www.geeksforgeeks.org/constructor-chaining-java-examples/"&gt;Constructor chaining&lt;/a&gt;, where you call one constructor from inside the other.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  All about classes
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Try and follow the Single Responsibility Principle (from SOLID principles) - the class should have only one reason to change. This results in smaller well defined classes. &lt;/li&gt;
&lt;li&gt;It should be cohesive - where fields and methods are highly related to each other. Higher the cohesion, the better. This will also help you avoid classes with way too many variables.&lt;/li&gt;
&lt;li&gt;Follow Loose coupling - a change in one class requires minimum/0 changes in another class. This reduces the inter dependency between classes. Most frameworks follow loose coupling for this reason.&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://www.freecodecamp.org/news/a-quick-intro-to-dependency-injection-what-it-is-and-when-to-use-it-7578c84fa88f/"&gt;Dependency Injection&lt;/a&gt; if possible.&lt;/li&gt;
&lt;li&gt;Uses interfaces as much as possible. If you ever want to change the implementation, it becomes a very quick and easy change. Allows you to be very flexible in the future. Example use &lt;code&gt;List&amp;lt;String&amp;gt; customerNames = ArrayList&amp;lt;String&amp;gt;();&lt;/code&gt; instead of &lt;code&gt;ArrayList&amp;lt;String&amp;gt; customerNames = ArrayList&amp;lt;String&amp;gt;();&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Encapsulation - keep variables private and any methods that need not be public, private. Even for getters and setters, only create them if it needs to be accessed from outside the class. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exception Handling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Avoid catching Throwable or Exception Classes. As the programmer, you need to know when Errors(Example: OutOfMemory) happen or when Runtime Exceptions that you would want to know when it happens. &lt;/li&gt;
&lt;li&gt;Do not catch and handle Null pointer exceptions in the catch block, instead write code to prevent the null from happening itself(if possible) and if not just do a &lt;code&gt;if(obj != null)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Exceptions when caught should be specific. Only if you expect an error to happen, you should try and catch it. Also Java 7 allows you to catch multiple exceptions in one block with &lt;code&gt;catch( IOException | SQLException e)&lt;/code&gt; and handle all exceptions the same way.&lt;/li&gt;
&lt;li&gt;When catching an exception, make sure you log the details(with a logging framework) of the exception and surely do not keep it empty. &lt;/li&gt;
&lt;li&gt;When catching an exception make sure you mention why the exception happened. Example if it is an Illegal Argument Exception, you can mention what type of value the argument had for the exception to happen. This helps with debugging. &lt;/li&gt;
&lt;li&gt;Use try with resources(if using java 7+) wherever possible to avoid additional code. &lt;/li&gt;
&lt;li&gt;Do not catch and handle exceptions you do not expect to occur. You should add catch blocks only for those exceptions that you are aware could happen for a reason. Anything else is extra avoidable code.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Comments
&lt;/h3&gt;

&lt;p&gt;Base rule: Never comment code out. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A comment should only increase our understanding of code. &lt;/li&gt;
&lt;li&gt;Avoid stating obvious points in comments that you can easily understand by reading the code. &lt;/li&gt;
&lt;li&gt;Keep note that that comments are rarely updated when code is updated. This can cause issues. As a team, always make sure any updates to code, is also reflected on comments or remove the comment altogether in such cases.&lt;/li&gt;
&lt;li&gt;Writing comments in the form of JavaDocs for public methods that will be used by clients of that class is extremely valuable.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Styling and Formatting
&lt;/h3&gt;

&lt;p&gt;Most Java IDEs have an inbuilt code formatter which helps you do this with a shortcut. &lt;br&gt;
The &lt;a href="https://google.github.io/styleguide/javaguide.html"&gt;Google Java Style Guide&lt;/a&gt; and &lt;a href="https://github.com/twitter-archive/commons/blob/master/src/java/com/twitter/common/styleguide.md"&gt;Java Style Guide by Twitter&lt;/a&gt;, both have some best practices when it comes to writing java code.&lt;br&gt;
Make sure you use line breaks and brackets wisely, making the code readable. Less lines of code doesn't make it more readable. &lt;/p&gt;

&lt;h3&gt;
  
  
  How to check code quality?
&lt;/h3&gt;

&lt;p&gt;There are plugins that help you check if code is being reused, written as well as they can be. &lt;a href="https://www.sonarlint.org/"&gt;SonarLint&lt;/a&gt; their very tag line is - Fix issues before they exist. It is available on all popular Java IDEs and you can do a full project scan to see how the code can be improved. &lt;br&gt;
&lt;a href="https://www.sonarqube.org/"&gt;SonarQube&lt;/a&gt; is an open source tool that can be added to your CI/CD pipeline and is extremely popular to check the entire project's code quality. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;At the end of the day, as a team, decide on what standards you would like to adhere to and stick to it.&lt;/strong&gt; If each member follows his own best practices, it helps no one. It often helps to keep a document for each project with the coding standards followed by all and is shared with any new members joining the team.&lt;br&gt;
Make sure when you are reviewing code with Pull Requests, your teammates are adhering to the rules agreed upon (and they make sure you do as well) so your overall code is consistent throughout the application.&lt;/p&gt;

&lt;p&gt;If you have any additional pointers to add that you feel have helped you and your team out, leave them in the comments down below. &lt;/p&gt;

</description>
      <category>java</category>
      <category>design</category>
      <category>beginners</category>
    </item>
    <item>
      <title>JS: Sort an Array of Objects on multiple columns/keys</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Thu, 22 Apr 2021 06:03:50 +0000</pubDate>
      <link>https://forem.com/markbdsouza/js-sort-an-array-of-objects-on-multiple-columns-keys-2bj1</link>
      <guid>https://forem.com/markbdsouza/js-sort-an-array-of-objects-on-multiple-columns-keys-2bj1</guid>
      <description>&lt;p&gt;Let's see how you can completely configure the sorting of an Array of objects. Let's say we have the below data set for our entire example.&lt;/p&gt;

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

let objs = [
  { name: 'Mark',
    age: 30,
    RollNo: 'R01'
  },
  { name: 'Anne',
    age: 20,
    RollNo: 'R02'
  },
  { name: 'James',
    age: 40,
    RollNo: 'R03'
  },
  { name: 'Jerry',
    age: 30,
    RollNo: 'R04'
  },
  { name: 'Lucy',
    age: 30,
    RollNo: 'R05'
  },
  { name: 'Mark',
    age: 30,
    RollNo: 'R06'
  },
]


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

&lt;/div&gt;

&lt;p&gt;Looking at the raw data we have with a &lt;code&gt;console.table(objs)&lt;/code&gt;&lt;br&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%2Fkdphmk8u69l8ozb4va2i.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%2Fkdphmk8u69l8ozb4va2i.PNG" alt="Table"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Single Column Sort
&lt;/h2&gt;

&lt;p&gt;Now say we want to sort this data across one column. The best way to do this is the sort() method. Check out the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;br&gt;
An example from there down below on a simple array of Strings&lt;/p&gt;

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

const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);


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

&lt;/div&gt;

&lt;p&gt;The output is &lt;code&gt;["Dec", "Feb", "Jan", "March"]&lt;/code&gt; &lt;br&gt;
This automatically sorts the &lt;strong&gt;original&lt;/strong&gt; array in alphabetical order and returns the original array as well on calling sort(). &lt;/p&gt;

&lt;h4&gt;
  
  
  Sorting on String
&lt;/h4&gt;

&lt;p&gt;Using the above example, let us try and sort our object&lt;/p&gt;

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

objs.sort(function(a, b) {
    return a.name.localeCompare(b.name)
});


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

&lt;/div&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%2Fv12q6yl1427r57sausim.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%2Fv12q6yl1427r57sausim.PNG" alt="Single Sort on Name"&gt;&lt;/a&gt;&lt;br&gt;
This is similar to a SQL Statement &lt;/p&gt;

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

SELECT * FROM OBJS ORDER BY NAME; 


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Sorting on number (the ES6 way)
&lt;/h4&gt;

&lt;p&gt;With ES6, we can even write it as an inline function. Let's try and sort based on the number field age.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

objs.sort((a, b) =&amp;gt; a.age - b.age);


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

&lt;/div&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%2Fjspephc1d6cmqlb3zmrd.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%2Fjspephc1d6cmqlb3zmrd.PNG" alt="Single Sort on Age"&gt;&lt;/a&gt;&lt;br&gt;
This is similar to a SQL Statement &lt;/p&gt;

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

SELECT * FROM OBJS ORDER BY AGE; 


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Multi Column Sort
&lt;/h2&gt;

&lt;p&gt;We can combine sorts using the || operator in the order of the sorting we need.&lt;/p&gt;
&lt;h4&gt;
  
  
  Sort by Age, and then Name
&lt;/h4&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

objs.sort((a,b)=&amp;gt; (a.age - b.age || a.name.localeCompare(b.name)  ));


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

&lt;/div&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%2Fu27vu0k022o8rx8ige9d.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%2Fu27vu0k022o8rx8ige9d.PNG" alt="MultiSort on age and name"&gt;&lt;/a&gt;&lt;br&gt;
This is similar to a SQL Statement &lt;/p&gt;

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

SELECT * FROM OBJS ORDER BY AGE, NAME; 


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Sort by Name, and then Age
&lt;/h4&gt;

&lt;p&gt;We can modify the order of how the sort is done. That is if we want to sort by name first and then age&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

objs.sort((a,b)=&amp;gt; (a.name.localeCompare(b.name) || a.age - b.age));


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

&lt;/div&gt;

&lt;p&gt;This is similar to a SQL Statement &lt;/p&gt;

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

SELECT * FROM OBJS ORDER BY NAME, AGE; 


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Changing to Descending order
&lt;/h4&gt;

&lt;p&gt;If we wanted Age and Name to be descending order we just need to swap the above command with &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

objs.sort((a,b)=&amp;gt; (b.age - a.age || b.name.localeCompare(a.name)  ));


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

&lt;/div&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%2F40fl85uthgaazevdl61l.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%2F40fl85uthgaazevdl61l.PNG" alt="MultiSort on age and name Descending"&gt;&lt;/a&gt;&lt;br&gt;
This is similar to a SQL Statement &lt;/p&gt;

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

SELECT * FROM OBJS ORDER BY NAME DESC, AGE DESC; 


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

&lt;/div&gt;
&lt;h4&gt;
  
  
  Extend to sort on all 3 columns
&lt;/h4&gt;

&lt;p&gt;Using the above logic, you can append how many ever sort columns you might need in the order you need them. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

objs.sort((a,b)=&amp;gt; (a.name.localeCompare(b.name) || a.age - b.age || a.RollNo - b.RollNo));


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

&lt;/div&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%2Foplqkq3wyfq7nk6hvbbj.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%2Foplqkq3wyfq7nk6hvbbj.PNG" alt="MultiSort on 3 columns"&gt;&lt;/a&gt; &lt;br&gt;
This is similar to a SQL Statement &lt;/p&gt;


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

&lt;p&gt;SELECT * FROM OBJS ORDER BY NAME , AGE , ROLLNO; &lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Use Case&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Say you have an API that returns an Array of Objects in a random manner. Maybe you have a table in your UI and you want to sort this data that comes in such that it makes the most sense for your user(sort on some category or maybe price). All you need to do is tweak the above logic and tada! &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>algorithms</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Do certifications help?</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Tue, 20 Apr 2021 11:07:04 +0000</pubDate>
      <link>https://forem.com/markbdsouza/do-certifications-help-khj</link>
      <guid>https://forem.com/markbdsouza/do-certifications-help-khj</guid>
      <description>&lt;p&gt;I've seen a lot of people in the industry really hate the concept of certifications and keep saying that they are a waste of money (and a money making strategy for the companies offering it). And that all you need to know are the concepts and the certification as such has NO value at all.&lt;/p&gt;

&lt;p&gt;Well, I think they are &lt;em&gt;partially right&lt;/em&gt;. At the end of the day it is only the knowledge that matters. But certifications (more importantly the process) do give you a slight edge and I'll go through how through some common questions about them. &lt;/p&gt;

&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Can a certification get me a job?&lt;/li&gt;
&lt;li&gt;Can a certification get me opportunities? &lt;/li&gt;
&lt;li&gt;Does the certification give me an advantage in interviews? &lt;/li&gt;
&lt;li&gt;How does it help me apart from a line on my resume?? &lt;/li&gt;
&lt;li&gt;I don't have hands on work experience with a tool/tech. Does doing a certification in it help?&lt;/li&gt;
&lt;li&gt;How do I prepare?&lt;/li&gt;
&lt;li&gt;Should I buy mock exams?&lt;/li&gt;
&lt;li&gt;Do I need to go somewhere to take the test?&lt;/li&gt;
&lt;li&gt;How can I afford certifications?&lt;/li&gt;
&lt;li&gt;How long are certifications valid?&lt;/li&gt;
&lt;li&gt;I have a certification but do not have the opportunity to work on it. What do I do? &lt;/li&gt;
&lt;li&gt;
Conclusion
&lt;a&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Can a certification get me a job?
&lt;/h3&gt;

&lt;p&gt;Absolutely NOT! No one is going to see a certification on your resume and blindly offer you a job offer for a tool/tech. The only thing it tells a recruiter is that this person 'should' know a bit about the topic in question. But at the end of the day you need to be able to answer the questions being thrown at you.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Can a certification get me opportunities?
&lt;/h3&gt;

&lt;p&gt;Having a certification could open a few doors for you. Having a cloud certification to compliment your developer exp could help you find certain opportunities that you probably wouldn't get offered without it. A lot of organizations are looking for people who know a bit of everything in today's world of agile teams. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Does the certification give me an advantage in interviews?
&lt;/h3&gt;

&lt;p&gt;Maybe. Maybe not. End of the day it really depends on the recruiter. No one in their right mind would think its a bad thing to have a certification for yourself in a craft you want to work in. &lt;br&gt;
I've been in the industry over 8 years now and would pick a candidate who shows the most promise and eagerness in getting the work done. BUT if I had 2 very very similar candidates and 1 has done a bunch of additional learning and certification over his work ex and has shown the interest to constantly learn and improve, I'd be inclined to go with them over someone who just does what needs to be done.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it help me apart from a line on my resume?
&lt;/h3&gt;

&lt;p&gt;There are 2 instances I can think of where one would take a certification&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A new tech you want to explore - 
Having certifications on things you dont really know yet can really really help you gain critical knowledge and help build a solid foundation. This is especially useful to ramp yourself up for a new role or open opportunities in projects where they need a mix of skills. A great example is the cloud. If your current project doesn't use cloud for infra or if your client doesnt want to use it, ull never learn anything about the cloud. Cloud providers have a 1 year free tier which helps you get good hands on in tech. &lt;/li&gt;
&lt;li&gt;A tech you've been working on/have worked on a bit - 
You've been working on it for a little time and want to get better. Google and Stack over flow being your best friends (along with Copy Paste) . Yet there are some concepts you don't really get. Preparing for a certification really strengthens -

&lt;ul&gt;
&lt;li&gt;Things you already know well cos you use it every day&lt;/li&gt;
&lt;li&gt;Parts of the tech you don't use regularly&lt;/li&gt;
&lt;li&gt;Get a deeper understanding of why things work the way they do
It can only make you a better programmer.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;A tech you're great at -
If you're really good at what you do and have great hands on experience, then there probably isn't a lot of gain in getting a certification unless you feel there are aspects to the tech/product that you might not be using regularly. At the end of the day its about the knowledge you have and nothing more. Surely consider doing it if your company reimburses you for the certification.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  I don't have hands on work experience with a tool/tech. Does doing a certification in it help?
&lt;/h3&gt;

&lt;p&gt;It surely can. Why? because in the process of that certification you do get hands-on experience as you explore the various concepts you are tested about. This isn't as good as client work experience but it is better than none. It will surely give you a strong foundation and prove that given the opportunity it isn't going to be something new to you. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I prepare?
&lt;/h3&gt;

&lt;p&gt;Research. Most certifications have dedicated study material to get through their certification(sometimes free). There are also technical books that give you a strong foundation and more. The only thing is you might not get a clear idea of the level of difficulty and type of questions being asked in the exam. &lt;br&gt;
Make a plan for yourself. Take your time in your preparation. It's fine to take a few weeks or a months to prep for a certification. The only deadline is the one you keep for yourself. A good way to make sure you do not slack off is booking your exam slot when you start your prep forcing yourself to stick to your timelines. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I buy mock exams?
&lt;/h3&gt;

&lt;p&gt;There are a bunch of websites and even specific Udemy courses aimed at helping you clear popular certification exams. There are specific courses which give you 5-6 mock exam question sets which are usually harder than the actual exam. So they really do prepare you to ace your exam for the most part. These courses have proper explanations as to why the answer is as such. Do not mug up but rather understand why the specific answer is true. This will help you when the questions are tricky and more importantly help you in real life. &lt;br&gt;
If you do not want to spend money on the exam, make sure you find a resource to take 1 free mock exam somewhere and if you clear it well above the cut off you're probably good to go. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to go somewhere to take the test?
&lt;/h3&gt;

&lt;p&gt;Given the pandemic around the world, almost all tests are proctored online exams. Make sure you have a laptop with a webcam with a good internet connection and a room for yourself while you take the test. Each exam provider has a bunch of checks to make sure you don't cheat or get help during the exam.&lt;br&gt;
Some providers allow you to reschedule as well, so make sure you read the terms and conditions well before you fix your date. &lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How can I afford certifications?
&lt;/h3&gt;

&lt;p&gt;Certifications are expensive. Period. The best way to do one is to see if your current organization has policies in place to either fully or partially fund your certification. If they do, you might only need to convince your reporting manager or boss why you need to it and how it would help you deliver. A little red tape, and you could get a really expensive certification for 0$. A PMP certification costs around 555 USD which is pretty expensive. &lt;br&gt;
If they don't, analyze how much you are willing to spend and hoyouw relevant the course is to your current and future ambitions. Example: If you're someone looking to get into cloud, AWS, GCP or Azure certifications are great to get started. Or if you want to move into management maybe a CSM or PMP certification. Just preparing for the certification will also give you a lot of hands on knowledge that you can use.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How long are certifications valid?
&lt;/h3&gt;

&lt;p&gt;It depends on the provider. Due to constant changes, product companies keep updating their exams and probably keep it between 2-5 years. Post this you will need to pay (hopefully a reduced rate) and appear for the exam again this time with the latest features. Keep this in mind when you choose your certification.&lt;/p&gt;

&lt;p&gt;&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  I have a certification but do not have the opportunity to work on it. What do I do?
&lt;/h3&gt;

&lt;p&gt;Implement something related to your current assignment if its posible. If not build something for yourself and share a prototype with your reporting manager to showcase your new skills. Again, just having the certification means nothing if you aren't able to implement something. Talk to your manager about your ambitions and what you would like to work on. Reach out to others in your organization working on the tool/tech and find if there are openings on their teams or how maybe you can partially support them.&lt;br&gt;
If none of these work out, maybe even think of looking to jump to a different organization looking for enthusiastic people in the tech.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion - &lt;a&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;In the end its the knowledge that comes along with the preparation and the hands on you get with it that is more critical than the certification itself. Another line on your resume doesn't harm you and could give you some opportunities which you might not have got otherwise.&lt;br&gt;
Practice. Practice. Practice. Don't stop practicing after clearing the exam. The more you do the better you become.&lt;br&gt;
Keep in note the cost and make a plan for yourself and stick to it. Give yourself ample time as some certifications can take months to properly prepare.&lt;/p&gt;

</description>
      <category>certification</category>
      <category>beginners</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Deploying a static website on AWS S3</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Tue, 13 Apr 2021 14:53:05 +0000</pubDate>
      <link>https://forem.com/markbdsouza/deploying-a-static-website-on-aws-s3-5am8</link>
      <guid>https://forem.com/markbdsouza/deploying-a-static-website-on-aws-s3-5am8</guid>
      <description>&lt;p&gt;In this quick tutorial, I am going to show you how you can quickly deploy a static website onto AWS S3. This is similar to the functionality that Github Pages provides where it allows you to host static websites.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pre-requisite:
&lt;/h4&gt;

&lt;p&gt;You need to sign up for AWS : &lt;a href="https://aws.amazon.com/" rel="noopener noreferrer"&gt;https://aws.amazon.com/&lt;/a&gt; and create an account. You get a bunch of stuff for free for the first year so if you have a new account, you can host your website for free for 1 year. &lt;br&gt;
Post which you will be charged a small fee. So make sure to delete your object and bucket once you are done with it. &lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1) Create a new Bucket
&lt;/h3&gt;

&lt;p&gt;Search for the S3 service in the AWS Search bar and click on 'Create bucket' &lt;br&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%2Fzd9o5yus29r9e82s96ze.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%2Fzd9o5yus29r9e82s96ze.PNG" alt="S3 Home Page"&gt;&lt;/a&gt; Enter the bucket name and scroll down and hit 'Create Bucket' button. &lt;br&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%2Fg0vj2l71579jv3j9o3hw.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%2Fg0vj2l71579jv3j9o3hw.PNG" alt="Enter Bucket name"&gt;&lt;/a&gt; Let all the default values be set. We will come back later and change some of these. &lt;/p&gt;

&lt;p&gt;You should now see this new bucket on your s3 Buckets home page. &lt;br&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%2Fp27gy9r05gnpo1ds5rlv.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%2Fp27gy9r05gnpo1ds5rlv.PNG" alt="Bucket created"&gt;&lt;/a&gt; Click on your bucket name to open the bucket.&lt;br&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%2Fi9bf6ftnsg84ywowuza8.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%2Fi9bf6ftnsg84ywowuza8.PNG" alt="Empty Bucket"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2) Upload your HTML Files
&lt;/h3&gt;

&lt;p&gt;Next up is to upload your Objects(files) into your bucket.&lt;br&gt;
I have 3 files I want to upload. It is a simple HTML, CSS, JS Static web site. &lt;br&gt;
 You can either click Upload button or drag and drop your files as well. &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%2Fz8jihhx5yge4po3jv361.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%2Fz8jihhx5yge4po3jv361.PNG" alt="Files selected for upload"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and click Upload now. This will upload your files to your bucket.&lt;br&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%2Fqoutc87unl3cmesm8ysd.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%2Fqoutc87unl3cmesm8ysd.PNG" alt="Uploaded files into bucket"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3) Make your Bucket public
&lt;/h3&gt;

&lt;p&gt;Go back to your bucket view and click on the Permissions tab. By default AWS makes sure your buckets are all private and not accessible from the outside to protect your data. Since we want this website to be accessible, we need to make the bucket 'public'.&lt;br&gt;
Under permissions&amp;gt; 'Block public access(bucket settings)' click on Edit.&lt;br&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%2F7rfh0fc6wvaz3n0kf6t2.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%2F7rfh0fc6wvaz3n0kf6t2.PNG" alt="Permissions"&gt;&lt;/a&gt; Un-check 'Block all public access' and click on 'Save changes'. &lt;br&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%2Fymbn1lda7esl1t9l6ii2.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%2Fymbn1lda7esl1t9l6ii2.PNG" alt="Remove block all public access"&gt;&lt;/a&gt; You will get a popup asking you to confirm. Confirm this. &lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4) Add a policy with Policy Generator.
&lt;/h3&gt;

&lt;p&gt;Under the permissions tab, scroll down to Bucket Policy and click 'Edit'.&lt;br&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%2Fsuv03cgn7hpdrz3xyiop.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%2Fsuv03cgn7hpdrz3xyiop.PNG" alt="Click on Edit Bucket Policy"&gt;&lt;/a&gt; This will allow you to access the &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_testing-policies.html" rel="noopener noreferrer"&gt;Policy Generator&lt;/a&gt;&lt;br&gt;
Bucket policies are written in JSON. Now, AWS provides a Policy Generator GUI to help you create the required JSON format.&lt;br&gt;
Also note that For me my ARN is arn:aws:s3:::markbdsouza-blog-post. This will be required in the next step.&lt;br&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%2Fmhit5s795nzv37m6mqrf.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%2Fmhit5s795nzv37m6mqrf.PNG" alt="Bucket Policy initial view"&gt;&lt;/a&gt;Click on Policy Generator and put in the below values &lt;br&gt;
Under Actions - Search for and select 'Get Object'&lt;br&gt;
Under Amazon Resource Name (ARN) : the files that we want to apply this policy to, make sure you append a /* at the end of your bucket url. This will include all files in your bucket. For me it would be- arn:aws:s3:::markbdsouza-blog-post/*&lt;br&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%2Fp4395py7tycizybxrlbr.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%2Fp4395py7tycizybxrlbr.PNG" alt="Policy Type and Statement"&gt;&lt;/a&gt;Hit 'Add Statement' and 'Generate Policy'&lt;br&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%2Fyf7bxh54lcfo7qshlrls.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%2Fyf7bxh54lcfo7qshlrls.PNG" alt="Generated Policy JSON"&gt;&lt;/a&gt;This generates the JSON you need to add to your bucket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "Id": "Policy1618322272060",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1618322267578",
      "Action": [
        "s3:GetObject"
      ],
      "Effect": "Allow",
      "Resource": "arn:aws:s3:::markbdsouza-blog-post/*",
      "Principal": "*"
    }
  ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please note the Resource in the policy would be different for you.&lt;br&gt;
Paste the created JSON policy in the Edit bucket policy section &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%2Fub9bwlanlyg9cc3bw90u.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%2Fub9bwlanlyg9cc3bw90u.PNG" alt="Updated Bucket Policy"&gt;&lt;/a&gt;Now scroll down and save changes. &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5) Set up the static website
&lt;/h3&gt;

&lt;p&gt;Go to the Properties tab of your bucket and scroll down to the end to 'Static website hosting section' &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%2Fjh4126xye453msw5kwlb.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%2Fjh4126xye453msw5kwlb.PNG" alt="Static Website Hosting"&gt;&lt;/a&gt; We see it is disabled. Click on 'Edit'.&lt;br&gt;
Enable static website hosting in the options provided and enter index.html as your index document. It also allows you to provide an Error document as an optional entry &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%2Floga1khr48dyrqrjaw98.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%2Floga1khr48dyrqrjaw98.PNG" alt="Static Website Options"&gt;&lt;/a&gt; Scroll down and hit save changes.&lt;br&gt;
Scroll back down to the bottom of Properties. It should now show you the url for your static website&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%2F6gu372nocl9zts0xphqa.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%2F6gu372nocl9zts0xphqa.PNG" alt="Created static website url"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6) Testing
&lt;/h3&gt;

&lt;p&gt;Click on the url, it will open a new tab with your website.&lt;br&gt;
My url is : &lt;a href="http://markbdsouza-blog-post.s3-website.ap-south-1.amazonaws.com/" rel="noopener noreferrer"&gt;http://markbdsouza-blog-post.s3-website.ap-south-1.amazonaws.com/&lt;/a&gt;  Not the friendliest of links but it gets the job done.&lt;br&gt;
Note: you can read your objects(files) in your bucket by adding /filepath. For example to see my script.js file I could read it through- &lt;a href="http://markbdsouza-blog-post.s3-website.ap-south-1.amazonaws.com/script.js" rel="noopener noreferrer"&gt;http://markbdsouza-blog-post.s3-website.ap-south-1.amazonaws.com/script.js&lt;/a&gt;&lt;br&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%2Fpehnqqh7pdipo9ztc4j5.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%2Fpehnqqh7pdipo9ztc4j5.PNG" alt="Created static website url"&gt;&lt;/a&gt;If you have followed these steps till now, please make sure you delete your buckets to avoid any unnecessary charges after your free trial is over.&lt;/p&gt;

&lt;p&gt;And that's it! A few one time steps to set up. If you need any changes to your website you can just reupload your files to your bucket and it will reflect in your website. &lt;br&gt;
You can also enable versioning in your bucket to make it easy to track changes and revert them if necessary. You could also use Route 53 to buy your domain instead of a long s3 specific url.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>deployment</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Spring Cloud Config Server: Step by Step</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Mon, 08 Mar 2021 18:05:17 +0000</pubDate>
      <link>https://forem.com/markbdsouza/spring-cloud-config-server-step-by-step-14fd</link>
      <guid>https://forem.com/markbdsouza/spring-cloud-config-server-step-by-step-14fd</guid>
      <description>&lt;p&gt;Spring Cloud Config Server is used to provide server-side and client-side support for externalized configuration in a distributed system. So when you have multiple microservices, and you want to easily control the configuration for all of them at one go - you'll mostly be looking at Spring Cloud Config Server.&lt;/p&gt;

&lt;h5&gt;
  
  
  So how do we do this?
&lt;/h5&gt;

&lt;p&gt;We will create a git project which contains all your properties files for the multiple microservices that you have (easy enough). We then create one spring boot application whose only role will be to be a micro service pointing to these files as it acts as a Spring Cloud Config Server. All the other microservices(the clients) can be configured to get the required properties from the Config Server. &lt;/p&gt;

&lt;p&gt;This isn't too tricky, and is actually easy to implement. In the below steps, I will walk you through how you can set this up in your project and even configure profiles for your microservices. &lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1) Create the Spring Cloud Config Server
&lt;/h1&gt;

&lt;h3&gt;
  
  
  1.1) Create a Sprig Boot App
&lt;/h3&gt;

&lt;p&gt;Lets start off creating our Spring boot application using start.spring.io&lt;br&gt;
I am using the Spring boot version 2.4.3 &lt;br&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%2Fdx1vnlduzrrkwzkysa1k.JPG" 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%2Fdx1vnlduzrrkwzkysa1k.JPG" alt="ServerSetup"&gt;&lt;/a&gt;&lt;br&gt;
Make sure the dependency is Config Server and not Config Client. &lt;br&gt;
Hit generate and you're done.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.2 Update the Main Class
&lt;/h3&gt;

&lt;p&gt;Open the project with your IDE.&lt;br&gt;
Open up your main Spring boot class with @SpringBootApplication and add &lt;code&gt;@EnableConfigServer&lt;/code&gt; as  well (Imported from import org.springframework.cloud.config.server.EnableConfigServer) &lt;br&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%2Ffz0k5sw4svxg69d0zwr9.JPG" 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%2Ffz0k5sw4svxg69d0zwr9.JPG" alt="ServerMainClassChange"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1.3 Create a git repo with the properties file
&lt;/h3&gt;

&lt;p&gt;Create a new folder where you will hold your config file and do a git init on that folder.&lt;/p&gt;

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

mkdir config-files
cd config-files
git init


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

&lt;/div&gt;

&lt;p&gt;now create the property file that you will map to your config server. We will be naming our microservice : microservice-one &lt;br&gt;
File Name : miroservice-one.properties &lt;/p&gt;

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

microservice-one.value=10


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

&lt;/div&gt;

&lt;p&gt;Now add and commit your changes. Else the spring boot app will not read it&lt;/p&gt;

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

git add .
git commit -m "created property file for microservice-one"


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

&lt;/div&gt;

&lt;p&gt;Note: you can also use yml files here &lt;/p&gt;

&lt;h3&gt;
  
  
  1.4 Update application.properties
&lt;/h3&gt;

&lt;p&gt;Copy the path of your new git repository and paste it in your application.properties file.&lt;/p&gt;

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

spring.application.name = spring-cloud-config-server
server.port=8888
spring.cloud.config.server.git.uri = file:///c:/Users/madsouza/Desktop/blogPost/config-files


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

&lt;/div&gt;

&lt;p&gt;The config server is generally set to port 8888.&lt;br&gt;
Windows users should make sure you are using the / and not \ when copying the path.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.5 Test it out
&lt;/h3&gt;

&lt;p&gt;Launch the application and navigate to : &lt;a href="http://localhost:8888/microservice-one/default" rel="noopener noreferrer"&gt;http://localhost:8888/microservice-one/default&lt;/a&gt;&lt;br&gt;
where microservice-one is the name of the file we have created. &lt;br&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%2Fhpb5cmu5zvdxloxmwnwz.JPG" 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%2Fhpb5cmu5zvdxloxmwnwz.JPG" alt="localhost 8888"&gt;&lt;/a&gt;&lt;br&gt;
As you can see, the property you have mapped is present. With this we are done setting up our basic Spring Cloud Config Server&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2) Create the Client Microservice
&lt;/h1&gt;

&lt;p&gt;Next up is fetching the property from this config server in an independent microservice. In our case microservice-one&lt;/p&gt;

&lt;h3&gt;
  
  
  2.1 Create a Spring Boot App
&lt;/h3&gt;

&lt;p&gt;Back to start.spring.io with Spring boot version 2.4.3 &lt;br&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%2Foza8ssemxckqk38ko5rp.JPG" 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%2Foza8ssemxckqk38ko5rp.JPG" alt="ClientSetup"&gt;&lt;/a&gt;&lt;br&gt;
Go ahead and generate the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  2.2 Update application.properties
&lt;/h3&gt;

&lt;p&gt;Open the app with your IDE and its time to do some configuration&lt;/p&gt;

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

spring.application.name = microservice-one
spring.config.import = optional:configserver:http://localhost:8888
#backup value
microservice-one.value=99


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

&lt;/div&gt;

&lt;p&gt;Here, we are basically importing the config server and providing the URL for the microservice. &lt;br&gt;
We can also mention the backup value in case for some reason we cannot find the config server. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.3 Create a configuration class
&lt;/h3&gt;

&lt;p&gt;Let us now create a Class that can read the properties from the config server &lt;/p&gt;

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

package com.markbdsouza.com.microserviceone;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("microservice-one")
@org.springframework.context.annotation.Configuration
public class Configuration {
    private String value;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }
}


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

&lt;/div&gt;

&lt;p&gt;Here we are setting the Configuration Properties annotation with the name of the file. This Class will automatically get set when the spring boot application is run and it would set the value that is present in the Spring Cloud Config Server&lt;/p&gt;

&lt;h3&gt;
  
  
  2.4 Create a Rest controller
&lt;/h3&gt;

&lt;p&gt;Now lets expose an endpoint which returns the config value &lt;/p&gt;

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

package com.markbdsouza.com.microserviceone;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MicroServiceController {

    @Autowired
    Configuration configuration;

    @GetMapping("/endpoint")
    public String retrieveLimits(){
        return configuration.getValue();
    }
}


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

&lt;/div&gt;

&lt;p&gt;Here we are auto-wiring the configuration class we created in the previous step and setting it at the '/endpoint' endpoint. &lt;/p&gt;

&lt;h3&gt;
  
  
  2.5 Test it out !
&lt;/h3&gt;

&lt;p&gt;Run the microservice-one spring boot application. and go to the defined controller end point &lt;br&gt;
&lt;a href="http://localhost:8080/endpoint" rel="noopener noreferrer"&gt;http://localhost:8080/endpoint&lt;/a&gt;&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%2F8m45hf7c5jpqkxdjdx6a.JPG" 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%2F8m45hf7c5jpqkxdjdx6a.JPG" alt="controller end point"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these simple steps you are DONE!&lt;br&gt;
I hope it doesn't seem as challenging as you thought it would be !!  &lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3) Implementing Profiles
&lt;/h1&gt;

&lt;p&gt;Now the only way to enhance this and make it really useful is having using different profiles. Depending on the environment, we usually have different properties file being used. So let's see how we can add different profile related configuration to our server and have it reflected in our client&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1) Commit additional properties files in git
&lt;/h3&gt;

&lt;p&gt;Now create additional application.properties files. One for dev and one for qa. &lt;br&gt;
File Name: microservice-one-dev.properties&lt;/p&gt;

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

microservice-one.value=50


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

&lt;/div&gt;

&lt;p&gt;File Name: microservice-one-qa.properties&lt;/p&gt;

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

microservice-one.value=75


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

&lt;/div&gt;

&lt;p&gt;make sure you do a git add and commit &lt;/p&gt;

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

git add .
git commit -m "created additional dev qa property files"


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

&lt;/div&gt;

&lt;p&gt;That's all you need to add new properties files. You don't need to touch the spring boot application we created as such. Just check in the files created.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.2) Test the profile related server endpoints
&lt;/h3&gt;

&lt;p&gt;Earlier we navigated to &lt;br&gt;
&lt;a href="http://localhost:8888/microservice-one/default" rel="noopener noreferrer"&gt;http://localhost:8888/microservice-one/default&lt;/a&gt;&lt;br&gt;
Now, 2 new endpoints open up in our 8888 port. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:8888/microservice-one/dev" rel="noopener noreferrer"&gt;http://localhost:8888/microservice-one/dev&lt;/a&gt;&lt;br&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%2Fc9cqmvs4bot7e7b30zd4.JPG" 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%2Fc9cqmvs4bot7e7b30zd4.JPG" alt="dev endpoint"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://localhost:8888/microservice-one/qa" rel="noopener noreferrer"&gt;http://localhost:8888/microservice-one/qa&lt;/a&gt;&lt;br&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%2F7sxwlcijht9jydflum74.JPG" 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%2F7sxwlcijht9jydflum74.JPG" alt="qa endpoint"&gt;&lt;/a&gt;&lt;br&gt;
Note that for both of these, we actually see the default value available as well. &lt;/p&gt;

&lt;h3&gt;
  
  
  3.3) Update the micro service
&lt;/h3&gt;

&lt;p&gt;All you really need to do is update the application.properties file of microservice-one and set the profile you want to use &lt;br&gt;
&lt;code&gt;spring.profiles.active=dev&lt;/code&gt; &lt;br&gt;
The overall file would now look like&lt;/p&gt;


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

&lt;p&gt;spring.application.name = microservice-one&lt;br&gt;
spring.config.import = optional:configserver:&lt;a href="http://localhost:8888" rel="noopener noreferrer"&gt;http://localhost:8888&lt;/a&gt;&lt;br&gt;
spring.profiles.active=dev&lt;/p&gt;
&lt;h1&gt;
  
  
  backup value
&lt;/h1&gt;

&lt;p&gt;microservice-one.value=99&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  3.4) One last Test&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Now if we hit the same endpoint we did earlier : &lt;a href="http://localhost:8080/endpoint" rel="noopener noreferrer"&gt;http://localhost:8080/endpoint&lt;/a&gt;&lt;br&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%2Fq2f89cg4sb2ednmogqkg.JPG" 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%2Fq2f89cg4sb2ednmogqkg.JPG" alt="dev value"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How quick and easy was that? You can very easily set it up for other profiles as well. I hope you've found this useful!! &lt;/p&gt;

</description>
      <category>springboot</category>
      <category>springcloud</category>
      <category>java</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Data Binding in Angular</title>
      <dc:creator>Mark Dsouza</dc:creator>
      <pubDate>Tue, 02 Mar 2021 18:46:50 +0000</pubDate>
      <link>https://forem.com/markbdsouza/data-binding-in-angular-59cb</link>
      <guid>https://forem.com/markbdsouza/data-binding-in-angular-59cb</guid>
      <description>&lt;p&gt;In this article, let's take a look at what data binding in Angular really is and how we can use it. Once we get this figured out, let's see how this compares to doing something similar with HTML and JS&lt;/p&gt;

&lt;h2&gt;
  
  
  So what is Data binding?
&lt;/h2&gt;

&lt;p&gt;Imagine the entire web page is split into different smaller individual parts - a header, a footer, maybe a sidebar, a main section(which probably has its own distinct sub-sections)- each with its own logic. These are called Components in Angular and it is basically the building block of Angular. Each Component defines a class that contains the application data and logic, and is associated with an HTML template that defines a view to be displayed in the target environment. &lt;br&gt;
Data binding is all about how these 2 files can communicate with each other and how data flows between the Component(TypeScript controller source) and the View(HTML Template). &lt;/p&gt;
&lt;h2&gt;
  
  
  The Types of Data Binding
&lt;/h2&gt;

&lt;p&gt;In general this can be split into &lt;br&gt;
1) Data being passed from Component to View&lt;br&gt;
2) Data being passed from View to Component&lt;br&gt;
3) A Combination of the above two&lt;/p&gt;
&lt;h3&gt;
  
  
  1) Data is passed from the Component to the View
&lt;/h3&gt;
&lt;h4&gt;
  
  
  String Interpolation
&lt;/h4&gt;

&lt;p&gt;If we want to display data which is in our component as text in our template. All we need to do is enclose it in &lt;code&gt;{{ X }}&lt;/code&gt; . Where X would be the name of the variable/function returning the data to be displayed in the view.&lt;br&gt;
Syntax : &lt;code&gt;&amp;lt;div&amp;gt; {{valueFromComponent}} &amp;lt;/div&amp;gt;&lt;/code&gt;&lt;br&gt;
Note : You can even mention a function. The return value of the function will be assigned to the property &lt;br&gt;
For Example: Say you are receiving some data from an API which has a JSON structure assigned to a variable &lt;code&gt;let data = {header: 'Topic Header', details: 'all the details'}&lt;/code&gt;. Then you can use &lt;code&gt;&amp;lt;h1&amp;gt;{{data.header}}&amp;lt;/h1&amp;gt; &amp;lt;h5&amp;gt;{{data.details}}&amp;lt;/h5&amp;gt;&lt;/code&gt; in your view to easily assign the data. &lt;br&gt;
You do not need to get the independent elements using query selectors in JS and then assign it. I hope you see how powerful and easy it would be to map larger objects with basic string interpolation.&lt;/p&gt;
&lt;h4&gt;
  
  
  Property Binding
&lt;/h4&gt;

&lt;p&gt;Next up is property binding where you can modify properties for DOM elements depending on values in the component. &lt;br&gt;
Syntax : &lt;code&gt;&amp;lt;div [propertyName] : "valueFromComponent"&amp;gt; &amp;lt;/div&amp;gt;&lt;/code&gt;&lt;br&gt;
We use square brackets [] to enclose the property we are trying to bind with the component file. You can even mention a function. The return value of the function will be assigned to the property.&lt;br&gt;
A use case for this would be to have a button enabled only when a certain condition is met or assigning the src of an image to a Url that you receive from an API.&lt;br&gt;
Example : &lt;code&gt;&amp;lt;img [src]="imgSrcUrl"&amp;gt;&lt;/code&gt; where imgSrcUrl is present in the Component file.&lt;br&gt;
We can use property binding to bind the class or even style &lt;br&gt;
&lt;code&gt;&amp;lt;div [class.sale]="onSale"&amp;gt;&amp;lt;/div&amp;gt; &amp;lt;div [style.background-color]="expression"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;br&gt;
Example of having logic in the expression -&lt;br&gt;
&lt;code&gt;&amp;lt;div [style.color]= "status=='Incomplete' ? 'red': 'green'"  &lt;br&gt;
     [style.text-align]= "'center'" &amp;gt;&lt;/code&gt;&lt;br&gt;
This allows us to have behavioral logic in the HTML file itself.&lt;br&gt;
Note : Data binding works with properties of DOM elements, components, and directives, not HTML attributes.&lt;/p&gt;
&lt;h3&gt;
  
  
  2) Data is passed from the View to the Component
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Event Binding
&lt;/h4&gt;

&lt;p&gt;We can bind events to functions in our component Object. This is similar to adding event listeners in our JS file. Here we do that binding in the HTML itself&lt;br&gt;
Syntax : &lt;code&gt;&amp;lt;button (click)="methodInTSFile()"&amp;gt; Click &amp;lt;/button&amp;gt;&lt;/code&gt;&lt;br&gt;
This can be done for any events that the view may encounter&lt;br&gt;
Example:  &lt;code&gt;&amp;lt;select (change) = "changeData($event)"&amp;gt;      &amp;lt;option&amp;gt;1&amp;lt;/option&amp;gt;      &amp;lt;option&amp;gt;2&amp;lt;/option&amp;gt;      &amp;lt;option&amp;gt;3&amp;lt;/option&amp;gt;   &amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3) Data is passed from the View to the Component and back
&lt;/h3&gt;
&lt;h4&gt;
  
  
  Two-Way binding
&lt;/h4&gt;

&lt;p&gt;basically data flows both ways - from component to view and view to component. But what does this mean exactly? Say you have an input field where the user types in something. Once the input field value is changed, the variable it is associated with in the TS file also changes. If we update the field in the input file, it modifies the value displayed on the page as well. The user does not have to tag a change event to the element, it is automatically taken care of. &lt;br&gt;
Syntax : &lt;code&gt;&amp;lt;div [(ngModel)]="variableInTSFile"&amp;gt; Test &amp;lt;/div&amp;gt;&lt;/code&gt;&lt;br&gt;
This syntax is called 'Banana in a box'. If you look close, all it is is a combination of [] and (). Below might explain that a little better.&lt;br&gt;
The below code, where myModel is a variable in the component object&lt;br&gt;
&lt;code&gt;&amp;lt;input [value]="myModel" (input)="myModel=$event.target.value" /&amp;gt;&lt;/code&gt;&lt;br&gt;
can be written in a single go as &lt;br&gt;
&lt;code&gt;&amp;lt;input [(ngModel)]="myModel"&amp;gt;&lt;/code&gt; &lt;br&gt;
combining property binding and event binding.&lt;br&gt;
Note: ngModel is a directive that is part of the FormsModule. Please make sure you add it to your imports in the app.module.ts&lt;/p&gt;
&lt;h2&gt;
  
  
  Comparison with data-binding using vanilla JS
&lt;/h2&gt;

&lt;p&gt;Below is the HTML &amp;amp; JS Code for the below business rules &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Page contains a heading, sub-heading, input field, checkbox, save button&lt;/li&gt;
&lt;li&gt;Heading, sub-heading and input field are populated by an API Call and are not known before hand&lt;/li&gt;
&lt;li&gt;On click of the checkbox, the save button should get toggled. By default on page load, save button should be disabled&lt;/li&gt;
&lt;li&gt;When the user clicks save, an API call is made with the data in the input field. the input field should be updated once the call is complete with the response.&lt;/li&gt;
&lt;li&gt;Ignore the API Call in the code. Write a comment wherever an API needs to be done.
Now, lets take a peak at how you would implement the same logic in JS.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;index.html&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;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;

&amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8"&amp;gt;
    &amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
    &amp;lt;title&amp;gt;Data Binding&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;

&amp;lt;body&amp;gt;
    &amp;lt;h1 id="header"&amp;gt;&amp;lt;/h1&amp;gt;
    &amp;lt;h4&amp;gt;This is to show the &amp;lt;span id="subHeading"&amp;gt;&amp;lt;/span&amp;gt; demo&amp;lt;/h4&amp;gt;
    &amp;lt;div class="container"&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;input type="text" id="details"&amp;gt;
            &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;label for="isComplete"&amp;gt;Completed?&amp;lt;/label&amp;gt;
            &amp;lt;input type="checkbox" name="isComplete" id="isComplete"&amp;gt;
            &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div&amp;gt;
            &amp;lt;button id="saveBtn" disabled&amp;gt;Save&amp;lt;/button&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;script src="./script.js"&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;

&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;script.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;headerEl = document.getElementById('header');
subHeadingEl = document.getElementById('subHeading');
saveBtn = document.getElementById('saveBtn');
isComplete = document.getElementById('isComplete');
detailsEl = document.getElementById('details');

function setInitValues() {
  // get initial values after making an API Call
  let returnObj = { header: 'Data Binding', details: 'Enter details here...' };
  headerEl.innerText = returnObj.header;
  subHeadingEl.innerText = 'Data Binding';
  detailsEl.value = returnObj.details;
  console.log(`initialized page`);
}

function completeClicked(e) {
  //should call the toggle save button method
  console.log('clicked');
  toggleSaveBtn(e.target.checked);
}

function toggleSaveBtn(conditon) {
  //toggle save button depending on condition
  if (conditon) {
    saveBtn.disabled = false;
  } else saveBtn.disabled = true;
}

function saveDetails() {
  let details = detailsEl.value;
  console.log(`saved details :${details}`);
  //call api to save details which returns updated details
  detailsEl.value = 'Updated details...';
}

setInitValues();
isComplete.addEventListener('click', completeClicked);
saveBtn.addEventListener('click', saveDetails);

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

&lt;/div&gt;



&lt;p&gt;Here we basically have to write query selectors to identify the elements we want to modify the value of or add event listeners to. &lt;/p&gt;

&lt;p&gt;On Page Load &lt;br&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%2F31ig4zkebf9herv8o7of.JPG" 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%2F31ig4zkebf9herv8o7of.JPG" alt="On Load"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When checkbox is clicked&lt;br&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%2Fpdobnr9zln40tjml7o42.JPG" 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%2Fpdobnr9zln40tjml7o42.JPG" alt="When Clicked"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When Save is clicked&lt;br&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%2Fewayqgn288erf8mzgyoy.JPG" 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%2Fewayqgn288erf8mzgyoy.JPG" alt="On Save"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now lets see how we can implement the exact same functionality with Angular. After creating my base angular project, below are the app component files&lt;/p&gt;

&lt;p&gt;app.component.html&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;h1 id="header"&amp;gt;{{header}}&amp;lt;/h1&amp;gt;
&amp;lt;h4&amp;gt;This is to show the {{subHeading}} demo&amp;lt;/h4&amp;gt;
&amp;lt;div class="container"&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;input type="text" id="details" [(ngModel)]="details"&amp;gt;
    &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;label for="isComplete"&amp;gt;Completed?&amp;lt;/label&amp;gt;
    &amp;lt;input type="checkbox" name="isComplete" id="isComplete" (click)='completeClicked($event)'&amp;gt;
    &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;div&amp;gt;
    &amp;lt;button id="saveBtn" [disabled]="disableSave" (click)=' saveDetails()'&amp;gt;Save&amp;lt;/button&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;app.component.ts&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent {
  title = "data-binding";
  header: string;
  subHeading: string;
  disableSave: boolean = true;
  details: string;

  ngOnInit() {
    // get initial values after making an API Call
    let returnObj = {
      header: "Data Binding",
      details: "Enter details here...",
    };
    this.header = returnObj.header;
    this.subHeading = "Data Binding";
    this.details = returnObj.details;
    console.log(`initialized page`);
  }

  completeClicked(e) {
    console.log("clicked");
    this.disableSave = !e.target.checked;
  }

  saveDetails() {
    console.log(`saved details :${this.details}`);
    //call api to save details which returns updated details
    this.details = "Updated details...";
  }
}

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

&lt;/div&gt;



&lt;p&gt;On Load&lt;br&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%2Flmhojhqtdxt3w2qjhqpu.JPG" 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%2Flmhojhqtdxt3w2qjhqpu.JPG" alt="Angular On  Load"&gt;&lt;/a&gt;&lt;br&gt;
On click of the checkbox&lt;br&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%2Fu6ymjnlwoilzs187vcjj.JPG" 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%2Fu6ymjnlwoilzs187vcjj.JPG" alt="Angular On Click"&gt;&lt;/a&gt;&lt;br&gt;
On Save&lt;br&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%2Fhyncv79vvdqx9u0geugu.JPG" 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%2Fhyncv79vvdqx9u0geugu.JPG" alt="Angular On Save"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, in the above angular example, we have used string interpolation for setting the main heading and sub heading, used property binding to bind the disabled property of the save button. We use event binding for the checkbox click event and the save button click event. 2 Way binding is used for the details input field where the data is shared between HTML and TS file. &lt;/p&gt;

&lt;p&gt;As the complexity of your page increases, the number of components you have also increase. Having a good data binding mechanism by using frameworks such as Angular, makes it a lot easier for the developer to write clean, error free code. &lt;/p&gt;

&lt;p&gt;I hope you found this walkthrough useful and you are clear on everything related to data binding in Angular! Cheers ^_^&lt;/p&gt;

</description>
      <category>angular</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
