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

# Java SDK requests, types, and pagination

> Immutable request and response models, uploads, raw responses, and pagination.

## Requests and responses

To send a request to the Telnyx API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.

For example, `client.calls().dial(...)` should be called with an instance of `CallDialParams`, and it will return an instance of `CallDialResponse`.

## Immutability

Each class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.

Each class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.

Because each class is immutable, builder modification will *never* affect already built class instances.

## File uploads

The SDK defines methods that accept files.

To upload a file, pass a [`Path`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html):

```java theme={null}
import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams;
import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse;
import java.nio.file.Paths;

AudioTranscribeParams params = AudioTranscribeParams.builder()
    .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2)
    .file(Paths.get("/path/to/file"))
    .build();
AudioTranscribeResponse response = client.ai().audio().transcribe(params);
```

Or an arbitrary [`InputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html):

```java theme={null}
import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams;
import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse;
import java.net.URL;

AudioTranscribeParams params = AudioTranscribeParams.builder()
    .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2)
    .file(new URL("https://example.com//path/to/file").openStream())
    .build();
AudioTranscribeResponse response = client.ai().audio().transcribe(params);
```

Or a `byte[]` array:

```java theme={null}
import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams;
import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse;

AudioTranscribeParams params = AudioTranscribeParams.builder()
    .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2)
    .file("content".getBytes())
    .build();
AudioTranscribeResponse response = client.ai().audio().transcribe(params);
```

Note that when passing a non-`Path` its filename is unknown so it will not be included in the request. To manually set a filename, pass a [`MultipartField`](https://github.com/team-telnyx/telnyx-java/blob/master/telnyx-core/src/main/kotlin/com/telnyx/sdk/core/Values.kt):

```java theme={null}
import com.telnyx.sdk.core.MultipartField;
import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams;
import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse;
import java.io.InputStream;
import java.net.URL;

AudioTranscribeParams params = AudioTranscribeParams.builder()
    .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2)
    .file(MultipartField.<InputStream>builder()
        .value(new URL("https://example.com//path/to/file").openStream())
        .filename("/path/to/file")
        .build())
    .build();
AudioTranscribeResponse response = client.ai().audio().transcribe(params);
```

## Binary responses

The SDK defines methods that return binary responses, which are used for API responses that shouldn't necessarily be parsed, like non-JSON data.

These methods return [`HttpResponse`](https://github.com/team-telnyx/telnyx-java/blob/master/telnyx-core/src/main/kotlin/com/telnyx/sdk/core/http/HttpResponse.kt):

```java theme={null}
import com.telnyx.sdk.core.http.HttpResponse;
import com.telnyx.sdk.models.ai.clusters.ClusterFetchGraphParams;

HttpResponse response = client.ai().clusters().fetchGraph("task_id");
```

To save the response content to a file, use the [`Files.copy(...)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#copy-java.io.InputStream-java.nio.file.Path-java.nio.file.CopyOption...-) method:

```java theme={null}
import com.telnyx.sdk.core.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

try (HttpResponse response = client.ai().clusters().fetchGraph(params)) {
    Files.copy(
        response.body(),
        Paths.get(path),
        StandardCopyOption.REPLACE_EXISTING
    );
} catch (Exception e) {
    System.out.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

Or transfer the response content to any [`OutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html):

```java theme={null}
import com.telnyx.sdk.core.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Paths;

try (HttpResponse response = client.ai().clusters().fetchGraph(params)) {
    response.body().transferTo(Files.newOutputStream(Paths.get(path)));
} catch (Exception e) {
    System.out.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

## Raw responses

The SDK defines methods that deserialize responses into instances of Java classes. However, these methods don't provide access to the response headers, status code, or the raw response body.

To access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:

```java theme={null}
import com.telnyx.sdk.core.http.Headers;
import com.telnyx.sdk.core.http.HttpResponseFor;
import com.telnyx.sdk.models.numberorders.NumberOrderCreateParams;
import com.telnyx.sdk.models.numberorders.NumberOrderCreateResponse;

