Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified .mvn/wrapper/MavenWrapperDownloader.java
100644 → 100755
Empty file.
Empty file modified .mvn/wrapper/maven-wrapper.jar
100644 → 100755
Empty file.
Empty file modified .mvn/wrapper/maven-wrapper.properties
100644 → 100755
Empty file.
1 change: 1 addition & 0 deletions Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: java -jar target/clickbus-0.0.1-SNAPSHOT.jar
6 changes: 6 additions & 0 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Desafio que resolve outro desafio
- Estou participando de um bootcamp do Santander na DIO, e como desafio,
foi proposto o desenvolvimento e publicação de uma API RESTFULL.
- Encontrei o desafio da @Clickbus e achei que seria interessante
entender e melhorar este desafio de código proposto pela empresa.

# Backend Developer Challenge

Esse desafio serve para avaliarmos suas habilidades em construir APIs.
Expand Down
4 changes: 3 additions & 1 deletion docker-compose.yml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ services:
container_name: clickbus_challenge_app
restart: always
image: maven:3.3-jdk-8
build: .
build:
context: ./docker/app/
dockerfile: Dockerfile
working_dir: /app
volumes:
- ./:/app
Expand Down
13 changes: 13 additions & 0 deletions docker/app/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Stage 1: Build the application
FROM maven:3.8.6-jdk-8 as build
WORKDIR /home/app
COPY ../../src /home/app/src
COPY ../../pom.xml /home/app
RUN mvn clean package

# Stage 2: Create the final image
FROM openjdk:8-jre
WORKDIR /home/app
COPY --from=build /home/app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
10 changes: 4 additions & 6 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,13 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.4.0</version>
</dependency>

<dependency>
Expand All @@ -41,15 +43,10 @@
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<optional>true</optional>
</dependency>

Expand Down Expand Up @@ -95,6 +92,7 @@
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
Expand Down
Empty file.
33 changes: 23 additions & 10 deletions src/main/java/br/com/clickbus/challenge/controller/PlaceController.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,24 @@
import br.com.clickbus.challenge.exception.PlaceNotFoundException;
import br.com.clickbus.challenge.service.PlaceService;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;
import java.util.stream.Collectors;

