0

In my Rest API it should be possible to retrieve data which is inside a bounding box. Because the bounding box has four coordinates I want to design the GET requests in such way, that they accept the bounding box as JSON. Therefore I need to be able to send and document JSON strings as URL parameter.

The test itself works, but I can not document these requests with Spring RestDocs (1.0.0.RC1). I reproduced the problem with a simpler method. See below:

  @Test public void ping_username() throws Exception
  {
    String query = "name={\"user\":\"Müller\"}";
    String encodedQuery = URLEncoder.encode(query, "UTF-8");
    mockMvc.perform(get(URI.create("/ping?" + encodedQuery)))
            .andExpect(status().isOk())
            .andDo(document("ping_username"));
  }

When I remove .andDo(document("ping_username")) the test passes.

Stacktrace:

java.lang.IllegalArgumentException: Illegal character in query at index 32: http://localhost:8080/ping?name={"user":"Müller"}
    at java.net.URI.create(URI.java:852)
    at org.springframework.restdocs.mockmvc.MockMvcOperationRequestFactory.createOperationRequest(MockMvcOperationRequestFactory.java:79)
    at org.springframework.restdocs.mockmvc.RestDocumentationResultHandler.handle(RestDocumentationResultHandler.java:93)
    at org.springframework.test.web.servlet.MockMvc$1.andDo(MockMvc.java:158)
    at application.rest.RestApiTest.ping_username(RestApiTest.java:65)

After I received the suggestion to encode the URL I tried it, but the problem remains.

The String which is used to create the URI in my test is now /ping?name%3D%7B%22user%22%3A%22M%C3%BCller%22%7D.

I checked the class MockMvcOperationRequestFactory which appears in the stacktrace, and in line 79 the following code is executed:

URI.create(getRequestUri(mockRequest)
                + (StringUtils.hasText(queryString) ? "?" + queryString : ""))

The problem here is that a not encoded String is used (in my case http://localhost:8080/ping?name={"user":"Müller"}) and the creation of the URI fails.

Remark:

Andy Wilkinson's answer is the solution for the problem. Although I think that David Sinfield is right and JSONs should be avoided in the URL to keep it simple. For my bounding box I will use a comma separated string, as it is used in WMS 1.1: BBOX=x1,y1,x2,y2

gillesB
  • 1,061
  • 1
  • 14
  • 30
  • Your url does not conform to RFC1738. Curly braces are 'unsafe" and need to be url encoded and decoded. – david sinfield Oct 01 '15 at 10:51
  • The encoding is the problem, but apparently there is a bug in Spring Restdocs. See my edit. – gillesB Oct 01 '15 at 12:02
  • 1
    I can't see why the ternary expression would fail. Unless the ? is being url encoded and not found. Is it necessary to make problems for yourself? Can't you use Rest as originally intended with a plain text query string. Why complicate things with a JSON string that is not URL compatible? – david sinfield Oct 01 '15 at 12:52
  • 1
    In the meantime I also think that using JSON strings in the URL is not the best idea. I am quite new to REST and web development and I thought it would be nice to have (JSON) objects around. – gillesB Oct 01 '15 at 13:11

2 Answers2

1

The problem is that URIs have to be encoded as ACII. And ü is not a valid ASCII character, so it must be escaped in the url with % escaping.

If you are using Tomcat, you can use URIEncoding="UTF-8" in the Connector element of the server.xml, to configure UTF-8 escaping as default. If you do this, ü will be automatically converted to %C3%BC, which is the ASCII representation of the \uC3BC Unicode code-point (which represents ü).


Edit: It seems that I have missed the exact point of the error, but it is still the same error. Curly braces are invalid in a URI. Only the following characters are acceptable according to RFC 3986:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~:/?#[]@!$&'()*+,;=%

So these must be escaped too.

meskobalazs
  • 15,741
  • 2
  • 40
  • 63
1

You haven't mentioned the version of Spring REST Docs that you're using, but I would guess that the problem is with URIUtil. I can't tell for certain as I can't see where URIUtil is from.

Anyway, using the JDK's URLEncoder works for me with Spring REST Docs 1.0.0.RC1:

String query = "name={\"user\":\"Müller\"}";
String encodedQuery = URLEncoder.encode(query, "UTF-8");
mockMvc.perform(get(URI.create("/baz?" + encodedQuery)))
        .andExpect(status().isOk())
        .andDo(document("ping_username"));

You can then use URLDecoder.decode on the server side to get the original JSON:

URLDecoder.decode(request.getQueryString(), "UTF-8")
Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242