3

I need to track entity view count.. for example I have a Product entity and have the following API endpoint:

GET /products/{productID} 

In case I want to track a view count of a particular Product should I add additional logic that will increment view count when I call this /products/{productID} endpoint? Or I should introduce a separate endpoint for this purpose?

UPDATED

Maybe I was not clear on my question but my question is about best practice for updating counters with REST API and not about multi-layer architecture. I'm trying to ask the following - should I update the counter by mentioned GET request or I should introduce another API.. let's say POST /products/{productID}/viewings and call it subsequently after the GET in order to update the counter?

alexanoid
  • 24,051
  • 54
  • 210
  • 410
  • Controller handles Web stuff, service implements business logic, database (dao) accesses the database. – DwB Sep 27 '17 at 18:07

5 Answers5

3

Is the view count a property on the Product entity or is it metadata?

If the view count is a property, then consider a separate PUT or PATCH request to update it.

A GET is a safe method and shouldn't update the resource being requested. If a client would prefetch and/or cache the result of that supposedly safe request, you'd have an incorrect view count.

Another question to ask yourself is whether the view count is synonymous with a GET request of that resource. In other words, might your app perform a GET on a resource for a reason other than a user view. If so, that would be another reason to increment the view count in a separate non-safe request.

If the view count is indeed metadata and a GET really does equate to a user view, then I would go ahead and increment the counter on the GET. A separate request has a cost and there are likely other harmless side effects happening (e.g. logging) on the server for each safe request being made.

Matt Terski
  • 891
  • 8
  • 11
2

Ideally it should be subsequent call as GET service is meant for retrieving the value. Since you have almost same logic in POST for updating the count you can make use of same service as given below :

      @RequestMapping(value = "/product/{id}", method = { RequestMethod.GET, RequestMethod.POST })
        public Product getProduct(@PathVariable String id){
           //get and update product
return product;
    }
Raj gopal
  • 114
  • 3
  • 12
0

This seems like a good scenario for AOP (Aspect Oriented Programing) as this will allow you to separate this statistic logic from the business logic.

Have a look at Spring doc for more info about AOP and how to achieve that with Spring.

You can then define a pointcut on your controller and have a service for counting (and probably then storing) the data.

Matt
  • 3,422
  • 1
  • 23
  • 28
0

Don't put the count in either the controller or in an AOP interceptor; both are terrible solutions for this problem.

You should have a datasource that provides information about a give product (perhaps a database). You should be using JDBC wrapper to access the database (maybe a DAO written using Hibernate or MyBatis). You should also have a service that is called by the controller to retrieve a given datasource (as demonstrated in the gene b answer).

Put the access count in either the database code (the DAO) or in the service.

Store the count in the database (perhaps create an AccessedProducts table).

DwB
  • 37,124
  • 11
  • 56
  • 82
  • Thanks for your answer. Maybe I was not clear at my question but my question is about best practice for updating counters with REST API and not about multi-layer architecture. I'm trying to ask the following - should I update the counter by mentioned `GET` request or I should introduce another API.. let's say `POST /products/{productID}/viewings` and call it subsequently after the `GET` in order to update the counter? – alexanoid Sep 27 '17 at 18:57
-1

As far as how to get started with a RestController in SpringMVC, the following is a quickstart example (with products/{id} and a JSON/XML req method, JSON is a straight /id and XML is /id.xml).

@RestController
@RequestMapping("products")
public class ProductsController {

    @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = "application/json")
    public Product getProductInJSON(@PathVariable String id) {

       //...Service/DAO fetch based on "id"
       Product p = service.getProduct(id);
       return p;
    }

    @RequestMapping(value = "/{id}.xml", method = RequestMethod.GET, produces = "application/xml")    
    public Product getProductInXML(@PathVariable String id) {

       //...Service/DAO fetch based on "id"
       Product p = service.getProduct(id);
       return p;

    } 
}

Regarding View Count, yes, I would just add extra logic in the Controller - may be cleaner/simpler than an interceptor.

gene b.
  • 10,512
  • 21
  • 115
  • 227