Add support for generating an HTTP request documentation snippet
Closes gh-13
This commit is contained in:
10
README.md
10
README.md
@@ -279,9 +279,9 @@ command for the request and the resulting response to files in a directory named
|
||||
`index` in the project's `build/generated-snippets/` directory. Three files will
|
||||
be written:
|
||||
|
||||
- `index/request.asciidoc`
|
||||
- `index/response.asciidoc`
|
||||
- `index/request-response.asciidoc`
|
||||
- `index/curl-request.asciidoc`
|
||||
- `index/http-request.asciidoc`
|
||||
- `index/http-response.asciidoc`
|
||||
|
||||
#### Parameterized output directories
|
||||
|
||||
@@ -340,8 +340,8 @@ which the snippets are written. For example, to include both the request and res
|
||||
snippets described above:
|
||||
|
||||
```
|
||||
include::{generated}/index/request.asciidoc[]
|
||||
include::{generated}/index/response.asciidoc[]
|
||||
include::{generated}/index/curl-request.asciidoc[]
|
||||
include::{generated}/index/http-response.asciidoc[]
|
||||
```
|
||||
|
||||
## Generating snippets in your IDE
|
||||
|
||||
@@ -69,7 +69,7 @@ include::{generated}/error-example/response-fields.asciidoc[]
|
||||
For example, a request that attempts to apply a non-existent tag to a note will produce a
|
||||
`400 Bad Request` response:
|
||||
|
||||
include::{generated}/error-example/response.asciidoc[]
|
||||
include::{generated}/error-example/http-response.asciidoc[]
|
||||
|
||||
[[overview-hypermedia]]
|
||||
== Hypermedia
|
||||
@@ -103,7 +103,7 @@ include::{generated}/index-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/index-example/response.asciidoc[]
|
||||
include::{generated}/index-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -132,11 +132,11 @@ include::{generated}/notes-list-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/notes-list-example/request.asciidoc[]
|
||||
include::{generated}/notes-list-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/notes-list-example/response.asciidoc[]
|
||||
include::{generated}/notes-list-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -151,11 +151,11 @@ include::{generated}/notes-create-example/request-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/notes-create-example/request.asciidoc[]
|
||||
include::{generated}/notes-create-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/notes-create-example/response.asciidoc[]
|
||||
include::{generated}/notes-create-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -177,11 +177,11 @@ include::{generated}/tags-list-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tags-list-example/request.asciidoc[]
|
||||
include::{generated}/tags-list-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tags-list-example/response.asciidoc[]
|
||||
include::{generated}/tags-list-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -196,11 +196,11 @@ include::{generated}/tags-create-example/request-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tags-create-example/request.asciidoc[]
|
||||
include::{generated}/tags-create-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tags-create-example/response.asciidoc[]
|
||||
include::{generated}/tags-create-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -229,11 +229,11 @@ include::{generated}/note-get-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/note-get-example/request.asciidoc[]
|
||||
include::{generated}/note-get-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/note-get-example/response.asciidoc[]
|
||||
include::{generated}/note-get-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -250,11 +250,11 @@ To leave an attribute of a note unchanged, any of the above may be omitted from
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/note-update-example/request.asciidoc[]
|
||||
include::{generated}/note-update-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/note-update-example/response.asciidoc[]
|
||||
include::{generated}/note-update-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -283,11 +283,11 @@ include::{generated}/tag-get-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tag-get-example/request.asciidoc[]
|
||||
include::{generated}/tag-get-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tag-get-example/response.asciidoc[]
|
||||
include::{generated}/tag-get-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -302,8 +302,8 @@ include::{generated}/tag-update-example/request-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tag-update-example/request.asciidoc[]
|
||||
include::{generated}/tag-update-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tag-update-example/response.asciidoc[]
|
||||
include::{generated}/tag-update-example/http-response.asciidoc[]
|
||||
|
||||
@@ -42,12 +42,12 @@ $ java -jar build/libs/*.jar
|
||||
You can check that the service is up and running by executing a simple request using
|
||||
cURL:
|
||||
|
||||
include::{generated}/index/1/request.asciidoc[]
|
||||
include::{generated}/index/1/curl-request.asciidoc[]
|
||||
|
||||
This request should yield the following response in the
|
||||
http://stateless.co/hal_specification.html[Hypertext Application Language (HAL)] format:
|
||||
|
||||
include::{generated}/index/1/response.asciidoc[]
|
||||
include::{generated}/index/1/http-response.asciidoc[]
|
||||
|
||||
Note the `_links` in the JSON response. They are key to navigating the API.
|
||||
|
||||
@@ -59,26 +59,26 @@ Now that you've started the service and verified that it works, the next step is
|
||||
it to create a new note. As you saw above, the URI for working with notes is included as
|
||||
a link when you perform a `GET` request against the root of the service:
|
||||
|
||||
include::{generated}/index/1/response.asciidoc[]
|
||||
include::{generated}/index/1/http-response.asciidoc[]
|
||||
|
||||
To create a note, you need to execute a `POST` request to this URI including a JSON
|
||||
payload containing the title and body of the note:
|
||||
|
||||
include::{generated}/creating-a-note/1/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/1/curl-request.asciidoc[]
|
||||
|
||||
The response from this request should have a status code of `201 Created` and contain a
|
||||
`Location` header whose value is the URI of the newly created note:
|
||||
|
||||
include::{generated}/creating-a-note/1/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/1/http-response.asciidoc[]
|
||||
|
||||
To work with the newly created note you use the URI in the `Location` header. For example,
|
||||
you can access the note's details by performing a `GET` request:
|
||||
|
||||
include::{generated}/creating-a-note/2/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/2/curl-request.asciidoc[]
|
||||
|
||||
This request will produce a response with the note's details in its body:
|
||||
|
||||
include::{generated}/creating-a-note/2/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/2/http-response.asciidoc[]
|
||||
|
||||
Note the `tags` link which we'll make use of later.
|
||||
|
||||
@@ -92,26 +92,26 @@ to tag a note, you must first create the tag.
|
||||
Referring back to the response for the service's index, the URI for working with tags is
|
||||
include as a link:
|
||||
|
||||
include::{generated}/index/1/response.asciidoc[]
|
||||
include::{generated}/index/1/http-response.asciidoc[]
|
||||
|
||||
To create a tag you need to execute a `POST` request to this URI, including a JSON
|
||||
payload containing the name of the tag:
|
||||
|
||||
include::{generated}/creating-a-note/3/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/3/curl-request.asciidoc[]
|
||||
|
||||
The response from this request should have a status code of `201 Created` and contain a
|
||||
`Location` header whose value is the URI of the newly created tag:
|
||||
|
||||
include::{generated}/creating-a-note/3/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/3/http-response.asciidoc[]
|
||||
|
||||
To work with the newly created tag you use the URI in the `Location` header. For example
|
||||
you can access the tag's details by performing a `GET` request:
|
||||
|
||||
include::{generated}/creating-a-note/4/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/4/curl-request.asciidoc[]
|
||||
|
||||
This request will produce a response with the tag's details in its body:
|
||||
|
||||
include::{generated}/creating-a-note/4/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/4/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -132,24 +132,25 @@ with it.
|
||||
Once again we execute a `POST` request. However, this time, in an array named tags, we
|
||||
include the URI of the tag we just created:
|
||||
|
||||
include::{generated}/creating-a-note/5/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/5/curl-request.asciidoc[]
|
||||
|
||||
Once again, the response's `Location` header tells us the URI of the newly created note:
|
||||
|
||||
include::{generated}/creating-a-note/5/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/5/http-response.asciidoc[]
|
||||
|
||||
As before, a `GET` request executed against this URI will retrieve the note's details:
|
||||
|
||||
include::{generated}/creating-a-note/6/request-response.asciidoc[]
|
||||
include::{generated}/creating-a-note/6/curl-request.asciidoc[]
|
||||
include::{generated}/creating-a-note/6/http-response.asciidoc[]
|
||||
|
||||
To verify that the tag has been associated with the note, we can perform a `GET` request
|
||||
against the URI from the `tags` link:
|
||||
|
||||
include::{generated}/creating-a-note/7/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/7/curl-request.asciidoc[]
|
||||
|
||||
The response embeds information about the tag that we've just associated with the note:
|
||||
|
||||
include::{generated}/creating-a-note/7/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/7/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -159,17 +160,18 @@ An existing note can be tagged by executing a `PATCH` request against the note's
|
||||
a body that contains the array of tags to be associated with the note. We'll used the
|
||||
URI of the untagged note that we created earlier:
|
||||
|
||||
include::{generated}/creating-a-note/8/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/8/curl-request.asciidoc[]
|
||||
|
||||
This request should produce a `204 No Content` response:
|
||||
|
||||
include::{generated}/creating-a-note/8/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/8/http-response.asciidoc[]
|
||||
|
||||
When we first created this note, we noted the tags link included in its details:
|
||||
|
||||
include::{generated}/creating-a-note/2/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/2/http-response.asciidoc[]
|
||||
|
||||
We can use that link now and execute a `GET` request to see that the note now has a
|
||||
single tag:
|
||||
|
||||
include::{generated}/creating-a-note/9/request-response.asciidoc[]
|
||||
include::{generated}/creating-a-note/9/curl-request.asciidoc[]
|
||||
include::{generated}/creating-a-note/9/http-response.asciidoc[]
|
||||
|
||||
@@ -69,7 +69,7 @@ include::{generated}/error-example/response-fields.asciidoc
|
||||
For example, a request that attempts to apply a non-existent tag to a note will produce a
|
||||
`400 Bad Request` response:
|
||||
|
||||
include::{generated}/error-example/response.asciidoc[]
|
||||
include::{generated}/error-example/http-response.asciidoc[]
|
||||
|
||||
[[overview-hypermedia]]
|
||||
== Hypermedia
|
||||
@@ -103,7 +103,7 @@ include::{generated}/index-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/index-example/response.asciidoc[]
|
||||
include::{generated}/index-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -132,11 +132,11 @@ include::{generated}/notes-list-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/notes-list-example/request.asciidoc[]
|
||||
include::{generated}/notes-list-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/notes-list-example/response.asciidoc[]
|
||||
include::{generated}/notes-list-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -151,11 +151,11 @@ include::{generated}/notes-create-example/request-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/notes-create-example/request.asciidoc[]
|
||||
include::{generated}/notes-create-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/notes-create-example/response.asciidoc[]
|
||||
include::{generated}/notes-create-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -177,11 +177,11 @@ include::{generated}/tags-list-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tags-list-example/request.asciidoc[]
|
||||
include::{generated}/tags-list-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tags-list-example/response.asciidoc[]
|
||||
include::{generated}/tags-list-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -196,11 +196,11 @@ include::{generated}/tags-create-example/request-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tags-create-example/request.asciidoc[]
|
||||
include::{generated}/tags-create-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tags-create-example/response.asciidoc[]
|
||||
include::{generated}/tags-create-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -229,11 +229,11 @@ include::{generated}/note-get-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/note-get-example/request.asciidoc[]
|
||||
include::{generated}/note-get-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/note-get-example/response.asciidoc[]
|
||||
include::{generated}/note-get-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -250,11 +250,11 @@ To leave an attribute of a note unchanged, any of the above may be omitted from
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/note-update-example/request.asciidoc[]
|
||||
include::{generated}/note-update-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/note-update-example/response.asciidoc[]
|
||||
include::{generated}/note-update-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
[[resources-tag]]
|
||||
@@ -282,11 +282,11 @@ include::{generated}/tag-get-example/response-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tag-get-example/request.asciidoc[]
|
||||
include::{generated}/tag-get-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tag-get-example/response.asciidoc[]
|
||||
include::{generated}/tag-get-example/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -301,8 +301,8 @@ include::{generated}/tag-update-example/request-fields.asciidoc[]
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{generated}/tag-update-example/request.asciidoc[]
|
||||
include::{generated}/tag-update-example/curl-request.asciidoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{generated}/tag-update-example/response.asciidoc[]
|
||||
include::{generated}/tag-update-example/http-response.asciidoc[]
|
||||
|
||||
@@ -42,11 +42,11 @@ $ java -jar build/libs/*.jar
|
||||
You can check that the service is up and running by executing a simple request using
|
||||
cURL:
|
||||
|
||||
include::{generated}/index/1/request.asciidoc[]
|
||||
include::{generated}/index/1/curl-request.asciidoc[]
|
||||
|
||||
This request should yield the following response:
|
||||
|
||||
include::{generated}/index/1/response.asciidoc[]
|
||||
include::{generated}/index/1/http-response.asciidoc[]
|
||||
|
||||
Note the `_links` in the JSON response. They are key to navigating the API.
|
||||
|
||||
@@ -58,26 +58,26 @@ Now that you've started the service and verified that it works, the next step is
|
||||
it to create a new note. As you saw above, the URI for working with notes is included as
|
||||
a link when you perform a `GET` request against the root of the service:
|
||||
|
||||
include::{generated}/index/1/response.asciidoc[]
|
||||
include::{generated}/index/1/http-response.asciidoc[]
|
||||
|
||||
To create a note you need to execute a `POST` request to this URI, including a JSON
|
||||
payload containing the title and body of the note:
|
||||
|
||||
include::{generated}/creating-a-note/1/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/1/curl-request.asciidoc[]
|
||||
|
||||
The response from this request should have a status code of `201 Created` and contain a
|
||||
`Location` header whose value is the URI of the newly created note:
|
||||
|
||||
include::{generated}/creating-a-note/1/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/1/http-response.asciidoc[]
|
||||
|
||||
To work with the newly created note you use the URI in the `Location` header. For example
|
||||
you can access the note's details by performing a `GET` request:
|
||||
|
||||
include::{generated}/creating-a-note/2/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/2/curl-request.asciidoc[]
|
||||
|
||||
This request will produce a response with the note's details in its body:
|
||||
|
||||
include::{generated}/creating-a-note/2/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/2/http-response.asciidoc[]
|
||||
|
||||
Note the `note-tags` link which we'll make use of later.
|
||||
|
||||
@@ -91,26 +91,26 @@ to tag a note, you must first create the tag.
|
||||
Referring back to the response for the service's index, the URI for working with tags is
|
||||
include as a link:
|
||||
|
||||
include::{generated}/index/1/response.asciidoc[]
|
||||
include::{generated}/index/1/http-response.asciidoc[]
|
||||
|
||||
To create a tag you need to execute a `POST` request to this URI, including a JSON
|
||||
payload containing the name of the tag:
|
||||
|
||||
include::{generated}/creating-a-note/3/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/3/curl-request.asciidoc[]
|
||||
|
||||
The response from this request should have a status code of `201 Created` and contain a
|
||||
`Location` header whose value is the URI of the newly created tag:
|
||||
|
||||
include::{generated}/creating-a-note/3/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/3/http-response.asciidoc[]
|
||||
|
||||
To work with the newly created tag you use the URI in the `Location` header. For example
|
||||
you can access the tag's details by performing a `GET` request:
|
||||
|
||||
include::{generated}/creating-a-note/4/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/4/curl-request.asciidoc[]
|
||||
|
||||
This request will produce a response with the tag's details in its body:
|
||||
|
||||
include::{generated}/creating-a-note/4/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/4/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -131,24 +131,25 @@ with it.
|
||||
Once again we execute a `POST` request, but this time, in an array named tags, we include
|
||||
the URI of the tag we just created:
|
||||
|
||||
include::{generated}/creating-a-note/5/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/5/curl-request.asciidoc[]
|
||||
|
||||
Once again, the response's `Location` header tells use the URI of the newly created note:
|
||||
|
||||
include::{generated}/creating-a-note/5/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/5/http-response.asciidoc[]
|
||||
|
||||
As before, a `GET` request executed against this URI will retrieve the note's details:
|
||||
|
||||
include::{generated}/creating-a-note/6/request-response.asciidoc[]
|
||||
include::{generated}/creating-a-note/6/curl-request.asciidoc[]
|
||||
include::{generated}/creating-a-note/6/http-response.asciidoc[]
|
||||
|
||||
To see the note's tags, execute a `GET` request against the URI of the note's
|
||||
`note-tags` link:
|
||||
|
||||
include::{generated}/creating-a-note/7/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/7/curl-request.asciidoc[]
|
||||
|
||||
The response shows that, as expected, the note has a single tag:
|
||||
|
||||
include::{generated}/creating-a-note/7/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/7/http-response.asciidoc[]
|
||||
|
||||
|
||||
|
||||
@@ -158,17 +159,18 @@ An existing note can be tagged by executing a `PATCH` request against the note's
|
||||
a body that contains the array of tags to be associated with the note. We'll use the
|
||||
URI of the untagged note that we created earlier:
|
||||
|
||||
include::{generated}/creating-a-note/8/request.asciidoc[]
|
||||
include::{generated}/creating-a-note/8/curl-request.asciidoc[]
|
||||
|
||||
This request should produce a `204 No Content` response:
|
||||
|
||||
include::{generated}/creating-a-note/8/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/8/http-response.asciidoc[]
|
||||
|
||||
When we first created this note, we noted the `note-tags` link included in its details:
|
||||
|
||||
include::{generated}/creating-a-note/2/response.asciidoc[]
|
||||
include::{generated}/creating-a-note/2/http-response.asciidoc[]
|
||||
|
||||
We can use that link now and execute a `GET` request to see that the note now has a
|
||||
single tag:
|
||||
|
||||
include::{generated}/creating-a-note/9/request-response.asciidoc[]
|
||||
include::{generated}/creating-a-note/9/curl-request.asciidoc[]
|
||||
include::{generated}/creating-a-note/9/http-response.asciidoc[]
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
package org.springframework.restdocs;
|
||||
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.documentCurlRequest;
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.documentCurlRequestAndResponse;
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.documentCurlResponse;
|
||||
import static org.springframework.restdocs.http.HttpDocumentation.documentHttpRequest;
|
||||
import static org.springframework.restdocs.http.HttpDocumentation.documentHttpResponse;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.documentLinks;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.documentRequestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.documentResponseFields;
|
||||
@@ -53,8 +53,8 @@ public class RestDocumentationResultHandler implements ResultHandler {
|
||||
|
||||
this.delegates = new ArrayList<ResultHandler>();
|
||||
this.delegates.add(documentCurlRequest(this.outputDir));
|
||||
this.delegates.add(documentCurlResponse(this.outputDir));
|
||||
this.delegates.add(documentCurlRequestAndResponse(this.outputDir));
|
||||
this.delegates.add(documentHttpRequest(this.outputDir));
|
||||
this.delegates.add(documentHttpResponse(this.outputDir));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.springframework.test.web.servlet.request.RequestPostProcessor;
|
||||
import org.springframework.test.web.servlet.setup.ConfigurableMockMvcBuilder;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurer;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcConfigurerAdapter;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
/**
|
||||
@@ -108,8 +109,19 @@ public class RestDocumentationConfigurer extends MockMvcConfigurerAdapter {
|
||||
request.setScheme(RestDocumentationConfigurer.this.scheme);
|
||||
request.setServerPort(RestDocumentationConfigurer.this.port);
|
||||
request.setServerName(RestDocumentationConfigurer.this.host);
|
||||
configureContentLengthHeaderIfAppropriate(request);
|
||||
return request;
|
||||
}
|
||||
|
||||
private void configureContentLengthHeaderIfAppropriate(
|
||||
MockHttpServletRequest request) {
|
||||
long contentLength = request.getContentLengthLong();
|
||||
if (contentLength > 0
|
||||
&& !StringUtils.hasText(request.getHeader("Content-Length"))) {
|
||||
request.addHeader("Content-Length", request.getContentLengthLong());
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.curl;
|
||||
|
||||
/**
|
||||
* Configuration for documenting Curl requests and responses
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class CurlConfiguration {
|
||||
|
||||
private boolean includeResponseHeaders = true;
|
||||
|
||||
boolean isIncludeResponseHeaders() {
|
||||
return this.includeResponseHeaders;
|
||||
}
|
||||
|
||||
void setIncludeResponseHeaders(boolean includeResponseHeaders) {
|
||||
this.includeResponseHeaders = includeResponseHeaders;
|
||||
}
|
||||
}
|
||||
@@ -16,29 +16,21 @@
|
||||
|
||||
package org.springframework.restdocs.curl;
|
||||
|
||||
import static org.springframework.restdocs.util.IterableEnumeration.iterable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.restdocs.snippet.DocumentationWriter;
|
||||
import org.springframework.restdocs.snippet.DocumentationWriter.DocumentationAction;
|
||||
import org.springframework.restdocs.snippet.SnippetWritingResultHandler;
|
||||
import org.springframework.restdocs.util.DocumentableHttpServletRequest;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* Static factory methods for documenting a RESTful API as if it were being driven using
|
||||
* the cURL command-line utility.
|
||||
*
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Yann Le Guern
|
||||
*/
|
||||
@@ -50,58 +42,17 @@ public abstract class CurlDocumentation {
|
||||
|
||||
/**
|
||||
* Produces a documentation snippet containing the request formatted as a cURL command
|
||||
*
|
||||
*
|
||||
* @param outputDir The directory to which snippet should be written
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static CurlSnippetResultHandler documentCurlRequest(String outputDir) {
|
||||
return new CurlSnippetResultHandler(outputDir, "request") {
|
||||
public static SnippetWritingResultHandler documentCurlRequest(String outputDir) {
|
||||
return new SnippetWritingResultHandler(outputDir, "curl-request") {
|
||||
|
||||
@Override
|
||||
public void handle(MvcResult result, DocumentationWriter writer)
|
||||
throws IOException {
|
||||
writer.shellCommand(new CurlRequestDocumentationAction(writer, result,
|
||||
getCurlConfiguration()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a documentation snippet containing the response formatted as the response
|
||||
* to a cURL command
|
||||
*
|
||||
* @param outputDir The directory to which snippet should be written
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static CurlSnippetResultHandler documentCurlResponse(String outputDir) {
|
||||
return new CurlSnippetResultHandler(outputDir, "response") {
|
||||
|
||||
@Override
|
||||
public void handle(MvcResult result, DocumentationWriter writer)
|
||||
throws IOException {
|
||||
writer.codeBlock("http", new CurlResponseDocumentationAction(writer,
|
||||
result, getCurlConfiguration()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a documentation snippet containing both the request formatted as a cURL
|
||||
* command and the response formatted formatted s the response to a cURL command.
|
||||
*
|
||||
* @param outputDir The directory to which the snippet should be written
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static CurlSnippetResultHandler documentCurlRequestAndResponse(String outputDir) {
|
||||
return new CurlSnippetResultHandler(outputDir, "request-response") {
|
||||
|
||||
@Override
|
||||
public void handle(MvcResult result, DocumentationWriter writer)
|
||||
throws IOException {
|
||||
writer.shellCommand(new CurlRequestDocumentationAction(writer, result,
|
||||
getCurlConfiguration()));
|
||||
writer.codeBlock("http", new CurlResponseDocumentationAction(writer,
|
||||
result, getCurlConfiguration()));
|
||||
writer.shellCommand(new CurlRequestDocumentationAction(writer, result));
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -121,152 +72,55 @@ public abstract class CurlDocumentation {
|
||||
|
||||
private final MvcResult result;
|
||||
|
||||
private final CurlConfiguration curlConfiguration;
|
||||
|
||||
CurlRequestDocumentationAction(DocumentationWriter writer, MvcResult result,
|
||||
CurlConfiguration curlConfiguration) {
|
||||
CurlRequestDocumentationAction(DocumentationWriter writer, MvcResult result) {
|
||||
this.writer = writer;
|
||||
this.result = result;
|
||||
this.curlConfiguration = curlConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() throws IOException {
|
||||
MockHttpServletRequest request = this.result.getRequest();
|
||||
DocumentableHttpServletRequest request = new DocumentableHttpServletRequest(
|
||||
this.result.getRequest());
|
||||
this.writer.print(String.format("curl %s://%s", request.getScheme(),
|
||||
request.getServerName()));
|
||||
request.getHost()));
|
||||
|
||||
if (isNonStandardPort(request)) {
|
||||
this.writer.print(String.format(":%d", request.getServerPort()));
|
||||
this.writer.print(String.format(":%d", request.getPort()));
|
||||
}
|
||||
|
||||
this.writer.print(getRequestUriWithQueryString(request));
|
||||
this.writer.print(request.getRequestUriWithQueryString().replace("&", "\\&"));
|
||||
|
||||
if (this.curlConfiguration.isIncludeResponseHeaders()) {
|
||||
this.writer.print(" -i");
|
||||
}
|
||||
this.writer.print(" -i");
|
||||
|
||||
if (!isGetRequest(request)) {
|
||||
if (!request.isGetRequest()) {
|
||||
this.writer.print(String.format(" -X %s", request.getMethod()));
|
||||
}
|
||||
|
||||
for (String headerName : iterable(request.getHeaderNames())) {
|
||||
for (String header : iterable(request.getHeaders(headerName))) {
|
||||
this.writer
|
||||
.print(String.format(" -H \"%s: %s\"", headerName, header));
|
||||
for (Entry<String, List<String>> entry : request.getHeaders().entrySet()) {
|
||||
for (String header : entry.getValue()) {
|
||||
this.writer.print(String.format(" -H \"%s: %s\"", entry.getKey(),
|
||||
header));
|
||||
}
|
||||
}
|
||||
|
||||
if (request.getContentLengthLong() > 0) {
|
||||
this.writer.print(String.format(" -d '%s'", getContent(request)));
|
||||
if (request.getContentLength() > 0) {
|
||||
this.writer
|
||||
.print(String.format(" -d '%s'", request.getContentAsString()));
|
||||
}
|
||||
else if (isPostRequest(request)) {
|
||||
Map<String, String[]> parameters = request.getParameterMap();
|
||||
if (!parameters.isEmpty()) {
|
||||
this.writer.print(String
|
||||
.format(" -d '%s'", toQueryString(parameters)));
|
||||
else if (request.isPostRequest()) {
|
||||
String queryString = request.getParameterMapAsQueryString();
|
||||
if (StringUtils.hasText(queryString)) {
|
||||
this.writer.print(String.format(" -d '%s'",
|
||||
queryString.replace("&", "\\&")));
|
||||
}
|
||||
}
|
||||
|
||||
this.writer.println();
|
||||
}
|
||||
|
||||
private boolean isGetRequest(HttpServletRequest request) {
|
||||
return RequestMethod.GET == RequestMethod.valueOf(request.getMethod());
|
||||
}
|
||||
|
||||
private boolean isPostRequest(HttpServletRequest request) {
|
||||
return RequestMethod.POST == RequestMethod.valueOf(request.getMethod());
|
||||
}
|
||||
|
||||
private boolean isNonStandardPort(HttpServletRequest request) {
|
||||
return (SCHEME_HTTP.equals(request.getScheme()) && request.getServerPort() != STANDARD_PORT_HTTP)
|
||||
|| (SCHEME_HTTPS.equals(request.getScheme()) && request
|
||||
.getServerPort() != STANDARD_PORT_HTTPS);
|
||||
}
|
||||
|
||||
private String getRequestUriWithQueryString(HttpServletRequest request) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(request.getRequestURI());
|
||||
String queryString = getQueryString(request);
|
||||
if (StringUtils.hasText(queryString)) {
|
||||
sb.append('?').append(queryString);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String getQueryString(HttpServletRequest request) {
|
||||
if (request.getQueryString() != null) {
|
||||
return request.getQueryString().replace("&", "\\&");
|
||||
}
|
||||
if (isGetRequest(request)) {
|
||||
return toQueryString(request.getParameterMap());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String toQueryString(Map<String, String[]> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String[]> entry : map.entrySet()) {
|
||||
for (String value : entry.getValue()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("\\&");
|
||||
}
|
||||
sb.append(urlEncodeUTF8(entry.getKey())).append('=')
|
||||
.append(urlEncodeUTF8(value));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String urlEncodeUTF8(String s) {
|
||||
try {
|
||||
return URLEncoder.encode(s, "UTF-8");
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
throw new IllegalStateException("Unable to URL encode " + s
|
||||
+ " using UTF-8", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private String getContent(MockHttpServletRequest request) throws IOException {
|
||||
StringWriter bodyWriter = new StringWriter();
|
||||
FileCopyUtils.copy(request.getReader(), bodyWriter);
|
||||
return bodyWriter.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CurlResponseDocumentationAction implements
|
||||
DocumentationAction {
|
||||
|
||||
private final DocumentationWriter writer;
|
||||
|
||||
private final MvcResult result;
|
||||
|
||||
private final CurlConfiguration curlConfiguration;
|
||||
|
||||
CurlResponseDocumentationAction(DocumentationWriter writer, MvcResult result,
|
||||
CurlConfiguration curlConfiguration) {
|
||||
this.writer = writer;
|
||||
this.result = result;
|
||||
this.curlConfiguration = curlConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() throws IOException {
|
||||
if (this.curlConfiguration.isIncludeResponseHeaders()) {
|
||||
HttpStatus status = HttpStatus.valueOf(this.result.getResponse()
|
||||
.getStatus());
|
||||
this.writer.println(String.format("HTTP/1.1 %d %s", status.value(),
|
||||
status.getReasonPhrase()));
|
||||
for (String headerName : this.result.getResponse().getHeaderNames()) {
|
||||
for (String header : this.result.getResponse().getHeaders(headerName)) {
|
||||
this.writer.println(String.format("%s: %s", headerName, header));
|
||||
}
|
||||
}
|
||||
this.writer.println();
|
||||
}
|
||||
this.writer.println(this.result.getResponse().getContentAsString());
|
||||
private boolean isNonStandardPort(DocumentableHttpServletRequest request) {
|
||||
return (SCHEME_HTTP.equals(request.getScheme()) && request.getPort() != STANDARD_PORT_HTTP)
|
||||
|| (SCHEME_HTTPS.equals(request.getScheme()) && request.getPort() != STANDARD_PORT_HTTPS);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.curl;
|
||||
|
||||
import org.springframework.restdocs.snippet.SnippetWritingResultHandler;
|
||||
import org.springframework.test.web.servlet.ResultHandler;
|
||||
|
||||
/**
|
||||
* Abstract base class for Spring Mock MVC {@link ResultHandler ResultHandlers} that
|
||||
* produce documentation snippets relating to cURL.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public abstract class CurlSnippetResultHandler extends SnippetWritingResultHandler {
|
||||
|
||||
private final CurlConfiguration curlConfiguration = new CurlConfiguration();
|
||||
|
||||
public CurlSnippetResultHandler(String outputDir, String fileName) {
|
||||
super(outputDir, fileName);
|
||||
}
|
||||
|
||||
CurlConfiguration getCurlConfiguration() {
|
||||
return this.curlConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether or not the generated cURL snippets should have contents as if cURL
|
||||
* had been invoked with {@code -i, --include}.
|
||||
*
|
||||
* @param include {@code true} to use {@code -i, --include}, otherwise false
|
||||
* @return {@code this}
|
||||
*/
|
||||
public CurlSnippetResultHandler includeResponseHeaders(boolean include) {
|
||||
this.curlConfiguration.setIncludeResponseHeaders(include);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.http;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.restdocs.snippet.DocumentationWriter;
|
||||
import org.springframework.restdocs.snippet.DocumentationWriter.DocumentationAction;
|
||||
import org.springframework.restdocs.snippet.SnippetWritingResultHandler;
|
||||
import org.springframework.restdocs.util.DocumentableHttpServletRequest;
|
||||
import org.springframework.test.web.servlet.MvcResult;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Static factory methods for documenting a RESTful API's HTTP requests.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public abstract class HttpDocumentation {
|
||||
|
||||
private HttpDocumentation() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a documentation snippet containing the request formatted as an HTTP
|
||||
* request
|
||||
*
|
||||
* @param outputDir The directory to which snippet should be written
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static SnippetWritingResultHandler documentHttpRequest(String outputDir) {
|
||||
return new SnippetWritingResultHandler(outputDir, "http-request") {
|
||||
|
||||
@Override
|
||||
public void handle(MvcResult result, DocumentationWriter writer)
|
||||
throws IOException {
|
||||
writer.codeBlock("http", new HttpRequestDocumentationAction(writer,
|
||||
result));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Produces a documentation snippet containing the response formatted as the HTTP
|
||||
* response sent by the server
|
||||
*
|
||||
* @param outputDir The directory to which snippet should be written
|
||||
* @return the handler that will produce the snippet
|
||||
*/
|
||||
public static SnippetWritingResultHandler documentHttpResponse(String outputDir) {
|
||||
return new SnippetWritingResultHandler(outputDir, "http-response") {
|
||||
|
||||
@Override
|
||||
public void handle(MvcResult result, DocumentationWriter writer)
|
||||
throws IOException {
|
||||
writer.codeBlock("http", new HttpResponseDocumentationAction(writer,
|
||||
result));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static class HttpRequestDocumentationAction implements DocumentationAction {
|
||||
|
||||
private final DocumentationWriter writer;
|
||||
|
||||
private final MvcResult result;
|
||||
|
||||
HttpRequestDocumentationAction(DocumentationWriter writer, MvcResult result) {
|
||||
this.writer = writer;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() throws IOException {
|
||||
DocumentableHttpServletRequest request = new DocumentableHttpServletRequest(
|
||||
this.result.getRequest());
|
||||
this.writer.printf("%s %s HTTP/1.1%n", request.getMethod(),
|
||||
request.getRequestUriWithQueryString());
|
||||
for (Entry<String, List<String>> header : request.getHeaders().entrySet()) {
|
||||
for (String value : header.getValue()) {
|
||||
this.writer.printf("%s: %s%n", header.getKey(), value);
|
||||
}
|
||||
}
|
||||
if (requiresFormEncodingContentType(request)) {
|
||||
this.writer.printf("%s: %s%n", HttpHeaders.CONTENT_TYPE,
|
||||
MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||
}
|
||||
this.writer.println();
|
||||
if (request.getContentLength() > 0) {
|
||||
this.writer.println(request.getContentAsString());
|
||||
}
|
||||
else if (request.isPostRequest()) {
|
||||
String queryString = request.getParameterMapAsQueryString();
|
||||
if (StringUtils.hasText(queryString)) {
|
||||
this.writer.println(queryString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean requiresFormEncodingContentType(
|
||||
DocumentableHttpServletRequest request) {
|
||||
return request.getHeaders().get(HttpHeaders.CONTENT_TYPE) == null
|
||||
&& request.isPostRequest()
|
||||
&& StringUtils.hasText(request.getParameterMapAsQueryString());
|
||||
}
|
||||
}
|
||||
|
||||
private static final class HttpResponseDocumentationAction implements
|
||||
DocumentationAction {
|
||||
|
||||
private final DocumentationWriter writer;
|
||||
|
||||
private final MvcResult result;
|
||||
|
||||
HttpResponseDocumentationAction(DocumentationWriter writer, MvcResult result) {
|
||||
this.writer = writer;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void perform() throws IOException {
|
||||
HttpStatus status = HttpStatus.valueOf(this.result.getResponse().getStatus());
|
||||
this.writer.println(String.format("HTTP/1.1 %d %s", status.value(),
|
||||
status.getReasonPhrase()));
|
||||
for (String headerName : this.result.getResponse().getHeaderNames()) {
|
||||
for (String header : this.result.getResponse().getHeaders(headerName)) {
|
||||
this.writer.println(String.format("%s: %s", headerName, header));
|
||||
}
|
||||
}
|
||||
this.writer.println();
|
||||
this.writer.println(this.result.getResponse().getContentAsString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.util;
|
||||
|
||||
import static org.springframework.restdocs.util.IterableEnumeration.iterable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.util.FileCopyUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
/**
|
||||
* An {@link HttpServletRequest} wrapper that provides a limited set of methods intended
|
||||
* to help in the documentation of the request.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*
|
||||
*/
|
||||
public class DocumentableHttpServletRequest {
|
||||
|
||||
private final MockHttpServletRequest delegate;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DocumentableHttpServletRequest} to document the given
|
||||
* {@code request}.
|
||||
*
|
||||
* @param request the request that is to be documented
|
||||
*/
|
||||
public DocumentableHttpServletRequest(MockHttpServletRequest request) {
|
||||
this.delegate = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this request is a {@code GET} request.
|
||||
*
|
||||
* @return {@code true} if it is a {@code GET} request, otherwise {@code false}
|
||||
* @see HttpServletRequest#getMethod()
|
||||
*/
|
||||
public boolean isGetRequest() {
|
||||
return RequestMethod.GET == RequestMethod.valueOf(this.delegate.getMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this request is a {@code POST} request.
|
||||
*
|
||||
* @return {@code true} if it is a {@code POST} request, otherwise {@code false}
|
||||
* @see HttpServletRequest#getMethod()
|
||||
*/
|
||||
public boolean isPostRequest() {
|
||||
return RequestMethod.POST == RequestMethod.valueOf(this.delegate.getMethod());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Map of the request's headers. The entries are ordered based on the
|
||||
* ordering of {@link HttpServletRequest#getHeaderNames()} and
|
||||
* {@link HttpServletRequest#getHeaders(String)}.
|
||||
*
|
||||
* @return the request's headers, keyed by name
|
||||
* @see HttpServletRequest#getHeaderNames()
|
||||
* @see HttpServletRequest#getHeaders(String)
|
||||
*/
|
||||
public Map<String, List<String>> getHeaders() {
|
||||
Map<String, List<String>> headersByName = new LinkedHashMap<String, List<String>>();
|
||||
for (String headerName : iterable(this.delegate.getHeaderNames())) {
|
||||
List<String> headers = new ArrayList<String>();
|
||||
headersByName.put(headerName, headers);
|
||||
for (String header : iterable(this.delegate.getHeaders(headerName))) {
|
||||
headers.add(header);
|
||||
}
|
||||
}
|
||||
return headersByName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request's scheme.
|
||||
*
|
||||
* @return the request's scheme
|
||||
* @see HttpServletRequest#getScheme()
|
||||
*/
|
||||
public String getScheme() {
|
||||
return this.delegate.getScheme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the host to which the request was sent.
|
||||
*
|
||||
* @return the host's name
|
||||
* @see HttpServletRequest#getServerName()
|
||||
*/
|
||||
public String getHost() {
|
||||
return this.delegate.getServerName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port to which the request was sent.
|
||||
*
|
||||
* @return the port
|
||||
* @see HttpServletRequest#getServerPort()
|
||||
*/
|
||||
public int getPort() {
|
||||
return this.delegate.getServerPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request's method.
|
||||
*
|
||||
* @return the request's method
|
||||
* @see HttpServletRequest#getMethod()
|
||||
*/
|
||||
public String getMethod() {
|
||||
return this.delegate.getMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the request's content
|
||||
*
|
||||
* @return the content length
|
||||
* @see HttpServletRequest#getContentLength()
|
||||
*/
|
||||
public long getContentLength() {
|
||||
return this.delegate.getContentLengthLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code String} of the request's content
|
||||
*
|
||||
* @return the request's content
|
||||
* @throws IOException if the content cannot be read
|
||||
*/
|
||||
public String getContentAsString() throws IOException {
|
||||
StringWriter bodyWriter = new StringWriter();
|
||||
FileCopyUtils.copy(this.delegate.getReader(), bodyWriter);
|
||||
return bodyWriter.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request's URI including its query string. The query string is
|
||||
* determined by calling {@link HttpServletRequest#getQueryString()}. If it's
|
||||
* {@code null} and it is a {@code GET} request, the query string is then constructed
|
||||
* from the request's {@link HttpServletRequest#getParameterMap()} parameter map.
|
||||
*
|
||||
* @return the URI of the request, including its query string
|
||||
*/
|
||||
public String getRequestUriWithQueryString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(this.delegate.getRequestURI());
|
||||
String queryString = getQueryString();
|
||||
if (StringUtils.hasText(queryString)) {
|
||||
sb.append('?').append(queryString);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the request's parameter map formatted as a query string
|
||||
*
|
||||
* @return The query string derived from the request's parameter map
|
||||
* @see HttpServletRequest#getParameterMap()
|
||||
*/
|
||||
public String getParameterMapAsQueryString() {
|
||||
return toQueryString(this.delegate.getParameterMap());
|
||||
}
|
||||
|
||||
private String getQueryString() {
|
||||
if (this.delegate.getQueryString() != null) {
|
||||
return this.delegate.getQueryString();
|
||||
}
|
||||
if (isGetRequest()) {
|
||||
return getParameterMapAsQueryString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String toQueryString(Map<String, String[]> map) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Map.Entry<String, String[]> entry : map.entrySet()) {
|
||||
for (String value : entry.getValue()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append("&");
|
||||
}
|
||||
sb.append(urlEncodeUTF8(entry.getKey())).append('=')
|
||||
.append(urlEncodeUTF8(value));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String urlEncodeUTF8(String s) {
|
||||
try {
|
||||
return URLEncoder.encode(s, "UTF-8");
|
||||
}
|
||||
catch (UnsupportedEncodingException ex) {
|
||||
throw new IllegalStateException("Unable to URL encode " + s + " using UTF-8",
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -84,7 +84,8 @@ public class RestDocumentationIntegrationTests {
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON))
|
||||
.andExpect(status().isOk()).andDo(document("basic"));
|
||||
assertExpectedSnippetFilesExist(new File("build/generated-snippets/basic"),
|
||||
"request.asciidoc", "response.asciidoc", "request-response.asciidoc");
|
||||
"http-request.asciidoc", "http-response.asciidoc",
|
||||
"curl-request.asciidoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -96,7 +97,8 @@ public class RestDocumentationIntegrationTests {
|
||||
.andExpect(status().isOk()).andDo(document("{method-name}"));
|
||||
assertExpectedSnippetFilesExist(new File(
|
||||
"build/generated-snippets/parameterized-output-directory"),
|
||||
"request.asciidoc", "response.asciidoc", "request-response.asciidoc");
|
||||
"http-request.asciidoc", "http-response.asciidoc",
|
||||
"curl-request.asciidoc");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -108,20 +110,23 @@ public class RestDocumentationIntegrationTests {
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
|
||||
status().isOk());
|
||||
assertExpectedSnippetFilesExist(
|
||||
new File("build/generated-snippets/multi-step-1/"), "request.asciidoc",
|
||||
"response.asciidoc", "request-response.asciidoc");
|
||||
new File("build/generated-snippets/multi-step-1/"),
|
||||
"http-request.asciidoc", "http-response.asciidoc",
|
||||
"curl-request.asciidoc");
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
|
||||
status().isOk());
|
||||
assertExpectedSnippetFilesExist(
|
||||
new File("build/generated-snippets/multi-step-2/"), "request.asciidoc",
|
||||
"response.asciidoc", "request-response.asciidoc");
|
||||
new File("build/generated-snippets/multi-step-2/"),
|
||||
"http-request.asciidoc", "http-response.asciidoc",
|
||||
"curl-request.asciidoc");
|
||||
|
||||
mockMvc.perform(get("/").accept(MediaType.APPLICATION_JSON)).andExpect(
|
||||
status().isOk());
|
||||
assertExpectedSnippetFilesExist(
|
||||
new File("build/generated-snippets/multi-step-3/"), "request.asciidoc",
|
||||
"response.asciidoc", "request-response.asciidoc");
|
||||
new File("build/generated-snippets/multi-step-3/"),
|
||||
"http-request.asciidoc", "http-response.asciidoc",
|
||||
"curl-request.asciidoc");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
package org.springframework.restdocs.config;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.nullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
@@ -72,6 +76,25 @@ public class RestDocumentationConfigurerTests {
|
||||
assertUriConfiguration("http", "localhost", 8081);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noContentLengthHeaderWhenRequestHasNotContent() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationConfigurer().withPort(
|
||||
8081).beforeMockMvcCreated(null, null);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
assertThat(this.request.getHeader("Content-Length"), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contentLengthHeaderIsSetWhenRequestHasContent() {
|
||||
RequestPostProcessor postProcessor = new RestDocumentationConfigurer().withPort(
|
||||
8081).beforeMockMvcCreated(null, null);
|
||||
byte[] content = "Hello, world".getBytes();
|
||||
this.request.setContent(content);
|
||||
postProcessor.postProcessRequest(this.request);
|
||||
assertThat(this.request.getHeader("Content-Length"),
|
||||
is(equalTo(Integer.toString(content.length))));
|
||||
}
|
||||
|
||||
private void assertUriConfiguration(String scheme, String host, int port) {
|
||||
assertEquals(scheme, this.request.getScheme());
|
||||
assertEquals(host, this.request.getServerName());
|
||||
|
||||
@@ -17,12 +17,8 @@
|
||||
package org.springframework.restdocs.curl;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.documentCurlRequest;
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.documentCurlRequestAndResponse;
|
||||
import static org.springframework.restdocs.curl.CurlDocumentation.documentCurlResponse;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
@@ -34,10 +30,8 @@ import java.util.List;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.restdocs.StubMvcResult;
|
||||
|
||||
/**
|
||||
@@ -77,15 +71,6 @@ public class CurlDocumentationTests {
|
||||
hasItem("$ curl http://localhost/foo -i -X POST"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithoutResponseHeaderInclusion() throws IOException {
|
||||
documentCurlRequest("request-without-response-header-inclusion")
|
||||
.includeResponseHeaders(false)
|
||||
.handle(new StubMvcResult(new MockHttpServletRequest("GET", "/foo"), null));
|
||||
assertThat(requestSnippetLines("request-without-response-header-inclusion"),
|
||||
hasItem("$ curl http://localhost/foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWithContent() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
@@ -192,67 +177,6 @@ public class CurlDocumentationTests {
|
||||
hasItem("$ curl http://localhost/foo -i -H \"Content-Type: application/json\" -H \"a: alpha\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicResponse() throws IOException {
|
||||
documentCurlResponse("basic-response").handle(
|
||||
new StubMvcResult(null, new MockHttpServletResponse()));
|
||||
assertThat(responseSnippetLines("basic-response"), hasItem("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonOkResponse() throws IOException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
documentCurlResponse("non-ok-response").handle(new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("non-ok-response"),
|
||||
hasItem("HTTP/1.1 400 Bad Request"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithHeaders() throws IOException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.setHeader("a", "alpha");
|
||||
documentCurlResponse("non-ok-response").handle(new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("non-ok-response"),
|
||||
hasItems("HTTP/1.1 200 OK", "Content-Type: application/json", "a: alpha"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithHeaderInclusionDisabled() throws IOException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.setHeader("a", "alpha");
|
||||
response.getWriter().append("content");
|
||||
documentCurlResponse("response-with-header-inclusion-disabled")
|
||||
.includeResponseHeaders(false).handle(new StubMvcResult(null, response));
|
||||
List<String> responseSnippetLines = responseSnippetLines("response-with-header-inclusion-disabled");
|
||||
assertThat(
|
||||
responseSnippetLines,
|
||||
not(hasItems("HTTP/1.1 200 OK", "Content-Type: application/json",
|
||||
"a: alpha")));
|
||||
assertThat(responseSnippetLines, hasItem("content"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithContent() throws IOException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().append("content");
|
||||
documentCurlResponse("response-with-content").handle(
|
||||
new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("response-with-content"),
|
||||
hasItems("HTTP/1.1 200 OK", "content"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestAndResponse() throws IOException {
|
||||
documentCurlRequestAndResponse("request-and-response").handle(
|
||||
new StubMvcResult(new MockHttpServletRequest("GET", "/foo"),
|
||||
new MockHttpServletResponse()));
|
||||
assertThat(requestResponseSnippetLines("request-and-response"),
|
||||
hasItems("$ curl http://localhost/foo -i", "HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void httpWithNonStandardPort() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
@@ -296,16 +220,7 @@ public class CurlDocumentationTests {
|
||||
}
|
||||
|
||||
private List<String> requestSnippetLines(String snippetName) throws IOException {
|
||||
return snippetLines(snippetName, "request");
|
||||
}
|
||||
|
||||
private List<String> responseSnippetLines(String snippetName) throws IOException {
|
||||
return snippetLines(snippetName, "response");
|
||||
}
|
||||
|
||||
private List<String> requestResponseSnippetLines(String snippetName)
|
||||
throws IOException {
|
||||
return snippetLines(snippetName, "request-response");
|
||||
return snippetLines(snippetName, "curl-request");
|
||||
}
|
||||
|
||||
private List<String> snippetLines(String snippetName, String snippetType)
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2014-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.restdocs.http;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.hasItem;
|
||||
import static org.hamcrest.CoreMatchers.hasItems;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.springframework.restdocs.http.HttpDocumentation.documentHttpRequest;
|
||||
import static org.springframework.restdocs.http.HttpDocumentation.documentHttpResponse;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockHttpServletResponse;
|
||||
import org.springframework.restdocs.StubMvcResult;
|
||||
|
||||
/**
|
||||
* Tests for {@link HttpDocumentation}
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
public class HttpDocumentationTests {
|
||||
|
||||
private final File outputDir = new File("build/http-documentation-tests");
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
System.setProperty("org.springframework.restdocs.outputDir",
|
||||
this.outputDir.getAbsolutePath());
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
System.clearProperty("org.springframework.restdocs.outputDir");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequest() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addHeader("Alpha", "a");
|
||||
documentHttpRequest("get-request").handle(new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("get-request"),
|
||||
hasItems("GET /foo HTTP/1.1", "Alpha: a"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestWithQueryString() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo?bar=baz");
|
||||
documentHttpRequest("get-request-with-query-string").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("get-request-with-query-string"),
|
||||
hasItems("GET /foo?bar=baz HTTP/1.1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getRequestWithParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
|
||||
request.addParameter("b&r", "baz");
|
||||
documentHttpRequest("get-request-with-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("get-request-with-parameter"),
|
||||
hasItems("GET /foo?b%26r=baz HTTP/1.1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithContent() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
byte[] content = "Hello, world".getBytes();
|
||||
request.setContent(content);
|
||||
documentHttpRequest("post-request-with-content").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(requestSnippetLines("post-request-with-content"),
|
||||
hasItems("POST /foo HTTP/1.1", "Hello, world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void postRequestWithParameter() throws IOException {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/foo");
|
||||
request.addParameter("b&r", "baz");
|
||||
request.addParameter("a", "alpha");
|
||||
documentHttpRequest("post-request-with-parameter").handle(
|
||||
new StubMvcResult(request, null));
|
||||
assertThat(
|
||||
requestSnippetLines("post-request-with-parameter"),
|
||||
hasItems("POST /foo HTTP/1.1",
|
||||
"Content-Type: application/x-www-form-urlencoded",
|
||||
"b%26r=baz&a=alpha"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicResponse() throws IOException {
|
||||
documentHttpResponse("basic-response").handle(
|
||||
new StubMvcResult(null, new MockHttpServletResponse()));
|
||||
assertThat(responseSnippetLines("basic-response"), hasItem("HTTP/1.1 200 OK"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nonOkResponse() throws IOException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setStatus(HttpStatus.BAD_REQUEST.value());
|
||||
documentHttpResponse("non-ok-response").handle(new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("non-ok-response"),
|
||||
hasItem("HTTP/1.1 400 Bad Request"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithHeaders() throws IOException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.setHeader("a", "alpha");
|
||||
documentHttpResponse("non-ok-response").handle(new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("non-ok-response"),
|
||||
hasItems("HTTP/1.1 200 OK", "Content-Type: application/json", "a: alpha"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void responseWithContent() throws IOException {
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
response.getWriter().append("content");
|
||||
documentHttpResponse("response-with-content").handle(
|
||||
new StubMvcResult(null, response));
|
||||
assertThat(responseSnippetLines("response-with-content"),
|
||||
hasItems("HTTP/1.1 200 OK", "content"));
|
||||
}
|
||||
|
||||
private List<String> requestSnippetLines(String snippetName) throws IOException {
|
||||
return snippetLines(snippetName, "http-request");
|
||||
}
|
||||
|
||||
private List<String> responseSnippetLines(String snippetName) throws IOException {
|
||||
return snippetLines(snippetName, "http-response");
|
||||
}
|
||||
|
||||
private List<String> snippetLines(String snippetName, String snippetType)
|
||||
throws IOException {
|
||||
File snippetDir = new File(this.outputDir, snippetName);
|
||||
File snippetFile = new File(snippetDir, snippetType + ".asciidoc");
|
||||
String line = null;
|
||||
List<String> lines = new ArrayList<String>();
|
||||
BufferedReader reader = new BufferedReader(new FileReader(snippetFile));
|
||||
try {
|
||||
while ((line = reader.readLine()) != null) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
reader.close();
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user