Skip to content

Commit

Permalink
feat : handle service calls efficiently
Browse files Browse the repository at this point in the history
  • Loading branch information
rajadilipkolli committed Oct 23, 2023
1 parent 9f77cbb commit aed94f9
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 146 deletions.
10 changes: 10 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@
"projectName": "boot-ultimate-redis",
"args": "",
"envFile": "${workspaceFolder}/.env"
},
{
"type": "java",
"name": "Spring Boot-TestApplication<boot-http-proxy>",
"request": "launch",
"cwd": "${workspaceFolder}",
"mainClass": "com.example.rest.proxy.TestApplication",
"projectName": "boot-http-proxy",
"args": "",
"envFile": "${workspaceFolder}/.env"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,27 @@

import com.example.rest.proxy.entities.Post;
import java.util.List;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.service.annotation.DeleteExchange;
import org.springframework.web.service.annotation.GetExchange;
import org.springframework.web.service.annotation.HttpExchange;
import org.springframework.web.service.annotation.PostExchange;
import org.springframework.web.service.annotation.PutExchange;

@HttpExchange(url = "https://jsonplaceholder.typicode.com")
public interface JsonPlaceholderService {

@GetExchange("/posts")
List<Post> loadAllPosts();

@GetExchange("/posts/{id}")
Post loadPostById(@PathVariable Long id);

@PostExchange("/posts")
Post createPost(@RequestBody Post post);

@PutExchange("/posts/{id}")
Post updatePostById(@PathVariable Long id, @RequestBody Post post);

@DeleteExchange("/posts/{id}")
Post deletePostById(@PathVariable Long id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.rest.proxy.exception;

import java.net.URI;
import java.time.Instant;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.web.ErrorResponseException;

public class PostNotFoundException extends ErrorResponseException {

public PostNotFoundException(Long id) {
super(HttpStatus.NOT_FOUND, asProblemDetail(id), null);
}

private static ProblemDetail asProblemDetail(Long id) {
ProblemDetail problemDetail =
ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND, "Post with Id '%d' not found".formatted(id));
problemDetail.setTitle("Post Not Found");
problemDetail.setType(URI.create("http://api.posts.com/errors/not-found"));
problemDetail.setProperty("errorCategory", "Generic");
problemDetail.setProperty("timestamp", Instant.now());
return problemDetail;
}
}
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
package com.example.rest.proxy.services;

import com.example.rest.proxy.client.JsonPlaceholderService;
import com.example.rest.proxy.entities.Post;
import com.example.rest.proxy.exception.PostNotFoundException;
import com.example.rest.proxy.model.response.PagedResult;
import com.example.rest.proxy.repositories.PostRepository;
import java.util.Optional;
import java.util.function.Function;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.HttpClientErrorException;

@Service
@Transactional
@RequiredArgsConstructor
public class PostService {

private final PostRepository postRepository;
private final JsonPlaceholderService jsonPlaceholderService;

public PagedResult<Post> findAllPosts(int pageNo, int pageSize, String sortBy, String sortDir) {
Sort sort =
Expand All @@ -33,14 +39,35 @@ public PagedResult<Post> findAllPosts(int pageNo, int pageSize, String sortBy, S
}

public Optional<Post> findPostById(Long id) {
return postRepository.findById(id);
Optional<Post> optionalPost = postRepository.findById(id);
if (optionalPost.isPresent()) {
return optionalPost;
} else {
Function<Long, Post> loadPostById = jsonPlaceholderService::loadPostById;
return Optional.of(callService(id, loadPostById.andThen(this::savePost)));
}
}

public Post savePost(Post post) {
return postRepository.save(post);
Post savedPost = jsonPlaceholderService.createPost(post);
return postRepository.save(savedPost);
}

public void deletePostById(Long id) {
jsonPlaceholderService.deletePostById(id);
postRepository.deleteById(id);
}

private <T> T callService(Long id, Function<Long, T> serviceFunction) {
T result;
try {
result = serviceFunction.apply(id);
} catch (HttpClientErrorException exception) {
if (exception.getStatusCode() == HttpStatus.NOT_FOUND) {
throw new PostNotFoundException(id);
}
throw exception;
}
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@ server.shutdown=graceful
spring.main.allow-bean-definition-overriding=true
spring.jmx.enabled=false

################ Logging #####################
logging.file.name=logs/${spring.application.name}.log
logging.level.web=INFO
logging.level.sql=INFO
## To enable transaction details logging
#logging.level.org.springframework.orm.jpa=DEBUG
#logging.level.org.springframework.transaction=DEBUG
#logging.level.org.hibernate.engine.transaction.internal.TransactionImpl=DEBUG

################ Actuator #####################
management.endpoints.web.exposure.include=configprops,env,health,info,logfile,loggers,metrics
management.endpoint.health.show-details=always
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>


<include resource="org/springframework/boot/logging/logback/defaults.xml" />
<include resource="org/springframework/boot/logging/logback/console-appender.xml" />

<springProperty scope="context" name="appName" source="spring.application.name"/>

<springProfile name="default">
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</springProfile>

<springProfile name="!default">
<property name="LOG_FILE" value="${java.io.tmpdir:-/tmp}/logs/${appName}.log"/>
<include resource="org/springframework/boot/logging/logback/file-appender.xml" />
<root level="INFO">
<appender-ref ref="FILE" />
Expand All @@ -19,5 +21,7 @@
</springProfile>

<logger name="com.example.rest.proxy" level="DEBUG"/>
<logger name="org.springframework.transaction" level="DEBUG" />
<logger name="org.springframework.web" level="INFO" />

</configuration>

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
package com.example.rest.proxy;

import com.example.rest.proxy.config.DBTestContainersConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.devtools.restart.RestartScope;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.PostgreSQLContainer;

@TestConfiguration(proxyBeanMethods = false)
public class TestApplication {

@Bean
@ServiceConnection
@RestartScope
PostgreSQLContainer<?> postgresContainer() {
return new PostgreSQLContainer<>("postgres:16.0-alpine");
}

public static void main(String[] args) {
SpringApplication.from(Application::main)
.with(DBTestContainersConfiguration.class)
.run(args);
SpringApplication.from(Application::main).with(TestApplication.class).run(args);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,16 @@
import static com.example.rest.proxy.utils.AppConstants.PROFILE_TEST;
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;

import com.example.rest.proxy.config.DBTestContainersConfiguration;
import com.example.rest.proxy.TestApplication;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;

@ActiveProfiles({PROFILE_TEST})
@SpringBootTest(webEnvironment = RANDOM_PORT)
@Import(DBTestContainersConfiguration.class)
@SpringBootTest(webEnvironment = RANDOM_PORT, classes = TestApplication.class)
@AutoConfigureMockMvc
public abstract class AbstractIntegrationTest {

Expand Down

This file was deleted.

This file was deleted.

0 comments on commit aed94f9

Please sign in to comment.