Skip to content

Commit

Permalink
Add find course endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
rgomezcasas committed Dec 23, 2019
1 parent ef008f3 commit 64bdb21
Show file tree
Hide file tree
Showing 15 changed files with 219 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package tv.codely.apps.backoffice.backend.controller.courses;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import tv.codely.backoffice.courses.application.BackofficeCoursesResponse;
import tv.codely.backoffice.courses.application.search_by_criteria.SearchBackofficeCoursesByCriteriaQuery;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.query.QueryBus;
import tv.codely.shared.domain.bus.query.QueryHandlerExecutionError;
Expand Down Expand Up @@ -44,6 +46,11 @@ public List<HashMap<String, String>> index(
}}).collect(Collectors.toList());
}

@Override
protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping() {
return null;
}

private List<HashMap<String, String>> parseFilters(HashMap<String, Serializable> params) {
int maxParams = params.size();

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package tv.codely.apps.backoffice.backend.controller.health_check;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.query.QueryBus;
import tv.codely.shared.infrastructure.spring.ApiController;
Expand All @@ -25,4 +27,9 @@ public HashMap<String, String> index() {

return status;
}

@Override
protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package tv.codely.apps.mooc.backend.controller.courses;

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.RestController;
import tv.codely.mooc.courses.application.CourseResponse;
import tv.codely.mooc.courses.application.find.FindCourseQuery;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.query.QueryBus;
import tv.codely.shared.domain.bus.query.QueryHandlerExecutionError;
import tv.codely.shared.domain.bus.query.QueryNotRegisteredError;
import tv.codely.shared.infrastructure.spring.ApiController;

import java.io.Serializable;
import java.util.HashMap;

@RestController
public final class CourseGetController extends ApiController {
public CourseGetController(
QueryBus queryBus,
CommandBus commandBus
) {
super(queryBus, commandBus);
}

@GetMapping("/courses/{id}")
public ResponseEntity<HashMap<String, Serializable>> index(@PathVariable String id) throws QueryHandlerExecutionError, QueryNotRegisteredError {
CourseResponse course = ask(new FindCourseQuery(id));

return ResponseEntity.ok().body(new HashMap<String, Serializable>() {{
put("id", course.id());
put("name", course.name());
put("duration", course.duration());
}});
}

@Override
protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import tv.codely.mooc.courses.application.create.CreateCourseCommand;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.command.CommandHandlerExecutionError;
import tv.codely.shared.domain.bus.command.CommandNotRegisteredError;
import tv.codely.shared.domain.bus.query.QueryBus;
import tv.codely.shared.infrastructure.spring.ApiController;

import java.util.HashMap;

@RestController
public final class CoursesPutController extends ApiController {
public CoursesPutController(
Expand All @@ -31,6 +34,11 @@ public ResponseEntity<String> index(

return new ResponseEntity<>(HttpStatus.CREATED);
}

@Override
protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping() {
return null;
}
}

final class Request {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package tv.codely.apps.mooc.backend.controller.courses_counter;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import tv.codely.mooc.courses_counter.application.find.CoursesCounterResponse;
import tv.codely.mooc.courses_counter.application.find.FindCoursesCounterQuery;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.query.QueryBus;
import tv.codely.shared.domain.bus.query.QueryHandlerExecutionError;
Expand All @@ -26,4 +28,9 @@ public HashMap<String, Integer> index() throws QueryNotRegisteredError, QueryHan
put("total", response.total());
}};
}

@Override
protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package tv.codely.apps.mooc.backend.controller.health_check;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.query.QueryBus;
import tv.codely.shared.infrastructure.spring.ApiController;
Expand All @@ -25,4 +27,9 @@ public HashMap<String, String> index() {

return status;
}

@Override
protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping() {
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RestController;
import tv.codely.mooc.notifications.application.send_new_courses_newsletter.SendNewCoursesNewsletterCommand;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.command.CommandHandlerExecutionError;
import tv.codely.shared.domain.bus.command.CommandNotRegisteredError;
import tv.codely.shared.domain.bus.query.QueryBus;
import tv.codely.shared.infrastructure.spring.ApiController;

import java.util.HashMap;

@RestController
public final class NewsletterNotificationPutController extends ApiController {
public NewsletterNotificationPutController(
Expand All @@ -29,4 +32,9 @@ public ResponseEntity<String> index(

return new ResponseEntity<>(HttpStatus.CREATED);
}

@Override
protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping() {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package tv.codely.apps.mooc.backend.controller.courses;

import org.junit.jupiter.api.Test;
import tv.codely.apps.mooc.MoocApplicationTestCase;

final class CourseGetControllerShould extends MoocApplicationTestCase {
@Test
void find_an_existing_course() throws Exception {
String id = "99ad55f5-6eab-4d73-b383-c63268e251e8";
String body = "{\"name\": \"The best course\", \"duration\": \"5 hours\"}";

givenThereIsACourse(id, body);

assertResponse(String.format("/courses/%s", id), 200, body);
}

private void givenThereIsACourse(String id, String body) throws Exception {
assertRequestWithBody("PUT", String.format("/courses/%s", id), body, 201);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,16 @@ public CourseResponse(String id, String name, String duration) {
public static CourseResponse fromAggregate(Course course) {
return new CourseResponse(course.id().value(), course.name().value(), course.duration().value());
}

public String id() {
return id;
}

public String name() {
return name;
}

public String duration() {
return duration;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package tv.codely.mooc.courses.application.find;

import tv.codely.mooc.courses.application.CourseResponse;
import tv.codely.mooc.courses.domain.CourseId;
import tv.codely.mooc.courses.domain.CourseNotExist;
import tv.codely.mooc.courses.domain.CourseRepository;
import tv.codely.shared.domain.Service;

@Service
public final class CourseFinder {
private final CourseRepository repository;

public CourseFinder(CourseRepository repository) {
this.repository = repository;
}

public CourseResponse find(CourseId id) throws CourseNotExist {
return repository.search(id)
.map(CourseResponse::fromAggregate)
.orElseThrow(() -> new CourseNotExist(id));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tv.codely.mooc.courses.application.find;

import tv.codely.shared.domain.bus.query.Query;

public final class FindCourseQuery implements Query {
private final String id;

public FindCourseQuery(String id) {
this.id = id;
}

public String id() {
return id;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package tv.codely.mooc.courses.application.find;

import tv.codely.mooc.courses.application.CourseResponse;
import tv.codely.mooc.courses.domain.CourseId;
import tv.codely.mooc.courses.domain.CourseNotExist;
import tv.codely.shared.domain.Service;
import tv.codely.shared.domain.bus.query.QueryHandler;

@Service
public final class FindCourseQueryHandler implements QueryHandler<FindCourseQuery, CourseResponse> {
private final CourseFinder finder;

public FindCourseQueryHandler(CourseFinder finder) {
this.finder = finder;
}

@Override
public CourseResponse handle(FindCourseQuery query) {
try {
return finder.find(new CourseId(query.id()));
} catch (CourseNotExist error) {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tv.codely.mooc.courses.domain;

import tv.codely.shared.domain.DomainError;

public final class CourseNotExist extends DomainError {
public CourseNotExist(CourseId id) {
super("course_not_exist", String.format("The course <%s> doesn't exist", id.value()));
}
}
21 changes: 21 additions & 0 deletions src/shared/main/tv/codely/shared/domain/DomainError.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package tv.codely.shared.domain;

public abstract class DomainError extends Throwable {
private final String errorCode;
private final String errorMessage;

public DomainError(String errorCode, String errorMessage) {
super(errorMessage);

this.errorCode = errorCode;
this.errorMessage = errorMessage;
}

public String getErrorCode() {
return errorCode;
}

public String getErrorMessage() {
return errorMessage;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package tv.codely.shared.infrastructure.spring;

import org.springframework.http.HttpStatus;
import tv.codely.shared.domain.DomainError;
import tv.codely.shared.domain.bus.command.Command;
import tv.codely.shared.domain.bus.command.CommandBus;
import tv.codely.shared.domain.bus.command.CommandHandlerExecutionError;
Expand All @@ -9,8 +11,10 @@
import tv.codely.shared.domain.bus.query.QueryHandlerExecutionError;
import tv.codely.shared.domain.bus.query.QueryNotRegisteredError;

import java.util.HashMap;

public abstract class ApiController {
private final QueryBus queryBus;
private final QueryBus queryBus;
private final CommandBus commandBus;

public ApiController(QueryBus queryBus, CommandBus commandBus) {
Expand All @@ -25,4 +29,6 @@ protected void dispatch(Command command) throws CommandNotRegisteredError, Comma
protected <R> R ask(Query query) throws QueryNotRegisteredError, QueryHandlerExecutionError {
return queryBus.ask(query);
}

abstract protected HashMap<Class<? extends DomainError>, HttpStatus> errorMapping();
}

0 comments on commit 64bdb21

Please sign in to comment.