NumberOrderCreateParams params = NumberOrderCreateParams.builder()
    .addPhoneNumber(NumberOrderCreateParams.PhoneNumber.builder()
        .phoneNumber("+15558675309")
        .build())
    .build();
HttpResponseFor<NumberOrderCreateResponse> numberOrder = client.numberOrders().withRawResponse().create(params);

int statusCode = numberOrder.statusCode();
Headers headers = numberOrder.headers();
```

You can still deserialize the response into an instance of a Java class if needed:

```java theme={null}
import com.telnyx.sdk.models.numberorders.NumberOrderCreateResponse;

NumberOrderCreateResponse parsedNumberOrder = numberOrder.parse();
```

## Pagination

The SDK defines methods that return a paginated lists of results. It provides convenient ways to access the results either one page at a time or item-by-item across all pages.

### Auto-pagination

To iterate through all results across all pages, use the `autoPager()` method, which automatically fetches more pages as needed.

When using the synchronous client, the method returns an [`Iterable`](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html)

```java theme={null}
import com.telnyx.sdk.models.accessipaddress.AccessIpAddressListPage;
import com.telnyx.sdk.models.accessipaddress.AccessIpAddressResponse;

AccessIpAddressListPage page = client.accessIpAddress().list();

// Process as an Iterable
for (AccessIpAddressResponse accessIpAddress : page.autoPager()) {
    System.out.println(accessIpAddress);
}

// Process as a Stream
page.autoPager()
    .stream()
    .limit(50)
    .forEach(accessIpAddress -> System.out.println(accessIpAddress));
```

When using the asynchronous client, the method returns an [`AsyncStreamResponse`](https://github.com/team-telnyx/telnyx-java/blob/master/telnyx-core/src/main/kotlin/com/telnyx/sdk/core/http/AsyncStreamResponse.kt):

```java theme={null}
import com.telnyx.sdk.core.http.AsyncStreamResponse;
import com.telnyx.sdk.models.accessipaddress.AccessIpAddressListPageAsync;
import com.telnyx.sdk.models.accessipaddress.AccessIpAddressResponse;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

CompletableFuture<AccessIpAddressListPageAsync> pageFuture = client.async().accessIpAddress().list();

pageFuture.thenRun(page -> page.autoPager().subscribe(accessIpAddress -> {
    System.out.println(accessIpAddress);
}));

// If you need to handle errors or completion of the stream
pageFuture.thenRun(page -> page.autoPager().subscribe(new AsyncStreamResponse.Handler<>() {
    @Override
    public void onNext(AccessIpAddressResponse accessIpAddress) {
        System.out.println(accessIpAddress);
    }

    @Override
    public void onComplete(Optional<Throwable> error) {
        if (error.isPresent()) {
            System.out.println("Something went wrong!");
            throw new RuntimeException(error.get());
        } else {
            System.out.println("No more!");
        }
    }
}));

// Or use futures
pageFuture.thenRun(page -> page.autoPager()
    .subscribe(accessIpAddress -> {
        System.out.println(accessIpAddress);
    })
    .onCompleteFuture()
    .whenComplete((unused, error) -> {
        if (error != null) {
            System.out.println("Something went wrong!");
            throw new RuntimeException(error);
        } else {
            System.out.println("No more!");
        }
    }));
```

### Manual pagination

To access individual page items and manually request the next page, use the `items()`,
`hasNextPage()`, and `nextPage()` methods:

```java theme={null}
import com.telnyx.sdk.models.accessipaddress.AccessIpAddressListPage;
import com.telnyx.sdk.models.accessipaddress.AccessIpAddressResponse;

AccessIpAddressListPage page = client.accessIpAddress().list();
while (true) {
    for (AccessIpAddressResponse accessIpAddress : page.items()) {
        System.out.println(accessIpAddress);
    }

    if (!page.hasNextPage()) {
        break;
    }

    page = page.nextPage();
}
```
