Skip to content

Latest commit

 

History

History
 
 

05.Spring-Boot-Advanced

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Spring Boot Advanced

You will be using Spring Boot and get introduced to REST Services.

You will learn about

  • Basics of Auto Configuration and Spring Boot Magic
  • Spring Boot Starter Projects
  • Spring Initializr
  • REST Service Content Negotiation with JSON and XML
  • Embedded servlet containers : Tomcat, Jetty and Undertow
  • Writing Unit and Integration tests using Spring Boot Starter Test
  • Profiles and Dynamic Configuration with Spring Boot
  • Spring Boot Data JPA
  • Spring Boot Actuator
  • Spring Boot Developer Tools and LiveReload

Step List

  • Step 01: Setup and Launch Spring Boot Application with Maven and Eclipse
  • Step 02: Creating your first RestController
  • Step 03: Understanding Spring Boot Magic : Spring Boot Starter Web
  • Step 04: Understanding Spring Boot Magic : Spring Boot Starter Parent
  • Step 05: Spring Boot vs Spring
  • Step 06: Create all Services for Survey and Questions
  • Step 07: What is REST? Creating REST Service with @GetMapping and @PathVariable
  • Step 08: Second REST Service to retrieve a specific question
  • Step 09: Spring Boot Developer Tools and LiveReload : Develop faster!
  • Step 10: Create a REST Service to add a new question to survey : @PostMapping, Postman
  • Step 11: Understand Content Negotiation. Deliver XML Responses from the REST Services
  • Step 12: Spring Initializr : Create Spring Boot Projects on the fly!
  • Step 13: Spring Boot Actuator : Monitor your Spring Boot applications!
  • Step 14: Understanding Embedded servlet containers : Switch to Jetty or Undertow
  • Step 15: Adding Dynamic Configuration to your application : YAML & More..
  • Step 16: Basics of Profiles
  • Step 17: Advanced Application Configuration with Type Safe Configuration Properties
  • Step 18: Spring Boot Starter : Spring Data JPA with CommandLineRunner
  • Step 19: In Memory Database H2 Console and add a new JPA Repository Method
  • Step 20: Spring Boot Starter : Introduction to Spring Data Rest
  • Step 21: Spring Boot Integration Test
  • Step 22: Adding Integration Test for POST Request
  • Step 23: Small Refactoring to organise ourselves
  • Step 24: Writing Unit Tests with Spring Boot and Mockito
  • Step 25: Writing Unit test for createTodo
  • Step 26: Securing our services with Basic Authentication using Spring Security
  • Step 27: Configure Spring Security user roles for survey and other services
  • Step 28: A Deep Dive into Spring Boot Auto Configuration

Complete Code Example

pom.xml

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.in28minutes.springboot</groupId>
  <artifactId>first-springboot-project</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.0.RELEASE</version>
  </parent>

  <properties>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</artifactId>
    </dependency>

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

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>

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

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-devtools</artifactId>
      <optional>true</optional>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-rest-hal-browser</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>

src/main/java/com/in28minutes/springboot/Application.java

package com.in28minutes.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;

@SpringBootApplication
public class Application {

  public static void main(String[] args) {
    ApplicationContext ctx = SpringApplication.run(Application.class, args);

  }

  @Profile("prod")
  @Bean
  public String dummy() {
    return "something";
  }
}

src/main/java/com/in28minutes/springboot/configuration/BasicConfiguration.java

package com.in28minutes.springboot.configuration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("basic")
public class BasicConfiguration {
  private boolean value;
  private String message;
  private int number;

  public boolean isValue() {
    return value;
  }

  public void setValue(boolean value) {
    this.value = value;
  }

  public String getMessage() {
    return message;
  }

  public void setMessage(String message) {
    this.message = message;
  }

  public int getNumber() {
    return number;
  }

