Volga
Home
API Docs
GitHub
  • English
  • Русский
Home
API Docs
GitHub
  • English
  • Русский
  • Home
  • Getting Started

    • Quick Start
    • Route Parameters
    • Query Parameters
    • Route Groups
  • Requests & Responses

    • Headers
    • Handling JSON
    • Handling Form Data
    • Working with Files
    • Cookies
  • Middleware & Infrastructure

    • Basic Middleware
    • Custom Middleware
    • Response Compression
    • Request Decompression
    • CORS (Cross-Origin Resource Sharing)
    • Static Files
    • Rate Limiting
  • Security & Access

    • Authentication and Authorization
  • Reliability & Observability

    • Global Error Handling
    • Tracing & Logging
    • Request cancellation
  • Protocols & Realtime

    • HTTP/1 and HTTP/2
    • HTTPS
    • WebSockets
    • Server-Sent Events (SSE)
  • Advanced Patterns

    • Dependency Injection
    • Custom Handling of HEAD, OPTIONS, and TRACE Methods

Handling JSON

Volga simplifies the process of dealing with JSON data in your web applications, both for ingesting incoming JSON payloads in requests and sending JSON responses.

Receiving JSON Data

To accept a JSON body in a request and deserialize it into a strongly-typed entity, use the Json<T> struct. Where T should be a deserializable struct, so ensure it derives from Deserialize from serde:

use volga::{App, Json, ok};
use serde::Deserialize;
 
#[derive(Deserialize)]
struct User {
    name: String,
    age: i32
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();

    // POST /hello
    // { name: "John", age: 35 }
    app.map_post("/hello", |user: Json<User>| async move {
        ok!("Hello {}!", user.name)
    });

    app.run().await
}

To test this endpoint, you can use the curl command like this:

curl -X POST "http://127.0.0.1:7878/hello" -H "Content-Type: application/json" -d '{ "name": "John", "age": 35 }'
Hello John!

Tips

You can wrap your struct fields into Option<T> as described in Optional Query Params

Sending JSON Responses

To send responses as JSON, Volga provides the ok! macro

use volga::{App, ok};
use serde::Serialize;
 
#[derive(Serialize)]
struct User {
    name: String,
    age: i32
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();

    app.map_get("/hello", || async {
        let user: User = User {
            name: "John".into(),
            age: 35
        };

        ok!(user)
    });

    app.run().await
}

To see the JSON response in action:

> curl http://127.0.0.1:7878/hello
{"name":"John","age":35}

Moreover, with the ok! macro you can also use the untyped JSON:

use volga::{App, ok};

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();

    app.map_get("/hello", || async {
        ok!({ name: "John", age: 35 })
    });

    app.run().await
}

Using Status with JSON

You can also include HTTP status codes in your JSON responses using the status! macro:

use volga::{App, status};
use serde::Serialize;
 
#[derive(Serialize)]
struct User {
    name: String,
    age: i32
}

#[tokio::main]
async fn main() -> std::io::Result<()> {
    let mut app = App::new();

    app.map_get("/hello", || async {
        let user: User = User {
            name: "John".into(),
            age: 35
        };

        status!(200, user)
    });

    app.run().await
}

The JSON body can be coupled with standard HTTP statuses such as 200, 400, 401, 403 and others to provide clear client-side messages.

Here is the full example

Last Updated: 1/18/26, 6:33 PM
Prev
Headers
Next
Handling Form Data