Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Command-Line Interface Design for JSON Formatters
JSON (JavaScript Object Notation) is the de facto standard for data exchange on the web and in many other contexts. While highly flexible, JSON can sometimes be hard to read, especially when it's minified or deeply nested. Command-line interface (CLI) tools that format (or "pretty-print") JSON are essential utilities for developers. This article explores common patterns and best practices for designing intuitive and powerful CLIs for JSON formatters.
Core Principles: Standard I/O and Files
A robust CLI formatter should support reading JSON from multiple sources and writing to multiple destinations. The most fundamental are standard input (stdin) and standard output (stdout), enabling pipeline usage, and direct file input/output.
Standard Input and Output (Piping)
This is arguably the most common use case. A user pipes JSON data from another command into your formatter, and the formatted output is printed to the console or piped to another command. This follows the Unix philosophy of small tools doing one thing well and connecting via pipes.
echo '<!-- Use HTML entity for quote --'{"name":"Alice"}' | your_formatter
cat data.json | your_formatter
curl api.com/data | your_formatter | less
Your formatter should read from stdin if no input file is specified. The formatted output should go to stdout.
File Input and Output
Allowing users to specify input and output files is also crucial.
your_formatter input.json
your_formatter input.json > output.json
your_formatter input.json --output output.json
If an input file is given but no output destination (either stdout implied or explicit output file), write to stdout. If an output file is specified, write to that file.
Avoid In-Place Modification by Default:
While an option for in-place modification ('--write' or '--inplace') can be convenient, it should never be the default behavior as it can lead to accidental data loss or corruption if the formatting fails. Require an explicit flag for this.
Command-Line Options and Flags
Options control how the formatting is performed. Common options for JSON formatters include:
Indentation
This is the most fundamental option. Users should be able to specify the number of spaces or use tabs for indentation.
your_formatter input.json --indent 2 // 2 spaces
your_formatter input.json --indent 4 // 4 spaces (often default)
your_formatter input.json --indent "\\t" // Tab indentation
your_formatter input.json --indent 0 // No indentation (compact output)
A common default is 2 or 4 spaces. 0 or no indent option implies compact output.
Compact Output
A flag to explicitly request the most compact output (no whitespace between tokens, except where required). This is equivalent to '--indent 0'.
your_formatter input.json --compact
Sort Keys
An option to sort keys within JSON objects alphabetically. This helps in comparing different versions of JSON data.
your_formatter input.json --sort-keys
Validation / Check Only
A mode to simply validate if the input is well-formed JSON, without printing any formatted output. This is useful in scripts or CI pipelines. The tool should exit with a status code of 0 for success and a non-zero code for failure.
your_formatter input.json --check
if your_formatter input.json --check; then
echo "Valid JSON";
exit 0;
else
echo "Invalid JSON";
exit 1;
fi
Help and Version Information
Standard flags like '--help' (or '-h') and '--version' (or '-v') should provide usage instructions and the tool's version number, respectively.
Implementation Considerations
Implementing a JSON formatter CLI involves:
- Argument Parsing: Use a library or manually parse 'process.argv' to understand user options and input/output paths.
- Reading Input:If a file is specified, read its content using file system APIs. If no file and stdin is potentially available (e.g., not a TTY), read from 'process.stdin'. Be mindful of large inputs; streaming might be necessary for very big files, though simple formatters often load everything into memory.
- Parsing JSON: Use the built-in 'JSON.parse()' method. Handle potential 'SyntaxError' exceptions.
- Formatting JSON: Use 'JSON.stringify()' with its 'space' argument for indentation. Sorting keys requires iterating over object keys, sorting them, and then rebuilding the object or stringifying with a custom replacer function.
- Writing Output:If an output file is specified, write the formatted string using file system APIs. Otherwise, write to 'process.stdout'.
- Error Handling: Catch parsing errors, file I/O errors, and invalid option usage. Print informative error messages to 'process.stderr' and exit with a non-zero status code.
A simple example of parsing and formatting in JavaScript/TypeScript:
Basic Formatting Logic (Conceptual):
function formatJson(jsonString: string, indent: string | number = 2, sortKeys: boolean = false): string { try { let parsed = JSON.parse(jsonString); if (sortKeys) { // Recursive function to sort keys in objects const sortObjectKeys = (obj: any): any => { if (Array.isArray(obj)) { return obj.map(sortObjectKeys); } else if (typeof obj === 'object' && obj !== null) { const sortedKeys = Object.keys(obj).sort(); const sortedObj: any = {}; for (const key of sortedKeys) { sortedObj[key] = sortObjectKeys(obj[key]); } return sortedObj; } return obj; }; parsed = sortObjectKeys(parsed); } // Use JSON.stringify for pretty-printing return JSON.stringify(parsed, null, indent); } catch (err: unknown) { if (err instanceof SyntaxError) { // err is narrowed to SyntaxError here, safe to access message // FIX: Replace template literal inside string with concatenation to avoid build issue throw new Error('Invalid JSON: ' + err.message); // Extract message and use directly } // Re-throw other errors (err is unknown here) throw err; } } // Example usage within a theoretical CLI script: // const inputJson = readInput(); // Function to read from stdin or file // try { // const formattedJson = formatJson(inputJson, 4, true); // writeOutput(formattedJson); // Function to write to stdout or file // } catch (err: unknown) { // // Need to check type if accessing properties, but console.error accepts unknown // console.error(`Error: ${err instanceof Error ? err.message : String(err)}`); // process.exit(1); // Indicate failure // }
Best Practices and User Experience
- Clear Documentation: Provide comprehensive help text ('--help') and README documentation.
- Consistent Options: Use standard conventions for option names (e.g., '--input', '--output', '--indent').
- Sensible Defaults: Choose reasonable defaults (e.g., 2 or 4 space indentation) when options are not specified.
- Never Fail Silently: Always report errors clearly to the user via stderr and exit codes.
- Handle Edge Cases: Consider empty objects/arrays, large numbers, specific string escapes, etc.
- Performance: For very large files, streaming parsers/formatters might be necessary, although this adds significant complexity.
Conclusion
Designing a good CLI for a JSON formatter involves more than just writing the formatting logic. It requires careful consideration of how users will interact with the tool in different scenarios — from simple manual formatting to integration into automated scripts. By adhering to standard CLI patterns like supporting stdin/stdout, providing clear options for formatting style, and implementing robust error handling, you can create a useful and developer-friendly utility.
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool