> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/unjs/ofetch/llms.txt
> Use this file to discover all available pages before exploring further.

# Automatic JSON Body Handling

> Learn how ofetch automatically stringifies request bodies and sets content-type headers

ofetch automatically handles JSON request bodies for you. When you pass an object or array as the `body` option, ofetch will:

1. Stringify it to JSON
2. Set the `content-type` header to `application/json`
3. Set the `accept` header to `application/json`

## Basic Usage

<CodeGroup>
  ```typescript Automatic JSON theme={null}
  import { ofetch } from 'ofetch'

  // Object body - automatically stringified
  await ofetch('/api/users', {
    method: 'POST',
    body: { name: 'John', age: 30 }
  })
  ```

  ```typescript Array body theme={null}
  import { ofetch } from 'ofetch'

  // Array body - also automatically stringified
  await ofetch('/api/users/bulk', {
    method: 'POST',
    body: [{ name: 'John' }, { name: 'Jane' }]
  })
  ```

  ```typescript Before (native fetch) theme={null}
  // Without ofetch, you have to do this manually
  await fetch('/api/users', {
    method: 'POST',
    headers: {
      'content-type': 'application/json',
      'accept': 'application/json'
    },
    body: JSON.stringify({ name: 'John', age: 30 })
  })
  ```
</CodeGroup>

## Content-Type Detection

ofetch only auto-stringifies when the content is JSON-serializable and you haven't set a different `content-type`:

```typescript theme={null}
// This will NOT be stringified - custom content-type is respected
await ofetch('/api/text', {
  method: 'POST',
  body: '"Hello"',
  headers: { 'content-type': 'text/plain' }
})
```

## What Gets Stringified?

ofetch considers a value JSON-serializable if it's:

* A plain object (`{}`)
* An array (`[]`)
* A primitive (string, number, boolean, null)
* An object with a `.toJSON()` method

The following are **not** stringified:

* `FormData` - sent as-is
* `URLSearchParams` - sent as-is
* `Blob` - sent as-is
* `ArrayBuffer` / typed arrays - sent as-is
* `ReadableStream` - sent as-is

## toJSON() Support

If your object has a `.toJSON()` method, ofetch will automatically call it:

```typescript theme={null}
class User {
  constructor(public name: string, private password: string) {}
  
  toJSON() {
    // Password won't be included
    return { name: this.name }
  }
}

// Only sends { name: 'John' }
await ofetch('/api/users', {
  method: 'POST',
  body: new User('John', 'secret123')
})
```

## Form URL Encoded

You can send form-encoded data by setting the content-type:

```typescript theme={null}
await ofetch('/api/form', {
  method: 'POST',
  headers: { 'content-type': 'application/x-www-form-urlencoded' },
  body: { username: 'john', password: 'secret' }
})
// Sends: username=john&password=secret
```

## Type Definition

From `src/types.ts:27`:

```typescript theme={null}
body?: RequestInit["body"] | Record<string, any>
```

The body can be any standard `RequestInit` body type, or a plain object/array that will be automatically stringified.