@Api("places")
@RestController
@RequestMapping("places")
public class PlaceController {

private PlaceService service;
private final PlaceService service;

public PlaceController(PlaceService service) {
this.service = service;
}

@PostMapping
public ResponseEntity create(@RequestBody @Valid PlaceDTO dto) {
Expand All @@ -35,7 +34,21 @@ public ResponseEntity create(@RequestBody @Valid PlaceDTO dto) {
public ResponseEntity findById(@PathVariable Long id) {
return service.findById(id)
.map(place -> ResponseEntity.ok(place.convertToDTO()))
.orElseThrow(() -> new PlaceNotFoundException(HttpStatus.NOT_FOUND));
.orElseThrow(() -> new PlaceNotFoundException(HttpStatus.NOT_FOUND.toString()));
}

@GetMapping(name = "findByName", path = "/")
public ResponseEntity<List<PlaceDTO>> findByName(@RequestParam(value = "name") String name) {
List<Place> places = service.findByName(name);

if (places.isEmpty()) {
throw new PlaceNotFoundException("There are no places associated with the given name.");
}

return ResponseEntity.ok(service.findByName(name)
.stream()
.map(Place::convertToDTO)
.collect(Collectors.toList()));
}

@GetMapping
Expand Down
Empty file modified src/main/java/br/com/clickbus/challenge/dto/PlaceDTO.java
100644 → 100755
Empty file.
18 changes: 17 additions & 1 deletion src/main/java/br/com/clickbus/challenge/entity/Place.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class Place {

public Place(String name, String slug, String city, String state) {
this.name = name;
this.slug = slug;
this.slug = Place.slugfy(slug);
this.city = city;
this.state = state;
this.createdAt = LocalDateTime.now();
Expand All @@ -51,7 +51,23 @@ public static Place of(String name, String slug, String city, String state) {
return new Place(name, slug, city, state);
}

private static String slugfy(String slug) {
return slug.toLowerCase()
.replaceAll("[^a-zA-Z0-9\\s+]", "")
.replaceAll("\\s+", "-");
}

public PlaceDTO convertToDTO() {
return PlaceDTO.of(this.name, this.slug, this.city, this.state);
}

public Place alter(PlaceDTO dto) {
this.name = dto.getName();
this.slug = Place.slugfy(dto.getSlug());
this.city = dto.getCity();
this.state = dto.getState();
this.updatedAt = LocalDateTime.now();

return this;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package br.com.clickbus.challenge.exception;

import org.apache.commons.lang3.NotImplementedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
public class GlobalExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(NotImplementedException.class)
public ResponseEntity<ResponseErrorBody> handleNotImplementedException(NotImplementedException notImplementedException) {
String message = notImplementedException.getMessage().isEmpty()
? "Resource not implemented yet."
: notImplementedException.getMessage();
return new ResponseEntity<>(this.responseError(message, HttpStatus.NOT_IMPLEMENTED), HttpStatus.NOT_IMPLEMENTED);
}

@ExceptionHandler(PlaceNotFoundException.class)
public ResponseEntity<ResponseErrorBody> handlePlaceNotFoundException(PlaceNotFoundException placeNotFoundException) {
String message = placeNotFoundException.getMessage().isEmpty()
? "Resource ID not found."
: placeNotFoundException.getMessage();
return new ResponseEntity<>(this.responseError(message, HttpStatus.NOT_FOUND), HttpStatus.NOT_FOUND);
}

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ResponseErrorBody> handleBusinessException(MethodArgumentNotValidException methodArgumentNotValidException) {
String message = methodArgumentNotValidException.getMessage().isEmpty()
? HttpStatus.BAD_REQUEST.toString()
: methodArgumentNotValidException.getMessage();
return new ResponseEntity<>(this.responseError(message, HttpStatus.BAD_REQUEST), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler(Throwable.class)
public ResponseEntity<ResponseErrorBody> handleUnexpectedException(Throwable unexpectedException) {
String message = "Unexpected server error.";
logger.error("", unexpectedException);
return new ResponseEntity<>(this.responseError(message, HttpStatus.INTERNAL_SERVER_ERROR), HttpStatus.INTERNAL_SERVER_ERROR);
}

private ResponseErrorBody responseError(String message, HttpStatus statusCode){
ResponseErrorBody responseError = new ResponseErrorBody();
responseError.setStatus("error");
responseError.setError(message);
responseError.setStatusCode(statusCode.value());
return responseError;
}
}
10 changes: 2 additions & 8 deletions src/main/java/br/com/clickbus/challenge/exception/PlaceNotFoundException.java
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
package br.com.clickbus.challenge.exception;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;


@ResponseStatus(HttpStatus.NOT_FOUND)
public class PlaceNotFoundException extends RuntimeException{

private String message;

public PlaceNotFoundException(HttpStatus status){
super(status.toString());
public PlaceNotFoundException(String message){
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package br.com.clickbus.challenge.exception;

import lombok.Data;

import java.util.Date;

@Data
public class ResponseErrorBody {
private Date timestamp = new Date();
private String status = "error";
private int statusCode = 400;
private String error;
}
Empty file.
19 changes: 10 additions & 9 deletions src/main/java/br/com/clickbus/challenge/service/PlaceService.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,37 @@
import br.com.clickbus.challenge.entity.Place;
import br.com.clickbus.challenge.repository.PlaceRepository;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.NotImplementedException;

@Service
@AllArgsConstructor
public class PlaceService {

private PlaceRepository repository;
@Autowired
private PlaceRepository placeRepository;

public List<Place> findAll() {
throw new NotImplementedException("Metodo nao implementado");
return placeRepository.findAll();
}

public Optional<Place> findById(@NotNull Long id) {
throw new NotImplementedException("Metodo nao implementado");
return placeRepository.findById(id);
}

public Place save(@NotNull Place place) {
throw new NotImplementedException("Metodo nao implementado");
public Place save(Place place) {
return placeRepository.save(place);
}

public List<Place> findByName(@NotNull String name) {
throw new NotImplementedException("Metodo nao implementado");
return placeRepository.findByName(name);
}

public Place alter(@NotNull Place place,@NotNull PlaceDTO placeDTO) {
throw new NotImplementedException("Metodo nao implementado");
public Place alter(@NotNull Place place, @NotNull PlaceDTO placeDTO) {
return placeRepository.save(place.alter(placeDTO));
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.yml
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ spring:
console:
enabled: true
path: /h2
settings:
web-allow-others: true
datasource:
url: jdbc:h2:mem:testdb
username: sa
Expand Down
Empty file.
23 changes: 20 additions & 3 deletions src/test/java/br/com/clickbus/challenge/service/PlaceServiceTest.java
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,13 @@
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.atLeastOnce;
Expand All @@ -45,6 +43,26 @@ void setUp() {
place = Place.of(NAME_PLACE, "bt", "Sao Paulo", "SP");
}

@Test
void whenFindAllNotEmpty() {
when(repository.findAll()).thenReturn(Collections.singletonList(place));

List<Place> places = service.findAll();

assertEquals(1, places.size());
verify(repository, atLeastOnce()).findAll();
}

@Test
void whenFindAllEmpty() {
when(repository.findAll()).thenReturn(Collections.emptyList());

List<Place> places = service.findAll();

assertEquals(0, places.size());
verify(repository, atLeastOnce()).findAll();
}

@Test
void whenFindByIdOk() {
when(repository.findById(1L)).thenReturn(Optional.of(place));
Expand All @@ -60,7 +78,6 @@ void whenFindByIdOk() {
verify(repository, atLeastOnce()).findById(anyLong());
}


@Test
void whenFindByIdThenReturnEmpty() {
when(repository.findById(1L)).thenReturn(Optional.empty());
Expand Down