  public void setNumber(int number) {
    this.number = number;
  }
}

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<Question> retrieveQuestions(@PathVariable String surveyId) {
    return surveyService.retrieveQuestions(surveyId);
  }

  // GET "/surveys/{surveyId}/questions/{questionId}"
  @GetMapping("/surveys/{surveyId}/questions/{questionId}")
  public Question retrieveDetailsForQuestion(@PathVariable String surveyId,
      @PathVariable String questionId) {
    return surveyService.retrieveQuestion(surveyId, questionId);
  }

  // /surveys/{surveyId}/questions
  @PostMapping("/surveys/{surveyId}/questions")
  public ResponseEntity<Void> addQuestionToSurvey(
      @PathVariable String surveyId, @RequestBody Question newQuestion) {

    Question question = surveyService.addQuestion(surveyId, newQuestion);

    if (question == null)
      return ResponseEntity.noContent().build();

    // Success - URI of the new resource in Response Header
    // Status - created
    // URI -> /surveys/{surveyId}/questions/{questionId}
    // question.getQuestionId()
    URI location = ServletUriComponentsBuilder.fromCurrentRequest().path(
        "/{id}").buildAndExpand(question.getId()).toUri();

    // Status
    return ResponseEntity.created(location).build();
  }

}

src/main/java/com/in28minutes/springboot/jpa/User.java

package com.in28minutes.springboot.jpa;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String name;
  private String role;

  protected User() {
  }

  public User(String name, String role) {
    super();
    this.name = name;
    this.role = role;
  }

  public Long getId() {
    return id;
  }

  public String getName() {
    return name;
  }

  public String getRole() {
    return role;
  }

  @Override
  public String toString() {
    return "User [id=" + id + ", name=" + name + ", role=" + role + "]";
  }

}

src/main/java/com/in28minutes/springboot/jpa/UserCommandLineRunner.java

package com.in28minutes.springboot.jpa;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class UserCommandLineRunner implements CommandLineRunner {

  private static final Logger log = LoggerFactory
      .getLogger(UserCommandLineRunner.class);

  @Autowired
  private UserRepository repository;

  @Override
  public void run(String... args) throws Exception {

    repository.save(new User("Ranga", "Admin"));
    repository.save(new User("Ravi", "User"));
    repository.save(new User("Satish", "Admin"));
    repository.save(new User("Raghu", "User"));

    for (User user : repository.findAll()) {
      log.info(user.toString());
    }

    log.info("Admin users are.....");
    log.info("____________________");
    for (User user : repository.findByRole("Admin")) {
      log.info(user.toString());
    }

  }

}

src/main/java/com/in28minutes/springboot/jpa/UserRepository.java

package com.in28minutes.springboot.jpa;

import java.util.List;

import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, Long> {
  List<User> findByRole(String role);
}

src/main/java/com/in28minutes/springboot/jpa/UserRestRepository.java

package com.in28minutes.springboot.jpa;

import java.util.List;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(path = "users", collectionResourceRel = "users")
public interface UserRestRepository extends
    PagingAndSortingRepository<User, Long> {
  List<User> findByRole(@Param("role") String role);
}

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<String> 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<String> 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<String> 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<Question> questions;

  public Survey(String id, String title, String description,
      List<Question> questions) {
    super();
    this.id = id;
    this.title = title;
    this.description = description;
    this.questions = questions;
  }

  public String getId() {
    return id;
  }

  public void setId(String id) {
    this.id = id;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }

  public String getDescription() {
    return description;
  }

  public void setDescription(String description) {
    this.description = description;
  }

  public List<Question> getQuestions() {
    return questions;
  }

  public void setQuestions(List<Question> questions) {
    this.questions = questions;
  }

  @Override
  public String toString() {
    return "Survey [id=" + id + ", title=" + title + ", description="
        + description + ", questions=" + questions + "]";
  }

}

src/main/java/com/in28minutes/springboot/security/SecurityConfig.java

