Skip to content
This repository was archived by the owner on Aug 16, 2024. It is now read-only.

Commit c768662

Browse files
committed
TIL Rack defaults to URL encoding
Tweak Rack's test helpers to test a JSON API
1 parent e7356b5 commit c768662

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

rails/empty-arrays-in-json-request.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
`Rack::Test` defaults to URL Encoding Parameters
2+
================================================
3+
4+
By default, Rack's test helpers set the `Content-Type` header to
5+
`application/x-www-form-urlencoded`.
6+
7+
The URL encoded representation of
8+
9+
```json
10+
{ "tags": ["foo", "bar"] }
11+
```
12+
13+
would be
14+
15+
```
16+
?tags[]=foo&tags[]=bar
17+
```
18+
19+
This works as expected for non-empty arrays:
20+
21+
```ruby
22+
put "/api/v1/post/1", {
23+
post: { tags: ["foo"] }
24+
}
25+
```
26+
27+
However, it isn't possible to represent `[]` as a URL encoded string.
28+
29+
```ruby
30+
put "/api/v1/post/1", {
31+
post: { tags: [] }
32+
}
33+
```
34+
35+
would be invalidly encoded as:
36+
37+
```
38+
?tags[]=
39+
```
40+
41+
As a result, Rack ignores the `tags` key, which would make the `post` key point
42+
to an empty hash, which Rack also ignores.
43+
44+
To work around this issue:
45+
46+
* transform the `params` hash to a [`JSON` string][rack-test]
47+
* append `.json` to the URL
48+
* explicitly set the `"Content-Type"` header to `"application/json"`
49+
50+
```ruby
51+
put "/api/v1/post/1.json", {
52+
post: { tags: [] }
53+
}.to_json, { "Content-Type" => "application.json" }
54+
```
55+
56+
This pattern can be extracted to a helper:
57+
58+
```ruby
59+
def json_put(path, params, headers_or_env = {})
60+
json_path = "#{path}.json"
61+
params_without_format = params.except(:format)
62+
headers = headers_or_env.reverse_merge("Content-Type" => "application/json")
63+
64+
put(json_path, params_without_format.to_json, headers)
65+
end
66+
67+
68+
json_put "/api/v1/post/1", {
69+
post: { tags: [] }
70+
}
71+
```
72+
73+
Coincidentally, Basecamp has a similar set of test helpers.
74+
75+
[rack-test]: https://github.com/brynary/rack-test/blob/acdbee66fc765f15c2d3a1a372c368fe8ee0a49c/lib/rack/test.rb#L218-L228

0 commit comments

Comments
 (0)