# IPATool HTTP Client Response Formats: JSON, RAW, and XML Explained

> Explore IPATool HTTP client response formats JSON, RAW, and XML. Decode server replies into Go structs, raw bytes, or plist structures for flexible data handling.

- Repository: [Majd/ipatool](https://github.com/majd/ipatool)
- Tags: api-reference
- Published: 2026-08-31

---

**The IPATool HTTP client supports three distinct response formats—JSON, RAW, and XML—allowing developers to decode server replies into typed Go structs, raw byte slices, or Apple Property List (plist) structures.**

The `majd/ipatool` repository implements a generic HTTP client (`Client[R]`) that adapts its decoding strategy based on the `ResponseFormat` field specified in each request. This design enables seamless interaction with Apple's App Store APIs, which return a mix of JSON metadata and binary plist responses.

## Supported Response Formats

The IPATool HTTP client provides three format identifiers defined in [`pkg/http/constants.go`](https://github.com/majd/ipatool/blob/main/pkg/http/constants.go). Each format determines how the raw HTTP body is processed before being returned to the caller.

### JSON Format (`ResponseFormatJSON`)

When using **JSON format**, the client unmarshals the response body into the generic type `R` using Go's standard `json.Unmarshal`. This is the default choice for REST API interactions that return structured data.

In [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go), the `handleJSONResponse` method reads the entire response body and attempts to decode it into the requested type. If the JSON is malformed or cannot map to the generic type `R`, the error propagates back to the caller.

### RAW Format (`ResponseFormatRaw`)

The **RAW format** returns the unprocessed `[]byte` slice directly from the HTTP response body without any parsing or unmarshaling. This format is strictly constrained: the generic type `R` must be `[]byte`, or the client returns an error stating *"raw response format requires a []byte result type"*.

According to the source in [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go) (lines 49-58), this guard clause prevents type mismatches when callers attempt to use RAW mode with incompatible struct types. RAW mode is ideal for downloading binary files or when you need to process the response body manually.

### XML Format (`ResponseFormatXML`)

The **XML format** handles Apple's XML Property List (plist) responses, which are common in App Store authentication and purchase flows. Rather than generic XML parsing, this format specifically expects plist-encoded data.

In [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go) (lines 42-46), the `handleXMLResponse` method normalizes the XML payload, verifies it resembles a valid plist structure, and unmarshals it using `plist.Unmarshal`. If the payload is not a valid plist, the client wraps the error in an `UnexpectedResponseError` with descriptive context.

## How the Client Selects Response Handlers

During request execution in [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go), the client evaluates the `ResponseFormat` field of the `Request` struct to determine which handler to invoke:

```go
if req.ResponseFormat == ResponseFormatJSON {
    return c.handleJSONResponse(res)
}
if req.ResponseFormat == ResponseFormatRaw {
    return c.handleRawResponse(res)
}
if req.ResponseFormat == ResponseFormatXML {
    return c.handleXMLResponse(res)
}

```

If the `ResponseFormat` value does not match any of the three supported constants, the client returns an error: *"content type is not supported"*. This explicit routing ensures type-safe decoding based on the expected response structure.

## Source Code Structure

Understanding the implementation requires examining three key files in the `pkg/http` package:

### Constants Definition ([`pkg/http/constants.go`](https://github.com/majd/ipatool/blob/main/pkg/http/constants.go))

This file declares the `ResponseFormat` type as a string alias and defines the three exported constants: `ResponseFormatJSON`, `ResponseFormatRaw`, and `ResponseFormatXML` (lines 6-8). These constants are used both by the client implementation and by consumers of the API when constructing requests.

### Client Implementation ([`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go))

The core logic resides here, implementing the generic `Client[R]` struct and its `Send` method. This file contains the three handler methods—`handleJSONResponse`, `handleRawResponse`, and `handleXMLResponse`—along with the type validation logic for the RAW format (lines 42-58).

### Request Configuration ([`pkg/http/request.go`](https://github.com/majd/ipatool/blob/main/pkg/http/request.go))

The `Request` struct defined here includes the `ResponseFormat` field, allowing callers to specify their expected response type on a per-request basis. This design makes the client flexible enough to handle different endpoint types within the same session.

## Practical Usage Examples

The following examples demonstrate how to configure the IPATool HTTP client for each response format.

### JSON Response Handling

Use this approach when consuming REST endpoints that return JSON metadata:

```go
package main

import (
    "fmt"
    "github.com/majd/ipatool/pkg/http"
)

func fetchJSON() {
    client := http.NewClient[map[string]any](http.Args{})
    req := http.Request{
        Method:         http.MethodGET,
        URL:            "https://example.com/api/json",
        ResponseFormat: http.ResponseFormatJSON,
    }
    res, err := client.Send(req)
    if err != nil {
        panic(err)
    }
    fmt.Printf("JSON data: %+v\n", res.Data)
}

```

### RAW Binary Response Handling

Use this when downloading binary data or when you need to inspect the raw HTTP body:

```go
package main

import (
    "fmt"
    "github.com/majd/ipatool/pkg/http"
)

func fetchRaw() {
    // Note: Generic type must be []byte for RAW format
    client := http.NewClient[[]byte](http.Args{})
    req := http.Request{
        Method:         http.MethodGET,
        URL:            "https://example.com/api/raw",
        ResponseFormat: http.ResponseFormatRaw,
    }
    res, err := client.Send(req)
    if err != nil {
        panic(err)
    }
    fmt.Printf("Raw bytes length: %d\n", len(res.Data))
}

```

### XML Property List Handling

Use this for Apple-specific endpoints returning plist-encoded data:

```go
package main

import (
    "fmt"
    "github.com/majd/ipatool/pkg/http"
    "github.com/majd/ipatool/pkg/http/payload"
)

func fetchXML() {
    client := http.NewClient[map[string]any](http.Args{})
    req := http.Request{
        Method:         http.MethodPOST,
        URL:            "https://example.com/api/xml",
        Payload:        payload.NewJSON(map[string]string{"foo": "bar"}),
        ResponseFormat: http.ResponseFormatXML,
    }
    res, err := client.Send(req)
    if err != nil {
        panic(err)
    }
    fmt.Printf("XML-decoded data: %+v\n", res.Data)
}

```

## Error Handling and Constraints

Each response format enforces specific constraints that trigger errors if violated:

- **RAW format type safety**: If the generic type `R` is not `[]byte`, the client immediately returns an error before making the HTTP request.
- **XML plist validation**: If the response body cannot be parsed as a valid plist, the client returns an `UnexpectedResponseError` wrapping the underlying plist parsing failure.
- **Unsupported formats**: Supplying an unrecognized `ResponseFormat` value results in a *"content type is not supported"* error.

These strict validations prevent runtime type assertion panics and ensure that decoding errors are caught early in the response lifecycle.

## Summary

- The IPATool HTTP client supports **JSON**, **RAW**, and **XML** response formats, defined as constants in [`pkg/http/constants.go`](https://github.com/majd/ipatool/blob/main/pkg/http/constants.go).
- **JSON** unmarshals into generic type `R` using standard Go JSON parsing, suitable for REST APIs.
- **RAW** returns unprocessed `[]byte` slices but requires the client to be instantiated with `[]byte` as the generic type parameter.
- **XML** specifically handles Apple plist responses using `plist.Unmarshal` and validates the payload structure before decoding.
- The client selects handlers via explicit conditional checks in [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go) based on the `Request.ResponseFormat` field.

## Frequently Asked Questions

### What happens if I use RAW format with a non-byte generic type?

The client returns an immediate error stating *"raw response format requires a []byte result type"* without executing the HTTP request. This guard clause in [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go) (lines 49-58) ensures type safety by validating the generic parameter `R` against `[]byte` during the request preparation phase.

### Can I extend the client to support additional response formats?

The current implementation in [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go) uses a hardcoded conditional chain to select between JSON, RAW, and XML handlers. Adding new formats would require modifying the source code to define a new constant in [`constants.go`](https://github.com/majd/ipatool/blob/main/constants.go), implement a corresponding handler method in [`client.go`](https://github.com/majd/ipatool/blob/main/client.go), and update the conditional logic in the `Send` method to route to the new handler.

### Why does the XML format use plist-specific parsing instead of generic XML?

Apple's App Store and iTunes APIs frequently return XML Property Lists (plists) rather than standard XML documents. The `handleXMLResponse` method in [`pkg/http/client.go`](https://github.com/majd/ipatool/blob/main/pkg/http/client.go) specifically uses `plist.Unmarshal` because the tool primarily interacts with Apple's proprietary endpoints. Generic XML parsing would fail to properly decode these plist-specific data types and structures.

### Is there a performance difference between RAW and JSON formats?

RAW format avoids the CPU overhead of JSON unmarshaling and memory allocation for intermediate structures, making it faster for large payloads or binary data. However, for small JSON responses, the difference is negligible. Choose RAW when you need the raw bytes for file downloads or custom parsing, and JSON when you need structured data mapped to Go types.