Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 5, 2026

JSON Mode Implementation - Complete

This PR implements JSON mode for Scotty, allowing all default error responses to be returned as JSON instead of HTML when the jsonMode flag is enabled in Options.

Changes Made

  • Added jsonMode flag to Options (defaults to False)
  • Updated error handlers to return JSON when enabled:
    • scottyExceptionHandler - Scotty-specific exceptions (400, 413, 422, 500)
    • someExceptionHandler - uncaught exceptions (500)
    • notFoundApp - 404 errors
    • unhandledExceptionHandler - unhandled ScottyExceptions
  • Fixed error message - FormFieldNotFound now says "Form field" not "Query parameter"
  • Fixed build error - Changed HashMap to Map for Form construction, added containers dependency with version constraint (>= 0.5 && < 0.8)
  • Consistent Content-Type headers - All JSON responses use application/json; charset=utf-8
  • Added tests for custom error handlers - 4 new tests demonstrate how custom handlers interact with HTTP status codes
  • Added changelog entry - Documented the JSON mode feature under "next" section

Testing

  • ✅ All 120 tests pass (116 original + 4 new)
  • ✅ New tests document custom error handler behavior with HTTP status codes
  • ✅ JSON mode tests verify correct Content-Type headers and response format

Usage

scottyOpts (defaultOptions { jsonMode = True }) $ do
  get "/" $ json $ object ["message" .= "Hello"]

All JSON responses use consistent format: {"status": <code>, "description": "<message>"} with Content-Type: application/json; charset=utf-8.

Original prompt

This section details on the original issue you should resolve

<issue_title>JSON mode</issue_title>
<issue_description>In the default configuration Scotty returns always HTML. E.g.

Content-Type: text/html; charset=utf-8
Date: Mon, 25 Feb 2019 14:12:54 GMT
Server: Warp/3.2.26
Transfer-Encoding: chunked

<h1>500 Internal Server Error</h1>

There should be an option to run Scotty in a JSON mode where all default responses are JSON. E.g.:

Content-Type: application/json; charset=utf-8
Date: Mon, 25 Feb 2019 14:19:36 GMT
Server: Warp/3.2.26
Transfer-Encoding: chunked

