diff --git a/schools/pom.xml b/schools/pom.xml
index 189d2175..24925535 100644
--- a/schools/pom.xml
+++ b/schools/pom.xml
@@ -36,13 +36,28 @@
com.h2database
h2
-
+
org.springframework.boot
spring-boot-starter-test
test
+
+ io.springfox
+ springfox-bean-validators
+ 2.9.2
+
+
+ io.springfox
+ springfox-spring-web
+ 2.9.2
+
+
+ io.springfox
+ springfox-swagger2
+ 2.9.2
+
@@ -54,4 +69,26 @@
+
+
+
+ io.springfox
+ springfox-swagger2
+ 2.9.2
+
+
+
+
+ io.springfox
+ springfox-swagger-ui
+ 2.9.2
+
+
+
+ io.springfox
+ springfox-bean-validators
+ 2.9.2
+
+
+
diff --git a/schools/src/main/java/com/lambdaschool/schools/config/Swagger2Config.java b/schools/src/main/java/com/lambdaschool/schools/config/Swagger2Config.java
new file mode 100644
index 00000000..c826dc4f
--- /dev/null
+++ b/schools/src/main/java/com/lambdaschool/schools/config/Swagger2Config.java
@@ -0,0 +1,45 @@
+package com.lambdaschool.schools.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@Configuration
+@EnableSwagger2
+@Import(BeanValidatorPluginsConfiguration.class)
+public class Swagger2Config
+{
+ @Bean
+ public Docket api()
+ {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .select()
+ .apis(RequestHandlerSelectors
+ .basePackage("com.lambdaschool.sampleemps"))
+ .paths(PathSelectors.regex("/.*"))
+ .build()
+ .apiInfo(apiEndPointsInfo());
+ }
+
+ private ApiInfo apiEndPointsInfo()
+ {
+ return new ApiInfoBuilder().title("Custom Swagger Documentation Example")
+ .description("Custom Swagger Documentation Example")
+ .contact(new Contact("John Mitchell",
+ "http://www.lambdaschool.com",
+ "john@lambdaschool.com"))
+ .license("MIT")
+ .licenseUrl("https://github.com/LambdaSchool/java-sampleswagger/blob/master/LICENSE")
+ .version("1.0.0")
+ .build();
+ }
+}
diff --git a/schools/src/main/java/com/lambdaschool/schools/controllers/CourseController.java b/schools/src/main/java/com/lambdaschool/schools/controllers/CourseController.java
index d9afc553..2d5a966c 100644
--- a/schools/src/main/java/com/lambdaschool/schools/controllers/CourseController.java
+++ b/schools/src/main/java/com/lambdaschool/schools/controllers/CourseController.java
@@ -1,7 +1,12 @@
package com.lambdaschool.schools.controllers;
import com.lambdaschool.schools.models.Course;
+import com.lambdaschool.schools.models.ErrorDetails;
import com.lambdaschool.schools.services.CoursesService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -21,26 +26,16 @@
import java.net.URISyntaxException;
import java.util.List;
-/**
- * The entry point for clients to work primary with courses
- */
@RestController
@RequestMapping(value = "/courses")
public class CourseController
{
- /**
- * Using the Courses service to process Course data
- */
@Autowired
private CoursesService coursesService;
- /**
- * Returns a list of all courses
- *
Example: http://localhost:2019/courses/courses
- *
- * @return JSON list of all courses with a status of OK
- * @see CoursesService#findAll() CoursesService.findAll()
- */
+ @ApiOperation(value = "returns all Courses",
+ response = Course.class,
+ responseContainer = "List")
@GetMapping(value = "/courses",
produces = {"application/json"})
public ResponseEntity> listAllCourses()
@@ -50,14 +45,13 @@ public ResponseEntity> listAllCourses()
HttpStatus.OK);
}
- /**
- * Returns a single course based off a course id number
- *
Example: http://localhost:2019/courses/course/7
- *
- * @param courseId The primary key of the course you seek
- * @return JSON object of the course you seek
- * @see CoursesService#findCourseById(long) CoursesService.findCourseById(long)
- */
+ @ApiOperation(value = "Retrieve a course based off of the id",
+ response = Course.class)
+ @ApiResponses(value = {@ApiResponse(code = 200,
+ message = "Course Found",
+ response = Course.class), @ApiResponse(code = 404,
+ message = "Course Not Found",
+ response = ErrorDetails.class)})
@GetMapping(value = "/course/{courseId}",
produces = {"application/json"})
public ResponseEntity> getCourseById(
@@ -69,17 +63,6 @@ public ResponseEntity> getCourseById(
HttpStatus.OK);
}
- /**
- * Given a complete Course Object, create a new Course record and student course records.
- *
Example: http://localhost:2019/courses/course
- *
- * @param newcourse A complete new course to add including instructor and students.
- * instructor must already exist.
- * students must already exist.
- * @return A location header with the URI to the newly created course and a status of CREATED
- * @throws URISyntaxException Exception if something does not work in creating the location header
- * @see CoursesService#save(Course) CoursesService.save(Course)
- */
@PostMapping(value = "/course",
consumes = {"application/json"})
public ResponseEntity> addCourse(
@@ -104,17 +87,13 @@ public ResponseEntity> addCourse(
HttpStatus.CREATED);
}
- /**
- * Given a complete Course Object
- * Given the course id, primary key, is in the Course table,
- * replace the Course record, student course combinations.
- *
Example: http://localhost:2019/courses/course/15
- *
- * @param updateCourse A complete Course including all students. Students and Instructor must already exist.
- * @param courseid The primary key of the course you wish to replace.
- * @return status of OK
- * @see CoursesService#save(Course) CoursesService.save(Course)
- */
+ @ApiOperation(value = "updates a course given in the request body",
+ response = Void.class)
+ @ApiResponses(value = {@ApiResponse(code = 200,
+ message = "Course Found",
+ response = Void.class), @ApiResponse(code = 404,
+ message = "Course Not Found",
+ response = ErrorDetails.class)})
@PutMapping(value = "/course/{courseid}",
consumes = {"application/json"})
public ResponseEntity> updateFullCourse(
@@ -130,14 +109,6 @@ public ResponseEntity> updateFullCourse(
return new ResponseEntity<>(HttpStatus.OK);
}
- /**
- * Deletes a given course along with associated student course enrollments
- *
Example: http://localhost:2019/courses/courses/14
- *
- * @param id the primary key of the course you wish to delete
- * @return Status of OK
- * @see CoursesService#delete(long) CoursesService.delete(long)
- */
@DeleteMapping(value = "/course/{id}")
public ResponseEntity> deleteCourseById(
@PathVariable
diff --git a/schools/src/main/java/com/lambdaschool/schools/controllers/StudentController.java b/schools/src/main/java/com/lambdaschool/schools/controllers/StudentController.java
index 3257a667..bb8decb4 100644
--- a/schools/src/main/java/com/lambdaschool/schools/controllers/StudentController.java
+++ b/schools/src/main/java/com/lambdaschool/schools/controllers/StudentController.java
@@ -21,26 +21,13 @@
import java.net.URISyntaxException;
import java.util.List;
-/**
- * The entry point for clients to work primary with student data
- */
@RestController
@RequestMapping(value = "/students")
public class StudentController
{
- /**
- * Using the Student service to process Student data
- */
@Autowired
private StudentService studentService;
- /**
- * Returns a list of all students
- *
Example: http://localhost:2019/students/students
- *
- * @return JSON list of all students with a status of OK
- * @see StudentService#findAll() StudentService.findAll()
- */
@GetMapping(value = "/students",
produces = {"application/json"})
public ResponseEntity> listAllStudents()
@@ -50,14 +37,6 @@ public ResponseEntity> listAllStudents()
HttpStatus.OK);
}
- /**
- * Returns a single user based off a student id number
- *
Example: http://localhost:2019/students/student/7
- *
- * @param studentId The primary key of the student you seek
- * @return JSON object of the student you seek
- * @see StudentService#findStudentById(long) StudentService.findStudentById(long)
- */
@GetMapping(value = "/student/{studentId}",
produces = {"application/json"})
public ResponseEntity> getStudentById(
@@ -69,16 +48,6 @@ public ResponseEntity> getStudentById(
HttpStatus.OK);
}
- /**
- * Given a complete student Object, create a new student record and student course records.
- *
Example: http://localhost:2019/students/student
- *
- * @param newStudent A complete new student to add including enrolled courses.
- * Courses must already exist.
- * @return A location header with the URI to the newly created student and a status of CREATED
- * @throws URISyntaxException Exception if something does not work in creating the location header
- * @see StudentService#save(Student) StudentService.save(User)
- */
@PostMapping(value = "/student",
consumes = {"application/json"})
public ResponseEntity> addStudentUser(
@@ -103,17 +72,6 @@ public ResponseEntity> addStudentUser(
HttpStatus.CREATED);
}
- /**
- * Given a complete student Object
- * Given the student id, primary key, is in the student table,
- * replace the student record, student course combinations.
- *
Example: http://localhost:2019/students/student/15
- *
- * @param updateStudent A complete student including all students. Students and Instructor must already exist.
- * @param studentid The primary key of the student you wish to replace.
- * @return status of OK
- * @see StudentService#save(Student) StudentService.save(Student)
- */
@PutMapping(value = "/student/{studentid}",
consumes = {"application/json"})
public ResponseEntity> updateFullstudent(
@@ -129,14 +87,6 @@ public ResponseEntity> updateFullstudent(
return new ResponseEntity<>(HttpStatus.OK);
}
- /**
- * Deletes a given student along with associated student course enrollments
- *
Example: http://localhost:2019/students/students/14
- *
- * @param id the primary key of the student you wish to delete
- * @return Status of OK
- * @see StudentService#delete(long) StudentService.delete(long)
- */
@DeleteMapping(value = "/student/{id}")
public ResponseEntity> deleteStudentById(
@PathVariable
diff --git a/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java b/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java
new file mode 100644
index 00000000..25a52971
--- /dev/null
+++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/CustomErrorDetails.java
@@ -0,0 +1,41 @@
+//Structure for all messages:
+// title
+// status (Http status)
+// details (human readable message)
+// timestamp
+// developerMessage
+// errors - validation errors
+// fieldname
+// message
+
+package com.lambdaschool.schools.exceptions;
+
+import com.lambdaschool.schools.services.HelperFunctions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.web.servlet.error.DefaultErrorAttributes;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.WebRequest;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Component
+public class CustomErrorDetails extends DefaultErrorAttributes {
+ @Autowired
+ HelperFunctions helperFunctions;
+
+ @Override
+ public Map getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
+ Map errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
+
+ Map errorDetails = new LinkedHashMap<>();
+ errorDetails.put("title", errorAttributes.get("error"));
+ errorDetails.put("status", errorAttributes.get("status"));
+ errorDetails.put("details", errorAttributes.get("message"));
+ errorDetails.put("timestamp", errorAttributes.get("timestamp"));
+ errorDetails.put("developerMessage", "path: " + errorAttributes.get("path"));
+ errorDetails.put("errors", helperFunctions.getConstraintViolations(this.getError(webRequest)));
+
+ return errorDetails;
+ }
+}
diff --git a/schools/src/main/java/com/lambdaschool/schools/exceptions/MissingException.java b/schools/src/main/java/com/lambdaschool/schools/exceptions/MissingException.java
new file mode 100644
index 00000000..b5a69609
--- /dev/null
+++ b/schools/src/main/java/com/lambdaschool/schools/exceptions/MissingException.java
@@ -0,0 +1,7 @@
+package com.lambdaschool.schools.exceptions;
+
+public class MissingException extends RuntimeException {
+ public MissingException(String message) {
+ super("Exception from in School:" + message);
+ }
+}
\ No newline at end of file
diff --git a/schools/src/main/java/com/lambdaschool/schools/handlers/RestException.java b/schools/src/main/java/com/lambdaschool/schools/handlers/RestException.java
new file mode 100644
index 00000000..7de5b33f
--- /dev/null
+++ b/schools/src/main/java/com/lambdaschool/schools/handlers/RestException.java
@@ -0,0 +1,55 @@
+package com.lambdaschool.schools.handlers;
+
+import com.lambdaschool.schools.exceptions.MissingException;
+import com.lambdaschool.schools.models.ErrorDetails;
+import com.lambdaschool.schools.services.HelperFunctions;
+import org.apache.coyote.Response;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+import java.util.Date;
+
+@Order(Ordered.HIGHEST_PRECEDENCE)
+@RestControllerAdvice
+public class RestException extends ResponseEntityExceptionHandler {
+ @Autowired
+ HelperFunctions helperFunctions;
+
+ public RestException() {
+ super();
+ }
+
+ @ExceptionHandler(MissingException.class)
+ public ResponseEntity> handleMissingException(MissingException rnfe) {
+ ErrorDetails errorDetails = new ErrorDetails();
+ errorDetails.setTimestamp(new Date());
+ errorDetails.setStatus(HttpStatus.NOT_FOUND.value());
+ errorDetails.setTitle("Resource Not Found");
+ errorDetails.setDetails(rnfe.getMessage());
+ errorDetails.setDeveloperMessage(rnfe.getClass().getName());
+ errorDetails.setErrors(helperFunctions.getConstraintViolations(rnfe));
+
+ return new ResponseEntity<>(errorDetails, HttpStatus.NOT_FOUND);
+ }
+
+ @Override
+ protected ResponseEntity