package com.in28minutes.springboot.security;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  // Authentication : User --> Roles
  protected void configure(AuthenticationManagerBuilder auth)
      throws Exception {
    auth.inMemoryAuthentication().passwordEncoder(org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance()).withUser("user1").password("secret1")
        .roles("USER").and().withUser("admin1").password("secret1")
        .roles("USER", "ADMIN");
  }

  // Authorization : Role -> Access
  // survey -> USER
  protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic().and().authorizeRequests().antMatchers("/surveys/**")
        .hasRole("USER").antMatchers("/users/**").hasRole("USER")
        .antMatchers("/**").hasRole("ADMIN").and().csrf().disable()
        .headers().frameOptions().disable();
  }

}

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<Survey> 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<Question> 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<Survey> retrieveAllSurveys() {
    return surveys;
  }

  public Survey retrieveSurvey(String surveyId) {
    for (Survey survey : surveys) {
      if (survey.getId().equals(surveyId)) {
        return survey;
      }
    }
    return null;
  }

  public List<Question> 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/java/com/in28minutes/springboot/WelcomeController.java

package com.in28minutes.springboot;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.in28minutes.springboot.configuration.BasicConfiguration;

@RestController
public class WelcomeController {

  //Auto wiring
  @Autowired
  private WelcomeService service;

  @Autowired
  private BasicConfiguration configuration;

  @RequestMapping("/welcome")
  public String welcome() {
    return service.retrieveWelcomeMessage();
  }

  @RequestMapping("/dynamic-configuration")
  public Map dynamicConfiguration() {
    Map map = new HashMap();
    map.put("message", configuration.getMessage());
    map.put("number", configuration.getNumber());
    map.put("value", configuration.isValue());

    return map;
  }

}

src/main/java/com/in28minutes/springboot/WelcomeService.java

package com.in28minutes.springboot;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

//Spring to manage this bean and create an instance of this
@Component
public class WelcomeService {

  @Value("${welcome.message}")
  private String welcomeMessage;

  public String retrieveWelcomeMessage() {
    //Complex Method
    return welcomeMessage;
  }
}

src/main/resources/application-dev.properties

logging.level.org.springframework: TRACE

src/main/resources/application-prod.properties

logging.level.org.springframework: INFO

src/main/resources/application.properties

logging.level.org.springframework: DEBUG
app.name=in28Minutes
welcome.message=Welcome message from property file! Welcome to ${app.name}

basic.value=true
basic.message=Welcome to in28minutes
basic.number=200

src/test/java/com/in28minutes/springboot/controller/SurveyControllerIT.java

package com.in28minutes.springboot.controller;

import static org.junit.Assert.assertTrue;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.boot.context.embedded.LocalServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.test.context.junit4.SpringRunner;

import com.in28minutes.springboot.Application;
import com.in28minutes.springboot.model.Question;

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Application.class,
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SurveyControllerIT {

  @LocalServerPort
  private int port;

  TestRestTemplate restTemplate = new TestRestTemplate();

  HttpHeaders headers = new HttpHeaders();

  @Before
  public void before() {
    headers.add("Authorization", createHttpAuthenticationHeaderValue(
        "user1", "secret1"));
    headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
  }

  @Test
  public void testRetrieveSurveyQuestion() {

    HttpEntity<String> entity = new HttpEntity<String>(null, headers);

    ResponseEntity<String> response = restTemplate.exchange(
        createURLWithPort("/surveys/Survey1/questions/Question1"),
        HttpMethod.GET, entity, String.class);

    String expected = "{id:Question1,description:Largest Country in the World,correctAnswer:Russia}";

    JSONAssert.assertEquals(expected, response.getBody(), false);
  }

  @Test
  public void retrieveAllSurveyQuestions() throws Exception {

    ResponseEntity<List<Question>> response = restTemplate.exchange(
        createURLWithPort("/surveys/Survey1/questions"),
        HttpMethod.GET, new HttpEntity<String>("DUMMY_DOESNT_MATTER",
            headers),
        new ParameterizedTypeReference<List<Question>>() {
        });

    Question sampleQuestion = new Question("Question1",
        "Largest Country in the World", "Russia", Arrays.asList(
            "India", "Russia", "United States", "China"));

    assertTrue(response.getBody().contains(sampleQuestion));
  }

  @Test
  public void addQuestion() {

    Question question = new Question("DOESNTMATTER", "Question1", "Russia",
        Arrays.asList("India", "Russia", "United States", "China"));

    HttpEntity entity = new HttpEntity<Question>(question, headers);

    ResponseEntity<String> response = restTemplate.exchange(
        createURLWithPort("/surveys/Survey1/questions"),
        HttpMethod.POST, entity, String.class);

    String actual = response.getHeaders().get(HttpHeaders.LOCATION).get(0);

    assertTrue(actual.contains("/surveys/Survey1/questions/"));

  }

  private String createURLWithPort(final String uri) {
    return "http://localhost:" + port + uri;
  }

  private String createHttpAuthenticationHeaderValue(String userId,
      String password) {

    String auth = userId + ":" + password;

    byte[] encodedAuth = Base64.encode(auth.getBytes(Charset
        .forName("US-ASCII")));

    String headerValue = "Basic " + new String(encodedAuth);

    return headerValue;
  }

}

