reqcord 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/Gemfile +5 -0
  4. data/README.md +13 -0
  5. data/gemfiles/rails_7.1.gemfile +13 -0
  6. data/gemfiles/rails_7.2.gemfile +13 -0
  7. data/gemfiles/rails_8.0.gemfile +13 -0
  8. data/gemfiles/rails_8.1.gemfile +13 -0
  9. data/lib/reqcord/version.rb +1 -1
  10. data/reqcord.gemspec +18 -4
  11. metadata +65 -217
  12. data/.gitignore +0 -8
  13. data/Gemfile.lock +0 -171
  14. data/examples/complex-spec-app/.rspec +0 -1
  15. data/examples/complex-spec-app/README.md +0 -21
  16. data/examples/complex-spec-app/app.rb +0 -363
  17. data/examples/complex-spec-app/docs/api/README.md +0 -104
  18. data/examples/complex-spec-app/docs/api/api/v1/admin/products/create.md +0 -117
  19. data/examples/complex-spec-app/docs/api/api/v1/admin/products/destroy.md +0 -51
  20. data/examples/complex-spec-app/docs/api/api/v1/admin/products/index.md +0 -11
  21. data/examples/complex-spec-app/docs/api/api/v1/admin/products/list.md +0 -106
  22. data/examples/complex-spec-app/docs/api/api/v1/auth/index.md +0 -9
  23. data/examples/complex-spec-app/docs/api/api/v1/auth/login.md +0 -76
  24. data/examples/complex-spec-app/docs/api/api/v1/cart-items/create.md +0 -91
  25. data/examples/complex-spec-app/docs/api/api/v1/cart-items/destroy.md +0 -51
  26. data/examples/complex-spec-app/docs/api/api/v1/cart-items/index.md +0 -10
  27. data/examples/complex-spec-app/docs/api/api/v1/carts/checkout.md +0 -102
  28. data/examples/complex-spec-app/docs/api/api/v1/carts/index.md +0 -10
  29. data/examples/complex-spec-app/docs/api/api/v1/carts/show.md +0 -73
  30. data/examples/complex-spec-app/docs/api/api/v1/home/index.md +0 -9
  31. data/examples/complex-spec-app/docs/api/api/v1/home/list.md +0 -47
  32. data/examples/complex-spec-app/docs/api/api/v1/notes/create.md +0 -94
  33. data/examples/complex-spec-app/docs/api/api/v1/notes/index.md +0 -10
  34. data/examples/complex-spec-app/docs/api/api/v1/notes/list.md +0 -61
  35. data/examples/complex-spec-app/docs/api/api/v1/orders/cancel.md +0 -69
  36. data/examples/complex-spec-app/docs/api/api/v1/orders/create.md +0 -150
  37. data/examples/complex-spec-app/docs/api/api/v1/orders/destroy.md +0 -37
  38. data/examples/complex-spec-app/docs/api/api/v1/orders/index.md +0 -13
  39. data/examples/complex-spec-app/docs/api/api/v1/orders/list.md +0 -78
  40. data/examples/complex-spec-app/docs/api/api/v1/orders/show.md +0 -83
  41. data/examples/complex-spec-app/docs/api/api/v1/products/index.md +0 -11
  42. data/examples/complex-spec-app/docs/api/api/v1/products/list.md +0 -83
  43. data/examples/complex-spec-app/docs/api/api/v1/products/search.md +0 -88
  44. data/examples/complex-spec-app/docs/api/api/v1/products/show.md +0 -71
  45. data/examples/complex-spec-app/docs/api/api/v1/profiles/index.md +0 -10
  46. data/examples/complex-spec-app/docs/api/api/v1/profiles/show.md +0 -61
  47. data/examples/complex-spec-app/docs/api/api/v1/profiles/update.md +0 -91
  48. data/examples/complex-spec-app/docs/api/api/v2/products/index.md +0 -9
  49. data/examples/complex-spec-app/docs/api/api/v2/products/list.md +0 -77
  50. data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/create.sh +0 -18
  51. data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/destroy.sh +0 -9
  52. data/examples/complex-spec-app/docs/api/curl/api/v1/admin/products/list.sh +0 -9
  53. data/examples/complex-spec-app/docs/api/curl/api/v1/auth/login.sh +0 -9
  54. data/examples/complex-spec-app/docs/api/curl/api/v1/cart-items/create.sh +0 -16
  55. data/examples/complex-spec-app/docs/api/curl/api/v1/cart-items/destroy.sh +0 -9
  56. data/examples/complex-spec-app/docs/api/curl/api/v1/carts/checkout.sh +0 -13
  57. data/examples/complex-spec-app/docs/api/curl/api/v1/carts/show.sh +0 -9
  58. data/examples/complex-spec-app/docs/api/curl/api/v1/home/list.sh +0 -8
  59. data/examples/complex-spec-app/docs/api/curl/api/v1/notes/create.sh +0 -15
  60. data/examples/complex-spec-app/docs/api/curl/api/v1/notes/list.sh +0 -9
  61. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/cancel.sh +0 -9
  62. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/create.sh +0 -29
  63. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/destroy.sh +0 -9
  64. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/list.sh +0 -9
  65. data/examples/complex-spec-app/docs/api/curl/api/v1/orders/show.sh +0 -9
  66. data/examples/complex-spec-app/docs/api/curl/api/v1/products/list.sh +0 -8
  67. data/examples/complex-spec-app/docs/api/curl/api/v1/products/search.sh +0 -8
  68. data/examples/complex-spec-app/docs/api/curl/api/v1/products/show.sh +0 -8
  69. data/examples/complex-spec-app/docs/api/curl/api/v1/profiles/show.sh +0 -9
  70. data/examples/complex-spec-app/docs/api/curl/api/v1/profiles/update.sh +0 -16
  71. data/examples/complex-spec-app/docs/api/curl/api/v2/products/list.sh +0 -8
  72. data/examples/complex-spec-app/docs/api/dataset.json +0 -5116
  73. data/examples/complex-spec-app/docs/api/postman/collection.json +0 -2519
  74. data/examples/complex-spec-app/generate.rb +0 -14
  75. data/examples/complex-spec-app/reqcord.yml +0 -28
  76. data/examples/complex-spec-app/spec/requests/admin_spec.rb +0 -67
  77. data/examples/complex-spec-app/spec/requests/cart_spec.rb +0 -61
  78. data/examples/complex-spec-app/spec/requests/home_and_auth_spec.rb +0 -49
  79. data/examples/complex-spec-app/spec/requests/orders_spec.rb +0 -124
  80. data/examples/complex-spec-app/spec/requests/products_spec.rb +0 -65
  81. data/examples/complex-spec-app/spec/spec_helper.rb +0 -17
  82. data/examples/complex-test-app/README.md +0 -40
  83. data/examples/complex-test-app/app.rb +0 -384
  84. data/examples/complex-test-app/docs/api/README.md +0 -104
  85. data/examples/complex-test-app/docs/api/api/v1/admin/products/create.md +0 -117
  86. data/examples/complex-test-app/docs/api/api/v1/admin/products/destroy.md +0 -51
  87. data/examples/complex-test-app/docs/api/api/v1/admin/products/index.md +0 -11
  88. data/examples/complex-test-app/docs/api/api/v1/admin/products/list.md +0 -106
  89. data/examples/complex-test-app/docs/api/api/v1/auth/index.md +0 -9
  90. data/examples/complex-test-app/docs/api/api/v1/auth/login.md +0 -76
  91. data/examples/complex-test-app/docs/api/api/v1/cart-items/create.md +0 -91
  92. data/examples/complex-test-app/docs/api/api/v1/cart-items/destroy.md +0 -51
  93. data/examples/complex-test-app/docs/api/api/v1/cart-items/index.md +0 -10
  94. data/examples/complex-test-app/docs/api/api/v1/carts/checkout.md +0 -102
  95. data/examples/complex-test-app/docs/api/api/v1/carts/index.md +0 -10
  96. data/examples/complex-test-app/docs/api/api/v1/carts/show.md +0 -73
  97. data/examples/complex-test-app/docs/api/api/v1/home/index.md +0 -9
  98. data/examples/complex-test-app/docs/api/api/v1/home/list.md +0 -47
  99. data/examples/complex-test-app/docs/api/api/v1/notes/create.md +0 -94
  100. data/examples/complex-test-app/docs/api/api/v1/notes/index.md +0 -10
  101. data/examples/complex-test-app/docs/api/api/v1/notes/list.md +0 -61
  102. data/examples/complex-test-app/docs/api/api/v1/orders/cancel.md +0 -69
  103. data/examples/complex-test-app/docs/api/api/v1/orders/create.md +0 -150
  104. data/examples/complex-test-app/docs/api/api/v1/orders/destroy.md +0 -37
  105. data/examples/complex-test-app/docs/api/api/v1/orders/index.md +0 -13
  106. data/examples/complex-test-app/docs/api/api/v1/orders/list.md +0 -71
  107. data/examples/complex-test-app/docs/api/api/v1/orders/show.md +0 -83
  108. data/examples/complex-test-app/docs/api/api/v1/products/index.md +0 -11
  109. data/examples/complex-test-app/docs/api/api/v1/products/list.md +0 -83
  110. data/examples/complex-test-app/docs/api/api/v1/products/search.md +0 -88
  111. data/examples/complex-test-app/docs/api/api/v1/products/show.md +0 -71
  112. data/examples/complex-test-app/docs/api/api/v1/profiles/index.md +0 -10
  113. data/examples/complex-test-app/docs/api/api/v1/profiles/show.md +0 -61
  114. data/examples/complex-test-app/docs/api/api/v1/profiles/update.md +0 -91
  115. data/examples/complex-test-app/docs/api/api/v2/products/index.md +0 -9
  116. data/examples/complex-test-app/docs/api/api/v2/products/list.md +0 -77
  117. data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/create.sh +0 -18
  118. data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/destroy.sh +0 -9
  119. data/examples/complex-test-app/docs/api/curl/api/v1/admin/products/list.sh +0 -9
  120. data/examples/complex-test-app/docs/api/curl/api/v1/auth/login.sh +0 -9
  121. data/examples/complex-test-app/docs/api/curl/api/v1/cart-items/create.sh +0 -16
  122. data/examples/complex-test-app/docs/api/curl/api/v1/cart-items/destroy.sh +0 -9
  123. data/examples/complex-test-app/docs/api/curl/api/v1/carts/checkout.sh +0 -13
  124. data/examples/complex-test-app/docs/api/curl/api/v1/carts/show.sh +0 -9
  125. data/examples/complex-test-app/docs/api/curl/api/v1/home/list.sh +0 -8
  126. data/examples/complex-test-app/docs/api/curl/api/v1/notes/create.sh +0 -15
  127. data/examples/complex-test-app/docs/api/curl/api/v1/notes/list.sh +0 -9
  128. data/examples/complex-test-app/docs/api/curl/api/v1/orders/cancel.sh +0 -9
  129. data/examples/complex-test-app/docs/api/curl/api/v1/orders/create.sh +0 -29
  130. data/examples/complex-test-app/docs/api/curl/api/v1/orders/destroy.sh +0 -9
  131. data/examples/complex-test-app/docs/api/curl/api/v1/orders/list.sh +0 -9
  132. data/examples/complex-test-app/docs/api/curl/api/v1/orders/show.sh +0 -9
  133. data/examples/complex-test-app/docs/api/curl/api/v1/products/list.sh +0 -8
  134. data/examples/complex-test-app/docs/api/curl/api/v1/products/search.sh +0 -8
  135. data/examples/complex-test-app/docs/api/curl/api/v1/products/show.sh +0 -8
  136. data/examples/complex-test-app/docs/api/curl/api/v1/profiles/show.sh +0 -9
  137. data/examples/complex-test-app/docs/api/curl/api/v1/profiles/update.sh +0 -16
  138. data/examples/complex-test-app/docs/api/curl/api/v2/products/list.sh +0 -8
  139. data/examples/complex-test-app/docs/api/dataset.json +0 -5109
  140. data/examples/complex-test-app/docs/api/postman/collection.json +0 -2568
  141. data/examples/complex-test-app/generate.rb +0 -14
  142. data/examples/complex-test-app/reqcord.yml +0 -28
  143. data/examples/complex-test-app/test/integration/admin_test.rb +0 -70
  144. data/examples/complex-test-app/test/integration/cart_test.rb +0 -64
  145. data/examples/complex-test-app/test/integration/home_and_auth_test.rb +0 -53
  146. data/examples/complex-test-app/test/integration/orders_test.rb +0 -127
  147. data/examples/complex-test-app/test/integration/products_test.rb +0 -66
  148. data/examples/spec-app/.rspec +0 -1
  149. data/examples/spec-app/README.md +0 -36
  150. data/examples/spec-app/app.rb +0 -209
  151. data/examples/spec-app/docs/api/README.md +0 -45
  152. data/examples/spec-app/docs/api/api/v1/customers/create.md +0 -95
  153. data/examples/spec-app/docs/api/api/v1/customers/index.md +0 -11
  154. data/examples/spec-app/docs/api/api/v1/customers/list.md +0 -67
  155. data/examples/spec-app/docs/api/api/v1/customers/show.md +0 -65
  156. data/examples/spec-app/docs/api/api/v1/tasks/complete.md +0 -51
  157. data/examples/spec-app/docs/api/api/v1/tasks/create.md +0 -90
  158. data/examples/spec-app/docs/api/api/v1/tasks/destroy.md +0 -35
  159. data/examples/spec-app/docs/api/api/v1/tasks/index.md +0 -14
  160. data/examples/spec-app/docs/api/api/v1/tasks/list.md +0 -65
  161. data/examples/spec-app/docs/api/api/v1/tasks/show.md +0 -65
  162. data/examples/spec-app/docs/api/api/v1/tasks/update.md +0 -74
  163. data/examples/spec-app/docs/api/api/v1/users/create.md +0 -95
  164. data/examples/spec-app/docs/api/api/v1/users/index.md +0 -11
  165. data/examples/spec-app/docs/api/api/v1/users/list.md +0 -67
  166. data/examples/spec-app/docs/api/api/v1/users/show.md +0 -65
  167. data/examples/spec-app/docs/api/curl/api/v1/customers/create.sh +0 -17
  168. data/examples/spec-app/docs/api/curl/api/v1/customers/list.sh +0 -9
  169. data/examples/spec-app/docs/api/curl/api/v1/customers/show.sh +0 -9
  170. data/examples/spec-app/docs/api/curl/api/v1/tasks/complete.sh +0 -8
  171. data/examples/spec-app/docs/api/curl/api/v1/tasks/create.sh +0 -15
  172. data/examples/spec-app/docs/api/curl/api/v1/tasks/destroy.sh +0 -8
  173. data/examples/spec-app/docs/api/curl/api/v1/tasks/list.sh +0 -8
  174. data/examples/spec-app/docs/api/curl/api/v1/tasks/show.sh +0 -8
  175. data/examples/spec-app/docs/api/curl/api/v1/tasks/update.sh +0 -14
  176. data/examples/spec-app/docs/api/curl/api/v1/users/create.sh +0 -17
  177. data/examples/spec-app/docs/api/curl/api/v1/users/list.sh +0 -9
  178. data/examples/spec-app/docs/api/curl/api/v1/users/show.sh +0 -9
  179. data/examples/spec-app/docs/api/dataset.json +0 -2402
  180. data/examples/spec-app/docs/api/postman/collection.json +0 -1290
  181. data/examples/spec-app/generate.rb +0 -14
  182. data/examples/spec-app/reqcord.yml +0 -27
  183. data/examples/spec-app/spec/requests/customers_spec.rb +0 -71
  184. data/examples/spec-app/spec/requests/tasks_spec.rb +0 -78
  185. data/examples/spec-app/spec/requests/users_spec.rb +0 -68
  186. data/examples/spec-app/spec/spec_helper.rb +0 -17
  187. data/examples/test-app/README.md +0 -57
  188. data/examples/test-app/app.rb +0 -212
  189. data/examples/test-app/docs/api/README.md +0 -45
  190. data/examples/test-app/docs/api/api/v1/customers/create.md +0 -95
  191. data/examples/test-app/docs/api/api/v1/customers/index.md +0 -11
  192. data/examples/test-app/docs/api/api/v1/customers/list.md +0 -67
  193. data/examples/test-app/docs/api/api/v1/customers/show.md +0 -65
  194. data/examples/test-app/docs/api/api/v1/tasks/complete.md +0 -51
  195. data/examples/test-app/docs/api/api/v1/tasks/create.md +0 -90
  196. data/examples/test-app/docs/api/api/v1/tasks/destroy.md +0 -35
  197. data/examples/test-app/docs/api/api/v1/tasks/index.md +0 -14
  198. data/examples/test-app/docs/api/api/v1/tasks/list.md +0 -65
  199. data/examples/test-app/docs/api/api/v1/tasks/show.md +0 -65
  200. data/examples/test-app/docs/api/api/v1/tasks/update.md +0 -74
  201. data/examples/test-app/docs/api/api/v1/users/create.md +0 -95
  202. data/examples/test-app/docs/api/api/v1/users/index.md +0 -11
  203. data/examples/test-app/docs/api/api/v1/users/list.md +0 -67
  204. data/examples/test-app/docs/api/api/v1/users/show.md +0 -65
  205. data/examples/test-app/docs/api/curl/api/v1/customers/create.sh +0 -17
  206. data/examples/test-app/docs/api/curl/api/v1/customers/list.sh +0 -9
  207. data/examples/test-app/docs/api/curl/api/v1/customers/show.sh +0 -9
  208. data/examples/test-app/docs/api/curl/api/v1/tasks/complete.sh +0 -8
  209. data/examples/test-app/docs/api/curl/api/v1/tasks/create.sh +0 -15
  210. data/examples/test-app/docs/api/curl/api/v1/tasks/destroy.sh +0 -8
  211. data/examples/test-app/docs/api/curl/api/v1/tasks/list.sh +0 -8
  212. data/examples/test-app/docs/api/curl/api/v1/tasks/show.sh +0 -8
  213. data/examples/test-app/docs/api/curl/api/v1/tasks/update.sh +0 -14
  214. data/examples/test-app/docs/api/curl/api/v1/users/create.sh +0 -17
  215. data/examples/test-app/docs/api/curl/api/v1/users/list.sh +0 -9
  216. data/examples/test-app/docs/api/curl/api/v1/users/show.sh +0 -9
  217. data/examples/test-app/docs/api/dataset.json +0 -2402
  218. data/examples/test-app/docs/api/postman/collection.json +0 -1290
  219. data/examples/test-app/generate.rb +0 -14
  220. data/examples/test-app/reqcord.yml +0 -28
  221. data/examples/test-app/test/integration/customers_test.rb +0 -72
  222. data/examples/test-app/test/integration/tasks_test.rb +0 -80
  223. data/examples/test-app/test/integration/users_test.rb +0 -72
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Stands in for `bin/rails reqcord:generate`, which this single file example
4
- # has no `bin/rails` to run.
5
- require_relative "app"
6
-
7
- dataset = Reqcord::Generator.call(
8
- resources: ENV.fetch("RESOURCE", "").split(",").map(&:strip).reject(&:empty?),
9
- version: ENV["VERSION"]
10
- )
11
-
12
- puts
13
- puts "Endpoints: #{dataset.endpoints.size} (#{dataset.documented_endpoints.size} covered by tests)"
14
- puts "Output: #{Reqcord.configuration.output_directory}"
@@ -1,27 +0,0 @@
1
- version: 1
2
-
3
- test:
4
- framework: rspec
5
- # A directory is enough: Reqcord runs `rspec <paths>`.
6
- paths:
7
- - spec/requests
8
-
9
- routes:
10
- prefix: /api
11
-
12
- output:
13
- directory: docs/api
14
-
15
- exporters:
16
- - curl
17
- - markdown
18
- - postman
19
-
20
- variables:
21
- base_url: http://localhost:3000
22
-
23
- sanitize:
24
- headers:
25
- Authorization: "Bearer {{token}}"
26
- body:
27
- password: "{{password}}"
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Ordinary request specs. As with Minitest, nothing here mentions Reqcord.
4
- #
5
- # The status assertions are spelled out because this example runs on plain
6
- # rspec-core; with rspec-rails you would write `have_http_status(:created)`.
7
- require "spec_helper"
8
-
9
- RSpec.describe "Customers", type: :request do
10
- let(:auth) { { "Authorization" => "Bearer eyJhbGciOiJIUzI1NiJ9.super-secret" } }
11
-
12
- it "lists customers" do
13
- get "/api/v1/customers", params: { per_page: 1 }, headers: auth, as: :json
14
-
15
- expect(response.status).to eq(200)
16
- end
17
-
18
- it "shows customer" do
19
- get "/api/v1/customers/1", headers: auth, as: :json
20
-
21
- expect(response.status).to eq(200)
22
- end
23
-
24
- it "returns not found for an unknown customer" do
25
- get "/api/v1/customers/999", headers: auth, as: :json
26
-
27
- expect(response.status).to eq(404)
28
- end
29
-
30
- it "creates an active customer" do
31
- post "/api/v1/customers",
32
- params: { customer: { name: "Ada Lovelace", email: "ada@example.com", status: "active" } },
33
- headers: auth,
34
- as: :json
35
-
36
- expect(response.status).to eq(201)
37
- end
38
-
39
- it "creates a passive customer" do
40
- post "/api/v1/customers",
41
- params: { customer: { name: "Grace Hopper", email: "grace@example.com", status: "passive" } },
42
- headers: auth,
43
- as: :json
44
-
45
- expect(response.status).to eq(201)
46
- end
47
-
48
- it "rejects an unknown status" do
49
- post "/api/v1/customers",
50
- params: { customer: { name: "Ada Lovelace", email: "ada@example.com", status: "inactive" } },
51
- headers: auth,
52
- as: :json
53
-
54
- expect(response.status).to eq(422)
55
- end
56
-
57
- it "rejects a customer without an email" do
58
- post "/api/v1/customers",
59
- params: { customer: { name: "Ada Lovelace", email: "", status: "active" } },
60
- headers: auth,
61
- as: :json
62
-
63
- expect(response.status).to eq(422)
64
- end
65
-
66
- it "requires authentication" do
67
- get "/api/v1/customers", as: :json
68
-
69
- expect(response.status).to eq(401)
70
- end
71
- end
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Ordinary request specs. As with Minitest, nothing here mentions Reqcord.
4
- require "spec_helper"
5
-
6
- RSpec.describe "Tasks", type: :request do
7
- it "lists tasks" do
8
- get "/api/v1/tasks", as: :json
9
-
10
- expect(response.status).to eq(200)
11
- end
12
-
13
- it "lists open tasks" do
14
- get "/api/v1/tasks", params: { status: "open" }, as: :json
15
-
16
- expect(response.status).to eq(200)
17
- end
18
-
19
- it "lists done tasks" do
20
- get "/api/v1/tasks", params: { status: "done" }, as: :json
21
-
22
- expect(response.status).to eq(200)
23
- end
24
-
25
- it "shows a task" do
26
- get "/api/v1/tasks/1", as: :json
27
-
28
- expect(response.status).to eq(200)
29
- end
30
-
31
- it "returns not found for an unknown task" do
32
- get "/api/v1/tasks/999", as: :json
33
-
34
- expect(response.status).to eq(404)
35
- end
36
-
37
- it "creates a high priority task" do
38
- post "/api/v1/tasks", params: { task: { title: "Review the release", priority: "high" } }, as: :json
39
-
40
- expect(response.status).to eq(201)
41
- end
42
-
43
- it "creates a low priority task" do
44
- post "/api/v1/tasks", params: { task: { title: "Water the plants", priority: "low" } }, as: :json
45
-
46
- expect(response.status).to eq(201)
47
- end
48
-
49
- it "rejects a task without a title" do
50
- post "/api/v1/tasks", params: { task: { title: "", priority: "high" } }, as: :json
51
-
52
- expect(response.status).to eq(422)
53
- end
54
-
55
- it "rejects an unknown priority" do
56
- post "/api/v1/tasks", params: { task: { title: "Anything", priority: "urgent" } }, as: :json
57
-
58
- expect(response.status).to eq(422)
59
- end
60
-
61
- it "updates a task" do
62
- patch "/api/v1/tasks/1", params: { task: { title: "Write better docs" } }, as: :json
63
-
64
- expect(response.status).to eq(200)
65
- end
66
-
67
- it "completes a task" do
68
- post "/api/v1/tasks/1/complete", as: :json
69
-
70
- expect(response.status).to eq(200)
71
- end
72
-
73
- it "deletes a task" do
74
- delete "/api/v1/tasks/3", as: :json
75
-
76
- expect(response.status).to eq(204)
77
- end
78
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Ordinary request specs. As with Minitest, nothing here mentions Reqcord.
4
- require "spec_helper"
5
-
6
- RSpec.describe "Users", type: :request do
7
- let(:auth) { { "Authorization" => "Bearer eyJhbGciOiJIUzI1NiJ9.super-secret" } }
8
-
9
- it "lists users" do
10
- get "/api/v1/users", params: { per_page: 1 }, headers: auth, as: :json
11
-
12
- expect(response.status).to eq(200)
13
- end
14
-
15
- it "shows user" do
16
- get "/api/v1/users/1", headers: auth, as: :json
17
-
18
- expect(response.status).to eq(200)
19
- end
20
-
21
- it "returns not found for an unknown user" do
22
- get "/api/v1/users/999", headers: auth, as: :json
23
-
24
- expect(response.status).to eq(404)
25
- end
26
-
27
- it "creates an active user" do
28
- post "/api/v1/users",
29
- params: { user: { name: "Ada Lovelace", email: "ada@example.com", status: "active" } },
30
- headers: auth,
31
- as: :json
32
-
33
- expect(response.status).to eq(201)
34
- end
35
-
36
- it "creates an inactive user" do
37
- post "/api/v1/users",
38
- params: { user: { name: "Grace Hopper", email: "grace@example.com", status: "inactive" } },
39
- headers: auth,
40
- as: :json
41
-
42
- expect(response.status).to eq(201)
43
- end
44
-
45
- it "rejects an unknown status" do
46
- post "/api/v1/users",
47
- params: { user: { name: "Ada Lovelace", email: "ada@example.com", status: "passive" } },
48
- headers: auth,
49
- as: :json
50
-
51
- expect(response.status).to eq(422)
52
- end
53
-
54
- it "rejects a user without an email" do
55
- post "/api/v1/users",
56
- params: { user: { name: "Ada Lovelace", email: "", status: "active" } },
57
- headers: auth,
58
- as: :json
59
-
60
- expect(response.status).to eq(422)
61
- end
62
-
63
- it "requires authentication" do
64
- get "/api/v1/users", as: :json
65
-
66
- expect(response.status).to eq(401)
67
- end
68
- end
@@ -1,17 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative "../app"
4
-
5
- require "rspec/core"
6
- require "action_dispatch/testing/integration"
7
-
8
- RSpec.configure do |config|
9
- # What rspec-rails would give you as `type: :request`; spelled out here so
10
- # the example runs with plain rspec-core.
11
- config.include ActionDispatch::Integration::Runner, type: :request
12
- config.include ActionDispatch::IntegrationTest::Behavior, type: :request
13
-
14
- config.before(:each, type: :request) { integration_session }
15
-
16
- config.expect_with(:rspec) { |expectations| expectations.syntax = :expect }
17
- end
@@ -1,57 +0,0 @@
1
- # test-app (Minitest)
2
-
3
- A one file Rails API with ordinary Minitest integration tests, and the
4
- documentation Reqcord generates from them. Three resources, each there to
5
- show something different in the output:
6
-
7
- | Resource | Shows |
8
- | --- | --- |
9
- | `customers` | bearer auth, a closed set of values (`"active" \| "passive"`), 401/422 responses |
10
- | `users` | a second authenticated resource with its own status set |
11
- | `tasks` | no auth, full CRUD, `PATCH` and `PUT` folded into one page, a `204`, a member action (`complete`), a filtered index (`?status=open`) |
12
-
13
- ```text
14
- app.rb the application
15
- test/integration/*_test.rb ordinary integration tests
16
- reqcord.yml Reqcord configuration
17
- docs/api/ generated output, committed here so you can
18
- read it without running anything:
19
- api/v1/{customers,users,tasks}/*.md Markdown, one page per endpoint
20
- curl/api/v1/**/*.sh runnable cURL scripts
21
- postman/collection.json Postman collection (Hoppscotch imports it)
22
- dataset.json the canonical dataset behind all three
23
- ```
24
-
25
- ## Regenerate
26
-
27
- ```bash
28
- ruby generate.rb
29
- ```
30
-
31
- In a real application you would run `bin/rails reqcord:generate` instead;
32
- `generate.rb` only exists because this example has no `bin/rails`.
33
-
34
- `reqcord.yml` only names the test directory; with no `bin/rails` around,
35
- Reqcord runs every `*_test.rb` beneath it itself.
36
-
37
- Filters work the same way:
38
-
39
- ```bash
40
- RESOURCE=tasks ruby generate.rb
41
- RESOURCE=customers,users ruby generate.rb
42
- VERSION=v1 ruby generate.rb
43
- ```
44
-
45
- ## What to look at
46
-
47
- - The tests never mention Reqcord.
48
- - `Authorization: Bearer eyJ...` is written as `Bearer {{token}}` in
49
- [docs/api/api/v1/customers/create.md](docs/api/api/v1/customers/create.md).
50
- - `customer.status` is documented as `"active" | "passive"`: two tests sent
51
- those and passed, a third sent `"inactive"` and was rejected, so the
52
- rejected value never becomes a documented parameter.
53
- - One endpoint carries every status its tests produced: `201`, `422`, `401`.
54
- - Each cURL example uses the real captured path, so it can be pasted into a
55
- terminal once `{{token}}` is replaced; the same request is in
56
- [docs/api/postman/collection.json](docs/api/postman/collection.json) with
57
- `{{token}}` as a collection variable.
@@ -1,212 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # A tiny Rails API, in one file, so the example stays readable. In a real
4
- # application this is just your app; Reqcord does not care how it is built.
5
- #
6
- # Three resources, each showing something different in the output:
7
- # customers authenticated, a closed set of statuses ("active" | "passive")
8
- # users the same shape with its own status set, to show two resources
9
- # tasks public (no auth), full CRUD with PATCH/PUT, a 204, a member
10
- # action (`complete`) and a filtered index (`?status=`)
11
- ENV["RAILS_ENV"] ||= "test"
12
-
13
- # Only needed because this example lives inside the Reqcord repository.
14
- # In your own application, `gem "reqcord"` in the Gemfile is enough.
15
- $LOAD_PATH.unshift File.expand_path("../../lib", __dir__)
16
-
17
- require "rails"
18
- require "action_controller/railtie"
19
- require "reqcord"
20
-
21
- class ExampleApp < Rails::Application
22
- config.root = __dir__
23
- config.eager_load = false
24
- config.logger = Logger.new(IO::NULL)
25
- config.secret_key_base = "a" * 64
26
- config.hosts.clear
27
- end
28
-
29
- Rails.application.initialize!
30
-
31
- module Api
32
- module V1
33
- class CustomersController < ActionController::API
34
- CUSTOMERS = [
35
- { id: 1, name: "John Doe", email: "john@example.com" },
36
- { id: 2, name: "Jane Roe", email: "jane@example.com" }
37
- ].freeze
38
-
39
- before_action :authenticate!
40
-
41
- def index
42
- render json: CUSTOMERS.first(params.fetch(:per_page, 25).to_i)
43
- end
44
-
45
- def show
46
- customer = CUSTOMERS.find { |record| record[:id] == params[:id].to_i }
47
-
48
- return render(json: { error: "Not Found" }, status: :not_found) unless customer
49
-
50
- render json: customer
51
- end
52
-
53
- STATUSES = %w[active passive].freeze
54
-
55
- def create
56
- if params.dig(:customer, :email).to_s.empty?
57
- return render(
58
- json: { errors: { email: ["can't be blank"] } },
59
- status: :unprocessable_entity
60
- )
61
- end
62
-
63
- unless STATUSES.include?(params.dig(:customer, :status).to_s)
64
- return render(
65
- json: { errors: { status: ["is not included in the list"] } },
66
- status: :unprocessable_entity
67
- )
68
- end
69
-
70
- render json: { id: 3, **customer_params }, status: :created
71
- end
72
-
73
- private
74
-
75
- def authenticate!
76
- return if request.headers["Authorization"].present?
77
-
78
- render json: { error: "Unauthorized" }, status: :unauthorized
79
- end
80
-
81
- def customer_params
82
- params.require(:customer).permit(:name, :email, :status).to_h.symbolize_keys
83
- end
84
- end
85
-
86
- class UsersController < ActionController::API
87
- USERS = [
88
- { id: 1, name: "John Doe", email: "john@example.com" },
89
- { id: 2, name: "Jane Roe", email: "jane@example.com" }
90
- ].freeze
91
-
92
- before_action :authenticate!
93
-
94
- def index
95
- render json: USERS.first(params.fetch(:per_page, 25).to_i)
96
- end
97
-
98
- def show
99
- user = USERS.find { |record| record[:id] == params[:id].to_i }
100
-
101
- return render(json: { error: "Not Found" }, status: :not_found) unless user
102
-
103
- render json: user
104
- end
105
-
106
- STATUSES = %w[active inactive].freeze
107
-
108
- def create
109
- if params.dig(:user, :email).to_s.empty?
110
- return render(
111
- json: { errors: { email: ["can't be blank"] } },
112
- status: :unprocessable_entity
113
- )
114
- end
115
-
116
- unless STATUSES.include?(params.dig(:user, :status).to_s)
117
- return render(
118
- json: { errors: { status: ["is not included in the list"] } },
119
- status: :unprocessable_entity
120
- )
121
- end
122
-
123
- render json: { id: 3, **user_params }, status: :created
124
- end
125
-
126
- private
127
-
128
- def authenticate!
129
- return if request.headers["Authorization"].present?
130
-
131
- render json: { error: "Unauthorized" }, status: :unauthorized
132
- end
133
-
134
- def user_params
135
- params.require(:user).permit(:name, :email, :status).to_h.symbolize_keys
136
- end
137
- end
138
-
139
- class TasksController < ActionController::API
140
- TASKS = [
141
- { id: 1, title: "Write the docs", status: "open", priority: "high" },
142
- { id: 2, title: "Ship 0.1.1", status: "done", priority: "high" },
143
- { id: 3, title: "Tidy the backlog", status: "open", priority: "low" }
144
- ].freeze
145
-
146
- STATUSES = %w[open done].freeze
147
- PRIORITIES = %w[low high].freeze
148
-
149
- def index
150
- tasks = TASKS
151
- tasks = tasks.select { |task| task[:status] == params[:status] } if params[:status].present?
152
-
153
- render json: tasks
154
- end
155
-
156
- before_action :find_task, only: %i[show update complete destroy]
157
-
158
- def show
159
- render json: @task
160
- end
161
-
162
- def create
163
- if params.dig(:task, :title).to_s.empty?
164
- return render(json: { errors: { title: ["can't be blank"] } }, status: :unprocessable_entity)
165
- end
166
-
167
- unless PRIORITIES.include?(params.dig(:task, :priority).to_s)
168
- return render(json: { errors: { priority: ["is not included in the list"] } }, status: :unprocessable_entity)
169
- end
170
-
171
- render json: { id: 4, status: "open", **task_params }, status: :created
172
- end
173
-
174
- def update
175
- render json: @task.merge(task_params)
176
- end
177
-
178
- def complete
179
- render json: @task.merge(status: "done")
180
- end
181
-
182
- def destroy
183
- head :no_content
184
- end
185
-
186
- private
187
-
188
- # Rendering in a before_action halts the chain, so the action never runs.
189
- def find_task
190
- @task = TASKS.find { |task| task[:id] == params[:id].to_i }
191
-
192
- render(json: { error: "Not Found" }, status: :not_found) unless @task
193
- end
194
-
195
- def task_params
196
- params.require(:task).permit(:title, :priority, :status).to_h.symbolize_keys
197
- end
198
- end
199
- end
200
- end
201
-
202
- Rails.application.routes.draw do
203
- namespace :api do
204
- namespace :v1 do
205
- resources :customers, only: %i[index show create]
206
- resources :users, only: %i[index show create]
207
- resources :tasks, except: %i[new edit] do
208
- post :complete, on: :member
209
- end
210
- end
211
- end
212
- end
@@ -1,45 +0,0 @@
1
- # API Documentation
2
-
3
- Generated by Reqcord from the application's integration tests.
4
-
5
- Base URL: `http://localhost:3000`
6
-
7
- ## Placeholders
8
-
9
- | Header | Replace with |
10
- | --- | --- |
11
- | Authorization | `Bearer {{token}}` |
12
- | X-Api-Key | `{{api_key}}` |
13
-
14
- ## Customers
15
-
16
- Namespace: `api/v1`
17
-
18
- | Method | Path | Description |
19
- | --- | --- | --- |
20
- | `GET` | [`/api/v1/customers`](api/v1/customers/list.md) | List Customers |
21
- | `POST` | [`/api/v1/customers`](api/v1/customers/create.md) | Create Customer |
22
- | `GET` | [`/api/v1/customers/:id`](api/v1/customers/show.md) | Get Customer |
23
-
24
- ## Tasks
25
-
26
- Namespace: `api/v1`
27
-
28
- | Method | Path | Description |
29
- | --- | --- | --- |
30
- | `GET` | [`/api/v1/tasks`](api/v1/tasks/list.md) | List Tasks |
31
- | `POST` | [`/api/v1/tasks`](api/v1/tasks/create.md) | Create Task |
32
- | `DELETE` | [`/api/v1/tasks/:id`](api/v1/tasks/destroy.md) | Delete Task |
33
- | `GET` | [`/api/v1/tasks/:id`](api/v1/tasks/show.md) | Get Task |
34
- | `PATCH` | [`/api/v1/tasks/:id`](api/v1/tasks/update.md) | Update Task |
35
- | `POST` | [`/api/v1/tasks/:id/complete`](api/v1/tasks/complete.md) | Complete Task |
36
-
37
- ## Users
38
-
39
- Namespace: `api/v1`
40
-
41
- | Method | Path | Description |
42
- | --- | --- | --- |
43
- | `GET` | [`/api/v1/users`](api/v1/users/list.md) | List Users |
44
- | `POST` | [`/api/v1/users`](api/v1/users/create.md) | Create User |
45
- | `GET` | [`/api/v1/users/:id`](api/v1/users/show.md) | Get User |
@@ -1,95 +0,0 @@
1
- # Create Customer
2
-
3
- `POST /api/v1/customers`
4
-
5
- Namespace: `api/v1`
6
-
7
- ## Headers
8
-
9
- | Header | Value |
10
- | --- | --- |
11
- | Authorization | `Bearer {{token}}` |
12
- | Content-Type | `application/json` |
13
- | Accept | `application/json` |
14
-
15
- ## Body Parameters
16
-
17
- | Field | Type | Required | Values |
18
- | --- | --- | --- | --- |
19
- | `customer.name` | string | yes | `"Ada Lovelace"` |
20
- | `customer.email` | string | yes | `"ada@example.com"` |
21
- | `customer.status` | string | yes | `"active"` \| `"passive"` |
22
-
23
- ## Example Request
24
-
25
- ```json
26
- {
27
- "customer": {
28
- "name": "Ada Lovelace",
29
- "email": "ada@example.com",
30
- "status": "active"
31
- }
32
- }
33
- ```
34
-
35
- ## cURL
36
-
37
- ```bash
38
- curl --request POST \
39
- --url "http://localhost:3000/api/v1/customers" \
40
- --header "Authorization: Bearer {{token}}" \
41
- --header "Content-Type: application/json" \
42
- --header "Accept: application/json" \
43
- --data '{
44
- "customer": {
45
- "name": "Ada Lovelace",
46
- "email": "ada@example.com",
47
- "status": "active"
48
- }
49
- }'
50
- ```
51
-
52
- ## Responses
53
-
54
- ### 201 Created
55
-
56
- #### Fields
57
-
58
- | Field | Type | Required | Values |
59
- | --- | --- | --- | --- |
60
- | `id` | integer | yes | `3` |
61
- | `name` | string | yes | `"Ada Lovelace"` |
62
- | `email` | string | yes | `"ada@example.com"` |
63
- | `status` | string | yes | `"active"` \| `"passive"` |
64
-
65
- ```json
66
- {
67
- "id": 3,
68
- "name": "Ada Lovelace",
69
- "email": "ada@example.com",
70
- "status": "active"
71
- }
72
- ```
73
-
74
- ### 422 Unprocessable Content
75
-
76
- #### Fields
77
-
78
- | Field | Type | Required | Values |
79
- | --- | --- | --- | --- |
80
- | `errors.email[]` | string | no | `"can't be blank"` |
81
- | `errors.status[]` | string | no | `"is not included in the list"` |
82
-
83
- ```json
84
- {
85
- "errors": {
86
- "email": [
87
- "can't be blank"
88
- ]
89
- }
90
- }
91
- ```
92
-
93
- ---
94
-
95
- Resource: [Customers](index.md)