Skip to content

Add --format json option for HTTP trigger route output#3429

Merged
itowlson merged 5 commits intospinframework:mainfrom
ChihweiLHBird:zhiwei/http-trigger-json-output
Mar 25, 2026
Merged

Add --format json option for HTTP trigger route output#3429
itowlson merged 5 commits intospinframework:mainfrom
ChihweiLHBird:zhiwei/http-trigger-json-output

Conversation

@ChihweiLHBird
Copy link
Contributor

@ChihweiLHBird ChihweiLHBird commented Mar 22, 2026

Resolve #949
I am a beginner for Rust, so do let me know if there is any better approach in the code I may take.

Summary

  • Add a --format CLI flag to the HTTP trigger that supports plain (default) and json output formats
  • When --format json is specified, route and listener information is printed to stdout as machine-readable JSON instead of human-readable text
  • Move diagnostic println! calls (runtime config, stdio logging, key-value/SQLite summaries) to eprintln! so stdout remains clean for structured output

Test

  • Added integration test (http_smoke_test_json_format) that verifies JSON output is valid and contains expected fields (routes, listeners)
  • Manual test: spin up --format json prints JSON to stdout
  • Manual test: spin up (no flag) behaves as before with plain text output

Sample test outputs

spin up --format json

Note that Logging component stdio to ".spin/logs/" is shown on screen but it's not in stdout. We can use /path/to/spin/target/release/spin up --format json > out.txt to verify it

Logging component stdio to ".spin/logs/"
{
  "base_url": "http://127.0.0.1:3000",
  "routes": [
    {
      "id": "test-spin-rust",
      "url": "http://127.0.0.1:3000",
      "route": ""
    },
    {
      "id": "api",
      "url": "http://127.0.0.1:3000/api (wildcard)",
      "route": "/api (wildcard)"
    }
  ]
}

spin up

Logging component stdio to ".spin/logs/"

Serving http://127.0.0.1:3000
Available Routes:
  test-spin-rust: http://127.0.0.1:3000
  api: http://127.0.0.1:3000/api (wildcard)

…nd summary hooks

Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
Copilot AI review requested due to automatic review settings March 22, 2026 19:05
@ChihweiLHBird ChihweiLHBird changed the title Add --format json option for HTTP trigger route output Add --format json option for HTTP trigger route output Mar 22, 2026
Copy link

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

Adds a --format flag to the HTTP trigger to support machine-readable startup output, while shifting various diagnostic messages to stderr to keep stdout clean for structured output consumers.

Changes:

  • Introduce --format {plain,json} for the HTTP trigger and plumb OutputFormat through trigger/server construction.
  • Emit startup route information as JSON when --format json is used (instead of human-readable text).
  • Move several previously-stdout diagnostic prints (runtime config, stdio logging, KV/SQLite summaries) to stderr and add an integration test that validates JSON stdout.

Reviewed changes

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

Show a summary per file
File Description
tests/testing-framework/src/runtimes/in_process_spin.rs Updates in-process HTTP trigger initialization to pass the new OutputFormat parameter.
tests/integration.rs Adds an integration test ensuring spin up --format json produces valid JSON with expected route fields.
crates/trigger/src/cli/summary.rs Redirects KV/SQLite “storing default …” summaries from stdout to stderr.
crates/trigger/src/cli/stdio.rs Redirects stdio logging directory message from stdout to stderr.
crates/trigger-http/src/server.rs Implements the JSON vs plain startup output switch and JSON schema emission.
crates/trigger-http/src/lib.rs Defines OutputFormat and adds --format flag to HTTP trigger CLI args; wires it into server startup.
crates/runtime-config/src/lib.rs Redirects runtime config summary from stdout to stderr.

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

@ChihweiLHBird ChihweiLHBird force-pushed the zhiwei/http-trigger-json-output branch from ba0c3d8 to a5b7235 Compare March 22, 2026 21:14
Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
@ChihweiLHBird ChihweiLHBird force-pushed the zhiwei/http-trigger-json-output branch from a5b7235 to 7b4dba6 Compare March 22, 2026 21:35
@ChihweiLHBird ChihweiLHBird requested a review from itowlson March 22, 2026 21:39
@itowlson itowlson requested review from rajatjindal and removed request for itowlson March 22, 2026 22:30
@itowlson
Copy link
Collaborator

Thanks for posting the output @ChihweiLHBird.

    {
      "id": "api",
      "url": "http://127.0.0.1:3000/api (wildcard)",
      "route": "/api (wildcard)"
    }

I'd value @rajatjindal's input on this, but my own thoughts are:

  1. (wildcard) is human formatting, not machine-readable. We could either:
    a. Ignore it: { route: "/api" }
    b. Create a separate field for it: { route: "/api", is_wildcard: true } (I think this is my preferred option but open to feedback)
    c. Something else?
  2. I'm not sure there is value in having both url and route. In the terminal output we print the URL so that it's convenient for the user to click, but that's not a concern in JSON. If consumers want the full URL they can combine base_url and route. But again I'd value Rajat's feedback here.

Copy link
Collaborator

@itowlson itowlson left a comment

Choose a reason for hiding this comment

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

This looks good to me, just a couple of suggestions in the review plus that (wildcard) thing from discussion. Thanks!


let base_url = parsed["base_url"]
.as_str()
.context(format!("JSON output missing 'base_url' string field\nGot: {parsed}"))?;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The repeated "Got {parsed}" part of this context could, I think, be added outside the helper (you can dump the stdout string, no need to rely on it being parsed). Like on line 145 check_json().with_context(|| format!("Actual output: {stdout}")?. (You might need to make check_json a true function rather than a closure, and pass the text in, to avoid lifetime issues.)

Copy link
Contributor Author

@ChihweiLHBird ChihweiLHBird Mar 23, 2026

Choose a reason for hiding this comment

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

I think it works with the closure. I just updated it in df789dd. Is there any lifetime issues I'm not aware of?

…ardcode `/` for root route

Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
@ChihweiLHBird ChihweiLHBird force-pushed the zhiwei/http-trigger-json-output branch from 18d6ca6 to c46cfbf Compare March 23, 2026 03:34
Signed-off-by: Zhiwei Liang <zhiwei.liang@zliang.me>
@ChihweiLHBird ChihweiLHBird requested a review from itowlson March 23, 2026 06:59
Copy link
Collaborator

@itowlson itowlson left a comment

Choose a reason for hiding this comment

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

Looks good to me - thanks! I'll give it a little longer for @rajatjindal to provide feedback, but will then merge.

@rajatjindal
Copy link
Member

I tried out this PR on my laptop, and it works great. Thank you for making those changes.

one thing I realized while testing is that with spin up, the app is started and hence the json output that we get is still on stdout console, which means if we started in e.g. GitHub actions, we need to start spin up in background and then parse the logs.

do you think it will be helpful to print this info on stdout as well as put this in a .spin/routeinfo.json or something like that?

IIRC, my original usecase was around implementing GitHub actions for Fermyon Cloud, in which case we will usually do spin cloud deploy, in which case the control is given back to terminal after deployment finishes.

In the current shape, if we were to do a deploy using some cloud plugin, will it still print this json info on console, or that depends on implementation of that specific cloud plugin?

@itowlson
Copy link
Collaborator

@rajatjindal It will depend on the implementation of the deployment plugin. Deployment plugins don't invoke spin up or the trigger.

@itowlson itowlson merged commit 3a060bb into spinframework:main Mar 25, 2026
17 checks passed
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.

providing spin routes and url info in json format

4 participants