src/test/java/com/in28minutes/springboot/controller/SurveyControllerTest.java

package com.in28minutes.springboot.controller;

import static org.junit.Assert.assertEquals;

import java.util.Arrays;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.skyscreamer.jsonassert.JSONAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import com.in28minutes.springboot.model.Question;
import com.in28minutes.springboot.service.SurveyService;

@RunWith(SpringRunner.class)
@WebMvcTest(value = SurveyController.class, secure = false)
public class SurveyControllerTest {

  @Autowired
  private MockMvc mockMvc;

  // Mock @Autowired
  @MockBean
  private SurveyService surveyService;

  @Test
  public void retrieveDetailsForQuestion() throws Exception {
    Question mockQuestion = new Question("Question1",
        "Largest Country in the World", "Russia", Arrays.asList(
            "India", "Russia", "United States", "China"));

    Mockito.when(
        surveyService.retrieveQuestion(Mockito.anyString(), Mockito
            .anyString())).thenReturn(mockQuestion);

    RequestBuilder requestBuilder = MockMvcRequestBuilders.get(
        "/surveys/Survey1/questions/Question1").accept(
        MediaType.APPLICATION_JSON);

    MvcResult result = mockMvc.perform(requestBuilder).andReturn();

    String expected = "{id:Question1,description:Largest Country in the World,correctAnswer:Russia}";

    JSONAssert.assertEquals(expected, result.getResponse()
        .getContentAsString(), false);

    // Assert
  }

  @Test
  public void createSurveyQuestion() throws Exception {
    Question mockQuestion = new Question("1", "Smallest Number", "1",
        Arrays.asList("1", "2", "3", "4"));

    String questionJson = "{\"description\":\"Smallest Number\",\"correctAnswer\":\"1\",\"options\":[\"1\",\"2\",\"3\",\"4\"]}";
    //surveyService.addQuestion to respond back with mockQuestion
    Mockito.when(
        surveyService.addQuestion(Mockito.anyString(), Mockito
            .any(Question.class))).thenReturn(mockQuestion);

    //Send question as body to /surveys/Survey1/questions
    RequestBuilder requestBuilder = MockMvcRequestBuilders.post(
        "/surveys/Survey1/questions")
        .accept(MediaType.APPLICATION_JSON).content(questionJson)
        .contentType(MediaType.APPLICATION_JSON);

    MvcResult result = mockMvc.perform(requestBuilder).andReturn();

    MockHttpServletResponse response = result.getResponse();

    assertEquals(HttpStatus.CREATED.value(), response.getStatus());

    assertEquals("http://localhost/surveys/Survey1/questions/1", response
        .getHeader(HttpHeaders.LOCATION));
  }
}