lapadets
lapadets

Reputation: 1095

Populate a database column by calling a rest API

I have a small spring boot service with a database (I use spring data JPA) and I need some additional info from another rest API. So I can get this additional info only by calling a rest API with ids from my database, and then save it.

So I created a controller with an endpoint /migrate and my idea is that when I start the service, I can call this endpoint, then I use findAll() to load all entries, and finally I iterate over them and call the 3rd party rest endpoint for each to get the additional info. So far so gut... but I am not sure what is the best approach here. Shall my endpoint be just a void method or, I should I model it ResponseEntity? My question is more or less what is the best practice here.

Here is some code.

@RestController
@RequiredArgsConstructor
@Slf4j
public class MigrationController {

private final MigrationService migrationService;

@GetMapping("/migrate")
public ResponseEntity<MigrationResult> migrateData() {

    var migrationResult = migrationService.migrateData();
    // this is not optimal here...
    if (migrationResult.getStatusCode().startsWith("2")) {
        return ResponseEntity.ok().body(migrationResult);
    } else {
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(migrationResult);
    }
}

}

And here is the MigrationService :

@Service
@AllArgsConstructor
public class MigrationService {

    private final CustomerRepository customerRepository;
    private final OrderService orderService;

    public MigrationResult migrateData() {
        var updatedCustomersCounter = new AtomicInteger();
        var migrationResult = new MigrationResult();
        long start = System.currentTimeMillis();

        var customers = customerRepository.findAll();

        if (customers.isEmpty()) {
            return MigrationResult.builder()
                .message("No customer datafound in database")
                .statusCode("404")
                .build();
        }

        for (Customer customer : customers) {
            try {
                var order = orderService.getOrderById(customer.getOrderId());

                if (order != null && !order.getOrders().isEmpty()) {
                    customer.setUniqueId(order.getOrders().get(0).getUniqueId());
                    updatedCustomersCounter.getAndIncrement();
                    customerRepository.save(customer);
                }

                if (order != null && order.getOrders().isEmpty()) {
                    return MigrationResult.builder()
                        .message("Migration of unique Id for oder id " + order.getOrderId() + " failed.")
                        .statusCode("500")
                        .build();
                }

            } catch (Exception e) {
                migrationResult.setMessage("Unexpected error while updating customer.");
                migrationResult.setStatusCode("500");
            }

            migrationResult.setMessage(
                "Migration of " + updatedCustomersCounter.get() + " customers finished in: " + (System.currentTimeMillis() - start)
                    + "ms. Total number of entries with present orderId " + filteredDataPlans.size());
            migrationResult.setStatusCode("200");
        }

        return migrationResult;
    }

}

Here is my model I use with the ResponseEntity:

public class MigrationResult {
    @NotNull
    private String statusCode;
    @NotNull
    private String message;
}

As you can see, I need this uniqueId from so-called orderService and then I save it to my Customer Entity. Obviously that will take some time to finish (around 1000 entries -> calls). I feel it is 'fishy' the way I've done it. But I am not sure what is the best approach, i.e. what is the better way to do something like this and still be HTTP conform regarding error messages and possible timeout (if the job runs too long). Also, there is no UI - That's why I decided to use this small POJO MigrationResult with message that I could become as JSON.

Upvotes: 0

Views: 578

Answers (1)

Mirjan Gjeta
Mirjan Gjeta

Reputation: 139

It depends on requirements you have .If you don't need such information you can simply return HttpStatus.Ok, but i think best approach would be to return a report after migration task is completed.Instead of wrapping information on String variable i would prefer to store this info in separate variables and create a method to build message with data you want to display.

public class MigrationReport{
  
   private String status;
   private String startDate;
   private String numberOfusers;
   private Long   durationTime;
   //
   // 
   private String message;
   
   //getter && setter methods 

} 

Suggestion : Instead of long start = System.currentTimeMillis(); use Instant.now()

Upvotes: 2

Related Questions