DEV Community

Rose
Rose

Posted on • Originally published at rosafiore.eu

Adding Functionality to the Backend - Building a Blog

The proof of concept worked like a charm. Now, I need to create the basis by adding functionality to the backend. today, I'll start with creating a blog post and see what challenges lie ahead on the road.

So, before I start implementing the full feature of creating a blog post. I had to remove the testing code I created last time in my proof of concept. With a clean BlogPostController, I can further structure my Spring Boot project.

High-Level Project Structure

I want to keep my business logic separated from my controller layer, even though there might not be a whole lot of business logic to a blog backend. Between my controller and repository layer, I add a service layer. So, essentially, we get the following structure in my project.

High-Level Project Structure for Adding Functionality

As you can see, I'm using a BlogPostService interface and a BlogPostServiceImpl for the implementation class. In this case, I'd like to use interfaces to future proof my software in case I need to change something in the implementation of my service. At school, I never really understood why, but this post on StackExchange has helped me understand this better.

Adding Functionality

Personally, I'd like to work from bottom to top when it comes to adding new functionality to my backend. Right now, I want to start with the first CRUD operating: create. I expect my frontend to deliver a blog post object in the request body, therefore I'musing my blogpost object in my code.

BlogPostService Interface

So, building from bottom to top, I start with my BlogPostService interface first. For now, the interface is still quite empty, but that will change soon enough when adding more functionality of course. For now, my interface looks like this.

public interface BlogPostService {
    public abstract void CreateBlogPost(BlogPost blogPost);
}

BlogPostService Implementation

With the interface in place, I now have to write the implementation of the method in my BlogPostServiceImpl with the same bit of code I used last time for MongoDB. Also,I have annotated the class with @Service to let Spring Boot know that this is a service component within my application. Furthermore, I have autowired MongoTemplate, so I can use it freely for saving my blog post to the database.

@Service
public class BlogPostServiceImpl implements BlogPostService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public void CreateBlogPost(BlogPost blogPost) {
        mongoTemplate.save(blogPost, "blogposts");
    }
}

BlogPostController

Finally, I can write the code for my controller layer. I've added a couple annotations to my BlogPostController versus last time.

@RestController()
@RequestMapping("/blog")
public class BlogPostController {

    @Autowired
    private BlogPostService blogPostService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void createBlogPost(@RequestBody BlogPost blogPost) {
        blogPostService.CreateBlogPost(blogPost);
    }
}

Let's go through the annotations. I have started with adding @RestController above my class to notify Spring Boot that this is a controller component, specifically one that accepts REST requests. Furthermore, I have added a custom endpoint set with @RequestMapping("/blog"). That means that every endpoint within this controller is http://localhost:8080/blog. For every method, I have to define what type of method it is with the @PostMapping annotation.

If you want to change the endpoint per method, you can add the name of the endpoint as a string in brackets behind @PostMapping like this: @PostMapping("/test"). The full endpoint for this method will be http://localhost:8080/blog/test. Of course, you can do this for all request types.

The last annotation, @ResponseStatus(HttpStatus.CREATED) allows me to define what response I want my backend to send back. At this stage, I haven't yet figured out how to throw the exceptions. I still have to figure that out, and when I do, I'll write about it of course. For now, this will have to do and it serves its testing purpose.

Last, but definitely not least, I have used te @RequestBody annotation before my BlogPost variable. This annotation lets Spring Boot know to check in the request body for the blog post object, which the service uses to save the post to the database.

Testing My Feature

Excited with my new bits of code, I was eager to test if it works. I run my first test with curl, since I don't have Postman available on my Debian laptop. Failed. Damn it! I check what I tried to send as my request body, and I noticed that I misspelled endpoint.There must be a way to validate the object to get a cleaner error message, right?

Java Bean Validation

After a quick search, I came across two articles (this one and this one) from Baeldung on Java Bean Validation. With a simple annotation, the bean automatically validates the input in the request body to match the object. I only have to make some tiny adjustments.

First, I have to add two dependencies to my pom.xml file:

<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator-annotation-processor</artifactId>
</dependency>

After letting maven do its thing, I only have to add the @Valid annotation before the request body annotation, and that's it! Now, the function should work.

Date Format

Yeah, not a chance. The function still doesn't work. This time, I'm getting a parsing error on the data I input. Fortunately, Baeldung came to the rescue again with a little article on the JsonFormat annotation. I added a small adjustment to my BlogPost class with the following line of code:

@JsonFormat(pattern="dd-MM-yyyy HH:mm")
private Date publishDate;

Functionality Added!

At long last, I am able to post a blog post! It is far from perfect yet, as I still have to figure out how to get the exceptions to work. Furthermore, I still have to write unit tests as well to make sure that my code is working as expected. That is what I'll be working on the upcoming few days. Once I get these two parts done, I can continue with adding even more functionality like getting and deleting a specific or all posts.

Discussion (0)