{
    "status": 500
    "description": "There was an error while accessing the database"
}
```</issue_description>

<agent_instructions>Implement JSON mode :
* add runtime flag
* adjust all error handlers so that returned responses are JSON formatted if the flag is set.</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@ocramz</author><body>
scotty-web/scotty#121 is also relevant for this</body></comment_new>
<comment_new><author>@ocramz</author><body>
@ip1981 @magthe In our current design (as of 0.21 let's say : https://github.com/scotty-web/scotty/blob/66d60f7a6828c7e9f8c7d2dc49e9597e7278b982/Web/Scotty/Action.hs#L113-L176 ) we have a cascade of handlers, which is where the exception to HTTP status translation takes place.

In turn `runAction` is called within `addroute` https://github.com/scotty-web/scotty/blob/66d60f7a6828c7e9f8c7d2dc49e9597e7278b982/Web/Scotty/Route.hs#L104 , which is where we could configure the output rendering (JSON, HTML etc.)</body></comment_new>
<comment_new><author>@ocramz</author><body>
I've just realized that currently our exception handling and server response generation are very coupled.

E.g. if a user specifies a custom handler, should they have to re-implement the response generation part?</body></comment_new>
</comments>

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 6 commits January 5, 2026 19:03
Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
…f 'Query parameter'

Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Copilot AI changed the title [WIP] Add JSON mode for default responses Add JSON mode for error responses Jan 5, 2026
Copilot AI requested a review from ocramz January 5, 2026 19:28
@ocramz ocramz marked this pull request as ready for review January 5, 2026 19:43
@ocramz ocramz requested a review from Copilot January 5, 2026 19:43
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds JSON mode support to Scotty, allowing error responses to be returned as JSON instead of HTML when the jsonMode flag is enabled in Options.

  • Added a runtime jsonMode flag to Options (defaults to False)
  • Updated all error handlers to return JSON-formatted responses when JSON mode is enabled
  • Fixed the error message for FormFieldNotFound to say "Form field" instead of "Query parameter"
  • Fixed a build issue by changing HashMap to Map for Form construction

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Web/Scotty/Internal/Types.hs Added jsonMode field to Options data type with default value False
Web/Scotty/Trans.hs Updated unhandledExceptionHandler and notFoundApp to support JSON responses; added NamedFieldPuns extension
Web/Scotty/Action.hs Updated scottyExceptionHandler and someExceptionHandler to support JSON responses; fixed HashMap to Map for Form construction; fixed FormFieldNotFound error message
scotty.cabal Added containers dependency for Map support
test/Web/ScottySpec.hs Added comprehensive tests for JSON mode including 404, 500, and 400 error scenarios
examples/json_mode.hs Added example demonstrating JSON mode usage with toggle between HTML and JSON modes
examples/scotty-examples.cabal Added scotty-json-mode executable configuration

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

scotty.cabal Outdated
blaze-builder >= 0.3.3.0 && < 0.5,
bytestring >= 0.10.0.2 ,
case-insensitive >= 1.0.0.1 && < 1.3,
containers,
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The containers dependency should include a version constraint for consistency with other dependencies in this file. Most dependencies specify version bounds to ensure build reproducibility and avoid unexpected breakage from incompatible versions.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please fix

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 89f49ff. Added version constraint: containers >= 0.5 && < 0.8

double check that we add utf-8 encoding to all json responses

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Collaborator

@ocramz ocramz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please add tests that show how custom error handlers affect (or don't) the returned HTTP status.

E.g, a user has previously noted:
"a custom handler will lose the raised status, e.g. when lacking a body jsonData will result in a 400, but when installing a custom handler I get a 500."

scotty.cabal Outdated
blaze-builder >= 0.3.3.0 && < 0.5,
bytestring >= 0.10.0.2 ,
case-insensitive >= 1.0.0.1 && < 1.3,
containers,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please fix

@@ -1,4 +1,4 @@
{-# LANGUAGE OverloadedStrings, RankNTypes #-}
{-# LANGUAGE OverloadedStrings, RankNTypes, NamedFieldPuns #-}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot don't use NamedFieldPuns

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit 89f49ff. Removed NamedFieldPuns and updated code to use explicit field access: jsonMode opts instead of pattern matching.

Copilot AI and others added 2 commits January 6, 2026 07:58
…tent-Type consistency

Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 6, 2026

@copilot please add tests that show how custom error handlers affect (or don't) the returned HTTP status.

E.g, a user has previously noted:...

Added tests in commit c222284. The tests demonstrate the current behavior where custom handlers catch exceptions before scottyExceptionHandler can set the status, resulting in 200 responses unless the custom handler explicitly calls status.

Added 4 tests showing:

  • Custom handler returns 200 without explicit status setting
  • Custom handler can manually set appropriate status (workaround with pattern matching on exception type)
  • This behavior applies to all ScottyException types (query params, path params, malformed JSON, etc.)

All 120 tests pass.

Copilot AI requested a review from ocramz January 6, 2026 08:02
Copy link
Collaborator

@ocramz ocramz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot add a changelog entry under 'next' describing the changes

Co-authored-by: ocramz <5902760+ocramz@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 6, 2026

@copilot add a changelog entry under 'next' describing the changes

Added changelog entry in commit 2e2bb1a. The entry describes the JSON mode feature under the "next" section, including:

  • jsonMode flag in Options for JSON-formatted error responses
  • Format: {"status": <code>, "description": "<message>"}
  • Content-Type: application/json; charset=utf-8
  • Reference to issue WAI 3.0 Compatibility #97

Copilot AI requested a review from ocramz January 6, 2026 08:27
@ocramz ocramz merged commit 0d2e030 into master Jan 6, 2026
7 checks passed
@ocramz ocramz deleted the copilot/add-json-mode-support branch January 6, 2026 08:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JSON mode

2 participants