Read and write JSON.
Use a generated Book resource for browser HTML, JSON responses, and typed JSON input through the same action contracts.
Ask for a JSON response
A generated action returns records from handle and supplies HTML through render. A client sending Accept: application/json receives the action result as JSON.
Corretto.session do |client, db|
response = client.get("/books",
headers: {"Accept" => "application/json"})
response.should have_status(200)
JSON.parse(response.body)["records"].as_a.should be_empty
endThis example assumes an empty spec database. Add a persisted-book case to verify the returned fields.
Bind a JSON object to the contract
The default request policy reads Content-Type: application/json. Use a top-level object and the field’s JSON type: strings for String and Time, numbers for Int32, Int64 and Float64, and booleans for Bool. Null is absent; nested arrays and objects do not bind to fields. Duplicate members are errors.
Corretto.session do |client, db|
book = {title: "Dune", author: "Frank Herbert"}
accept = {"Accept" => "application/json"}
created = client.post("/books", json: book, headers: accept)
created.should have_status(201)
JSON.parse(created.body)["record"]["title"].as_s.should eq("Dune")
endKeep browser writes protected
Same-origin browser fetch requests send the page’s CSRF token as X-CSRF-Token. A JSON member named _csrf does not supply that token, and _method does not override the HTTP method. Corretto adds the origin, cookie, and CSRF header automatically; override a header to test rejection.
forged = {"Accept" => "application/json", "X-CSRF-Token" => "forged"}
client.post("/books", json: book, headers: forged).should have_status(403)Check the failure cases
Malformed JSON returns 400. A valid JSON value that is not an object returns 422. Wrong field types and contract or changeset errors return 422; JSON clients receive an errors object. Unsupported media types, including application/*+json, return 415 under the default policy. An action can use raw ingress when it needs a different JSON format.
frappe check
frappe corretto spec/requests/books_spec.crAn API that skips browser CSRF must declare an authenticator with ingress. Its session is empty and unsaved; authenticate with a bearer token or signature that a browser does not attach automatically. The webhook guide shows the request-policy boundary.