Source code for Lightrun articles

This commit is contained in:
Graham Cox
2022-05-17 16:07:21 +01:00
parent 06a6b0b3a7
commit 67b8a66173
54 changed files with 1460 additions and 0 deletions

33
lightrun/api-service/.gitignore vendored Normal file
View File

@@ -0,0 +1,33 @@
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/
### VS Code ###
.vscode/

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.7</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.baeldung</groupId>
<artifactId>api-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>api-service</name>
<description>Aggregator Service for LightRun Article</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,13 @@
package com.baeldung.apiservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ApiServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ApiServiceApplication.class, args);
}
}

View File

@@ -0,0 +1,33 @@
package com.baeldung.apiservice;
import org.slf4j.MDC;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
@Component
public class RequestIdGenerator implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String requestId = UUID.randomUUID().toString();
MDC.put(RequestIdGenerator.class.getCanonicalName(), requestId);
response.addHeader("X-Request-Id", requestId);
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
MDC.remove(RequestIdGenerator.class.getCanonicalName());
}
public static String getRequestId() {
return MDC.get(RequestIdGenerator.class.getCanonicalName());
}
}

View File

@@ -0,0 +1,20 @@
package com.baeldung.apiservice;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder
.additionalInterceptors((request, body, execution) -> {
request.getHeaders().add("X-Request-Id", RequestIdGenerator.getRequestId());
return execution.execute(request, body);
})
.build();
}
}

View File

@@ -0,0 +1,17 @@
package com.baeldung.apiservice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private RequestIdGenerator requestIdGenerator;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(requestIdGenerator);
}
}

View File

@@ -0,0 +1,11 @@
package com.baeldung.apiservice.adapters.http;
import java.time.Instant;
public record TaskResponse(String id,
String title,
Instant created,
UserResponse createdBy,
UserResponse assignedTo,
String status) {
}

View File

@@ -0,0 +1,54 @@
package com.baeldung.apiservice.adapters.http;
import com.baeldung.apiservice.adapters.tasks.Task;
import com.baeldung.apiservice.adapters.tasks.TaskRepository;
import com.baeldung.apiservice.adapters.users.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
@RequestMapping("/")
@RestController
public class TasksController {
@Autowired
private TaskRepository taskRepository;
@Autowired
private UserRepository userRepository;
@GetMapping("/{id}")
public TaskResponse getTaskById(@PathVariable("id") String id) {
Task task = taskRepository.getTaskById(id);
if (task == null) {
throw new UnknownTaskException();
}
return buildResponse(task);
}
private TaskResponse buildResponse(Task task) {
return new TaskResponse(task.id(),
task.title(),
task.created(),
getUser(task.createdBy()),
getUser(task.assignedTo()),
task.status());
}
private UserResponse getUser(String userId) {
if (userId == null) {
return null;
}
var user = userRepository.getUserById(userId);
if (user == null) {
return null;
}
return new UserResponse(user.id(), user.name());
}
@ExceptionHandler(UnknownTaskException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public void handleUnknownTask() {
}
}

View File

@@ -0,0 +1,4 @@
package com.baeldung.apiservice.adapters.http;
public class UnknownTaskException extends RuntimeException {
}

View File

@@ -0,0 +1,4 @@
package com.baeldung.apiservice.adapters.http;
public record UserResponse(String id, String name) {
}

View File

@@ -0,0 +1,11 @@
package com.baeldung.apiservice.adapters.tasks;
import java.time.Instant;
public record Task(String id,
String title,
Instant created,
String createdBy,
String assignedTo,
String status) {
}

View File

@@ -0,0 +1,30 @@
package com.baeldung.apiservice.adapters.tasks;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
@Repository
public class TaskRepository {
@Autowired
private RestTemplate restTemplate;
@Value("${tasks-service.url}")
private String tasksService;
public Task getTaskById(String id) {
var uri = UriComponentsBuilder.fromUriString(tasksService)
.path(id)
.build()
.toUri();
try {
return restTemplate.getForObject(uri, Task.class);
} catch (HttpClientErrorException.NotFound e) {
return null;
}
}
}

View File

@@ -0,0 +1,4 @@
package com.baeldung.apiservice.adapters.users;
public record User(String id, String name) {
}

View File

@@ -0,0 +1,31 @@
package com.baeldung.apiservice.adapters.users;
import com.baeldung.apiservice.adapters.users.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
@Repository
public class UserRepository {
@Autowired
private RestTemplate restTemplate;
@Value("${users-service.url}")
private String usersService;
public User getUserById(String id) {
var uri = UriComponentsBuilder.fromUriString(usersService)
.path(id)
.build()
.toUri();
try {
return restTemplate.getForObject(uri, User.class);
} catch (HttpClientErrorException.NotFound e) {
return null;
}
}
}

View File

@@ -0,0 +1,2 @@
users-service.url=http://localhost:8081
tasks-service.url=http://localhost:8082