From 7b45ed5828721459558407775112bec00465efcb Mon Sep 17 00:00:00 2001 From: Ranga Rao Karanam Date: Tue, 3 Jan 2017 21:37:01 +0530 Subject: [PATCH] Step 013 --- Step07.md | 14 +- Step08.md | 7 +- Step09.md | 44 +- Step10.md | 419 ++++++++++++++++ Step10.zip | Bin 0 -> 8770 bytes Step11.md | 456 ++++++++++++++++++ Step12.md | 7 + Step13.md | 22 + pom.xml | 23 + .../controller/SurveyController.java | 22 + 10 files changed, 989 insertions(+), 25 deletions(-) create mode 100644 Step10.md create mode 100644 Step10.zip create mode 100644 Step11.md create mode 100644 Step12.md create mode 100644 Step13.md diff --git a/Step07.md b/Step07.md index 9af8fb7..30e563a 100644 --- a/Step07.md +++ b/Step07.md @@ -1,12 +1,22 @@ ##What You Will Learn during this Step: -- Create a Rest Service +- What is REST? + - Architectural style for the web. REST specifies a set of constraints. + - Client - Server : Server (service provider) should be different from a client (service consumer). + - Enables loose coupling and independent evolution of server and client as new technologies emerge. + - Each service should be stateless. + - Each Resource has a resource identifier. + - It should be possible to cache response. + - Consumer of the service may not have a direct connection to the Service Provider. Response might be sent from a middle layer cache. + - A resource can have multiple representations. Resource can modified through a message in any of the these representations. + +- Create a REST Service - Autowire SurveyService - Create @GetMapping("/surveys/{surveyId}/questions") - Use @PathVariable String surveyId - http://localhost:8080/surveys/Survey1/questions/ - How does the Bean get converted to a JSON? - Auto Configuration : If Jackson jar is on the class path, message converters are auto created! (Search in log :Creating shared instance of singleton bean 'mappingJackson2HttpMessageConverter') - + ## Useful Snippets and References First Snippet ``` diff --git a/Step08.md b/Step08.md index e4221f1..59f965c 100644 --- a/Step08.md +++ b/Step08.md @@ -2,7 +2,12 @@ - Adding the second method to rest service to retrieve a specific question - This will be a very short step - http://localhost:8080/surveys/Survey1/questions/Question1 - +- Different Request Methods + - GET - Retrieve details of a resource + - POST - Create a new resource + - PUT - Update an existing resource + - PATCH - Update part of a resource + - DELETE - Delete a resource ## Useful Snippets and References First Snippet ``` diff --git a/Step09.md b/Step09.md index 54b14d5..1d95b66 100644 --- a/Step09.md +++ b/Step09.md @@ -1,33 +1,25 @@ ##What You Will Learn during this Step: -- Create a REST Service to add a new question to survey - - @PostMapping("/surveys/{surveyId}/questions") - - @RequestBody Question question - - ResponseEntity.created(location).build() - - ResponseEntity.noContent().build() +- I hate the fact that I've to stop and start the server each time. Can somebody save me? + - Yeah. Spring Boot Developer Tools + - By default, any entry on the classpath that points to a folder will be monitored for changes. + - These will not trigger restart - /META-INF/maven, /META-INF/resources ,/resources ,/static ,/public or /templates + - Folders can be configured : spring.devtools.restart.exclude=static/**,public/** + - Additional Paths : spring.devtools.restart.additional-paths + - LiveReload livereload.com + - Technology in progress!! So, expect a few problems! ## Useful Snippets and References First Snippet ``` - @PostMapping("/surveys/{surveyId}/questions") - ResponseEntity add(@PathVariable String surveyId, - @RequestBody Question question) { - - Question createdTodo = surveyService.addQuestion(surveyId, question); - - if (createdTodo == null) { - return ResponseEntity.noContent().build(); - } - - URI location = ServletUriComponentsBuilder.fromCurrentRequest() - .path("/{id}").buildAndExpand(createdTodo.getId()).toUri(); - - return ResponseEntity.created(location).build(); - - } + + org.springframework.boot + spring-boot-devtools + true + ``` ## Exercises -- Create more REST services of your choice +- Make changes and see if they reflect immediately ## Files List ### /pom.xml @@ -52,8 +44,16 @@ First Snippet org.springframework.boot spring-boot-starter-web + + + org.springframework.boot + spring-boot-devtools + true + + + 1.8 diff --git a/Step10.md b/Step10.md new file mode 100644 index 0000000..deb6a59 --- /dev/null +++ b/Step10.md @@ -0,0 +1,419 @@ +##What You Will Learn during this Step: +- Create a REST Service to add a new question to survey + - @PostMapping("/surveys/{surveyId}/questions") + - @RequestBody Question question + - What should be Response Status for create? + - ResponseEntity.created(location).build() + - ResponseEntity.noContent().build() + - Using Postman : https://www.getpostman.com + +## Useful Snippets and References +First Snippet +``` + @PostMapping("/surveys/{surveyId}/questions") + ResponseEntity add(@PathVariable String surveyId, + @RequestBody Question question) { + + Question createdTodo = surveyService.addQuestion(surveyId, question); + + if (createdTodo == null) { + return ResponseEntity.noContent().build(); + } + + URI location = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}").buildAndExpand(createdTodo.getId()).toUri(); + + return ResponseEntity.created(location).build(); + + } +``` +Second Snippet +``` +{"description":"Second Most Populous Country in the World","correctAnswer":"India","options":["India","Russia","United States","China"]} +``` + +## Exercises +- Create more REST services of your choice + +## Files List +### /pom.xml +``` + + 4.0.0 + com.in28minutes + springboot-for-beginners-example + 0.0.1-SNAPSHOT + Your First Spring Boot Example + jar + + + org.springframework.boot + spring-boot-starter-parent + 1.4.0.RELEASE + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-devtools + true + + + + + + + 1.8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + +``` +### /src/main/java/com/in28minutes/springboot/Application.java +``` +package com.in28minutes.springboot; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + ApplicationContext ctx = SpringApplication.run(Application.class, args); + + } + + @RestController + class SomeBean { + + @Autowired + private SomeDependency someDependency; + + @RequestMapping("/") + public String index() { + return someDependency.getSomething(); + } + + } + + @Component + class SomeDependency { + + public String getSomething() { + return "Hello! Welcome!"; + } + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/controller/SurveyController.java +``` +package com.in28minutes.springboot.controller; + +import java.net.URI; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +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.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.service.SurveyService; + +@RestController +class SurveyController { + @Autowired + private SurveyService surveyService; + + @GetMapping("/surveys/{surveyId}/questions") + public List retrieveQuestions(@PathVariable String surveyId) { + return surveyService.retrieveQuestions(surveyId); + } + + @GetMapping(path = "/surveys/{surveyId}/questions/{questionId}") + public Question retrieveQuestion(@PathVariable String surveyId, + @PathVariable String questionId) { + return surveyService.retrieveQuestion(surveyId, questionId); + } + + @PostMapping("/surveys/{surveyId}/questions") + ResponseEntity add(@PathVariable String surveyId, + @RequestBody Question question) { + + Question createdTodo = surveyService.addQuestion(surveyId, question); + + if (createdTodo == null) { + return ResponseEntity.noContent().build(); + } + + URI location = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}").buildAndExpand(createdTodo.getId()).toUri(); + + return ResponseEntity.created(location).build(); + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/model/Question.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Question { + private String id; + private String description; + private String correctAnswer; + private List options; + + // Needed by Caused by: com.fasterxml.jackson.databind.JsonMappingException: + // Can not construct instance of com.in28minutes.springboot.model.Question: + // no suitable constructor found, can not deserialize from Object value + // (missing default constructor or creator, or perhaps need to add/enable + // type information?) + public Question() { + + } + + public Question(String id, String description, String correctAnswer, + List options) { + super(); + this.id = id; + this.description = description; + this.correctAnswer = correctAnswer; + this.options = options; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public String getCorrectAnswer() { + return correctAnswer; + } + + public List getOptions() { + return options; + } + + @Override + public String toString() { + return String + .format("Question [id=%s, description=%s, correctAnswer=%s, options=%s]", + id, description, correctAnswer, options); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (id == null ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Question other = (Question) obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + return true; + } + +} +``` +### /src/main/java/com/in28minutes/springboot/model/Survey.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Survey { + private String id; + private String title; + private String description; + private List questions; + + public Survey(String id, String title, String description, + List questions) { + super(); + this.id = id; + this.title = title; + this.description = description; + this.questions = questions; + } + + public String getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public List getQuestions() { + return questions; + } + + @Override + public String toString() { + return String.format( + "Survey [id=%s, title=%s, description=%s, questions=%s]", id, + title, description, questions); + } + +} +``` +### /src/main/java/com/in28minutes/springboot/service/SurveyService.java +``` +package com.in28minutes.springboot.service; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.model.Survey; + +@Component +public class SurveyService { + private static List surveys = new ArrayList<>(); + static { + Question question1 = new Question("Question1", + "Largest Country in the World", "Russia", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question2 = new Question("Question2", + "Most Populus Country in the World", "China", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question3 = new Question("Question3", + "Highest GDP in the World", "United States", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question4 = new Question("Question4", + "Second largest english speaking country", "India", + Arrays.asList("India", "Russia", "United States", "China")); + + List questions = new ArrayList<>(Arrays.asList(question1, + question2, question3, question4)); + + Survey survey = new Survey("Survey1", "My Favorite Survey", + "Description of the Survey", questions); + + surveys.add(survey); + } + + public List retrieveAllSurveys() { + return surveys; + } + + public Survey retrieveSurvey(String surveyId) { + for (Survey survey : surveys) { + if (survey.getId().equals(surveyId)) { + return survey; + } + } + return null; + } + + public List retrieveQuestions(String surveyId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + return survey.getQuestions(); + } + + public Question retrieveQuestion(String surveyId, String questionId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + for (Question question : survey.getQuestions()) { + if (question.getId().equals(questionId)) { + return question; + } + } + + return null; + } + + private SecureRandom random = new SecureRandom(); + + public Question addQuestion(String surveyId, Question question) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + String randomId = new BigInteger(130, random).toString(32); + question.setId(randomId); + + survey.getQuestions().add(question); + + return question; + } +} +``` +### /src/main/resources/application.properties +``` +logging.level.org.springframework: DEBUG +``` diff --git a/Step10.zip b/Step10.zip new file mode 100644 index 0000000000000000000000000000000000000000..741dc8b0309650740ac33897e2024e84074b7a91 GIT binary patch literal 8770 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 J8(IkD{{UJT_j>>U literal 0 HcmV?d00001 diff --git a/Step11.md b/Step11.md new file mode 100644 index 0000000..c644219 --- /dev/null +++ b/Step11.md @@ -0,0 +1,456 @@ +##What You Will Learn during this Step: +- Understand Content Negotiation + - Accept:application/xml +- http://localhost:8080/surveys/Survey1/questions/ + +## Useful Snippets and References +First Snippet +``` + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + +``` +Second Snippet +``` + + + Question1 + Largest Country in the World + Russia + + India + Russia + United States + China + + + + Question2 + Most Populus Country in the World + China + + India + Russia + United States + China + + + + Question3 + Highest GDP in the World + United States + + India + Russia + United States + China + + + + Question4 + Second largest english speaking country + India + + India + Russia + United States + China + + + +``` + + + +## Exercises +- Execute other services using xml and see what happens! + +## Files List +### /pom.xml +``` + + 4.0.0 + com.in28minutes + springboot-for-beginners-example + 0.0.1-SNAPSHOT + Your First Spring Boot Example + jar + + + org.springframework.boot + spring-boot-starter-parent + 1.4.0.RELEASE + + + + + org.springframework.boot + spring-boot-starter-web + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + + + org.springframework.boot + spring-boot-devtools + true + + + + + + + 1.8 + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + +``` +### /src/main/java/com/in28minutes/springboot/Application.java +``` +package com.in28minutes.springboot; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + ApplicationContext ctx = SpringApplication.run(Application.class, args); + + } + + @RestController + class SomeBean { + + @Autowired + private SomeDependency someDependency; + + @RequestMapping("/") + public String index() { + return someDependency.getSomething(); + } + + } + + @Component + class SomeDependency { + + public String getSomething() { + return "Hello! Welcome!"; + } + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/controller/SurveyController.java +``` +package com.in28minutes.springboot.controller; + +import java.net.URI; +import java.util.List; + +import org.springframework.beans.factory.annotation.Autowired; +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.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.service.SurveyService; + +@RestController +class SurveyController { + @Autowired + private SurveyService surveyService; + + @GetMapping("/surveys/{surveyId}/questions") + public List retrieveQuestions(@PathVariable String surveyId) { + return surveyService.retrieveQuestions(surveyId); + } + + @GetMapping(path = "/surveys/{surveyId}/questions/{questionId}") + public Question retrieveQuestion(@PathVariable String surveyId, + @PathVariable String questionId) { + return surveyService.retrieveQuestion(surveyId, questionId); + } + + @PostMapping("/surveys/{surveyId}/questions") + ResponseEntity add(@PathVariable String surveyId, + @RequestBody Question question) { + + Question createdTodo = surveyService.addQuestion(surveyId, question); + + if (createdTodo == null) { + return ResponseEntity.noContent().build(); + } + + URI location = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}").buildAndExpand(createdTodo.getId()).toUri(); + + return ResponseEntity.created(location).build(); + + } + +} +``` +### /src/main/java/com/in28minutes/springboot/model/Question.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Question { + private String id; + private String description; + private String correctAnswer; + private List options; + + // Needed by Caused by: com.fasterxml.jackson.databind.JsonMappingException: + // Can not construct instance of com.in28minutes.springboot.model.Question: + // no suitable constructor found, can not deserialize from Object value + // (missing default constructor or creator, or perhaps need to add/enable + // type information?) + public Question() { + + } + + public Question(String id, String description, String correctAnswer, + List options) { + super(); + this.id = id; + this.description = description; + this.correctAnswer = correctAnswer; + this.options = options; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDescription() { + return description; + } + + public String getCorrectAnswer() { + return correctAnswer; + } + + public List getOptions() { + return options; + } + + @Override + public String toString() { + return String + .format("Question [id=%s, description=%s, correctAnswer=%s, options=%s]", + id, description, correctAnswer, options); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (id == null ? 0 : id.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Question other = (Question) obj; + if (id == null) { + if (other.id != null) { + return false; + } + } else if (!id.equals(other.id)) { + return false; + } + return true; + } + +} +``` +### /src/main/java/com/in28minutes/springboot/model/Survey.java +``` +package com.in28minutes.springboot.model; + +import java.util.List; + +public class Survey { + private String id; + private String title; + private String description; + private List questions; + + public Survey(String id, String title, String description, + List questions) { + super(); + this.id = id; + this.title = title; + this.description = description; + this.questions = questions; + } + + public String getId() { + return id; + } + + public String getTitle() { + return title; + } + + public String getDescription() { + return description; + } + + public List getQuestions() { + return questions; + } + + @Override + public String toString() { + return String.format( + "Survey [id=%s, title=%s, description=%s, questions=%s]", id, + title, description, questions); + } + +} +``` +### /src/main/java/com/in28minutes/springboot/service/SurveyService.java +``` +package com.in28minutes.springboot.service; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.springframework.stereotype.Component; + +import com.in28minutes.springboot.model.Question; +import com.in28minutes.springboot.model.Survey; + +@Component +public class SurveyService { + private static List surveys = new ArrayList<>(); + static { + Question question1 = new Question("Question1", + "Largest Country in the World", "Russia", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question2 = new Question("Question2", + "Most Populus Country in the World", "China", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question3 = new Question("Question3", + "Highest GDP in the World", "United States", Arrays.asList( + "India", "Russia", "United States", "China")); + Question question4 = new Question("Question4", + "Second largest english speaking country", "India", + Arrays.asList("India", "Russia", "United States", "China")); + + List questions = new ArrayList<>(Arrays.asList(question1, + question2, question3, question4)); + + Survey survey = new Survey("Survey1", "My Favorite Survey", + "Description of the Survey", questions); + + surveys.add(survey); + } + + public List retrieveAllSurveys() { + return surveys; + } + + public Survey retrieveSurvey(String surveyId) { + for (Survey survey : surveys) { + if (survey.getId().equals(surveyId)) { + return survey; + } + } + return null; + } + + public List retrieveQuestions(String surveyId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + return survey.getQuestions(); + } + + public Question retrieveQuestion(String surveyId, String questionId) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + for (Question question : survey.getQuestions()) { + if (question.getId().equals(questionId)) { + return question; + } + } + + return null; + } + + private SecureRandom random = new SecureRandom(); + + public Question addQuestion(String surveyId, Question question) { + Survey survey = retrieveSurvey(surveyId); + + if (survey == null) { + return null; + } + + String randomId = new BigInteger(130, random).toString(32); + question.setId(randomId); + + survey.getQuestions().add(question); + + return question; + } +} +``` +### /src/main/resources/application.properties +``` +logging.level.org.springframework: DEBUG +``` diff --git a/Step12.md b/Step12.md new file mode 100644 index 0000000..360b578 --- /dev/null +++ b/Step12.md @@ -0,0 +1,7 @@ +##What You Will Learn during this Step: +- Spring Initializr +- https://start.spring.io +- Create a few projects! + +## Exercises +- Create more projects with Spring Initializr and play around with it! diff --git a/Step13.md b/Step13.md new file mode 100644 index 0000000..f3366b0 --- /dev/null +++ b/Step13.md @@ -0,0 +1,22 @@ +##What You Will Learn during this Step: +- Spring Boot Actuator + - /env, /metrics, /trace, /dump, /shutdown, /beans, / autoconfig, /configprops, /mappings +- http://localhost:8080/actuator/ +- Execute individual REST Services for each of above + +## Useful Snippets and References +First Snippet +``` + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.data + spring-data-rest-hal-browser + + +``` + +## Files List diff --git a/pom.xml b/pom.xml index ee2ff20..3686c8e 100644 --- a/pom.xml +++ b/pom.xml @@ -18,8 +18,31 @@ org.springframework.boot spring-boot-starter-web + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + + + + org.springframework.boot + spring-boot-starter-actuator + + + + org.springframework.data + spring-data-rest-hal-browser + + + + org.springframework.boot + spring-boot-devtools + true + + + 1.8 diff --git a/src/main/java/com/in28minutes/springboot/controller/SurveyController.java b/src/main/java/com/in28minutes/springboot/controller/SurveyController.java index abb9b05..4c98353 100644 --- a/src/main/java/com/in28minutes/springboot/controller/SurveyController.java +++ b/src/main/java/com/in28minutes/springboot/controller/SurveyController.java @@ -1,11 +1,16 @@ package com.in28minutes.springboot.controller; +import java.net.URI; import java.util.List; import org.springframework.beans.factory.annotation.Autowired; +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.RequestBody; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import com.in28minutes.springboot.model.Question; import com.in28minutes.springboot.service.SurveyService; @@ -26,4 +31,21 @@ public Question retrieveQuestion(@PathVariable String surveyId, return surveyService.retrieveQuestion(surveyId, questionId); } + @PostMapping("/surveys/{surveyId}/questions") + ResponseEntity add(@PathVariable String surveyId, + @RequestBody Question question) { + + Question createdTodo = surveyService.addQuestion(surveyId, question); + + if (createdTodo == null) { + return ResponseEntity.noContent().build(); + } + + URI location = ServletUriComponentsBuilder.fromCurrentRequest() + .path("/{id}").buildAndExpand(createdTodo.getId()).toUri(); + + return ResponseEntity.created(location).build(); + + } + }