# Requests

## Available Request annotations

| Annotation                                 | HTTP verb | Description                                             |
| ------------------------------------------ | --------- | ------------------------------------------------------- |
| `@GET()`, `@get`                           | `GET`     | Defines a `GET` request.                                |
| `@POST()`, `@post`                         | `POST`    | Defines a `POST` request.                               |
| `@PUT()`, `@put`                           | `PUT`     | Defines a `PUT` request.                                |
| `@PATCH()`, `@patch`                       | `PATCH`   | Defines a `PATCH` request.                              |
| `@DELETE()`, `@delete`                     | `DELETE`  | Defines a `DELETE` request.                             |
| `@HEAD()`, `@head`                         | `HEAD`    | Defines a `HEAD` request.                               |
| `@OPTIONS()`, `@options`                   | `OPTIONS` | Defines an `OPTIONS` request.                           |
| `@Path()`, `@path`                         | -         | Defines a dynamic path parameter.                       |
| `@Body()`, `@body`                         | -         | Defines the request's body.                             |
| `@Header()`, `@header`                     | -         | Defines a dynamic request header.                       |
| `@FormUrlEncoded()`, `@formUrlEncoded`     | -         | Defines an `application/x-www-form-urlencoded` request. |
| `@Multipart()`, `@multipart`               | -         | Defines a `multipart/form-data` request.                |
| `@Query()`, `@query`                       | -         | Defines a query parameter.                              |
| `@QueryMap()`, `@queryMap`                 | -         | Defines a query parameter map.                          |
| `@FactoryConverter()`, `@factoryConverter` | -         | Defines a request/response converter factory.           |
| `@Field()`, `@field`                       | -         | Defines a form field.                                   |
| `@FieldMap()`, `@fieldMap`                 | -         | Defines a form field map.                               |
| `@Part()`, `@part`                         | -         | Defines a multipart part.                               |
| `@PartMap()`, `@partMap`                   | -         | Defines a multipart part map.                           |
| `@PartFile()`, `@partFile`                 | -         | Defines a multipart file part.                          |
| `@PartFileMap()`, `@partFileMap`           | -         | Defines a multipart file part map.                      |
| `@Tag()`, `@tag`                           | -         | Defines a tag parameter.                                |
| `@AbortTrigger()`, `@abortTrigger`         | -         | Defines a request cancellation trigger.                 |

## Path resolution

Chopper handles paths passed to HTTP verb annotations' `path` parameter based on the path's content.

If the `path` value is a relative path, it will be concatenated to the URL composed of the `baseUrl` of the `ChopperClient` and the `baseUrl` of the enclosing service class (provided as a parameter of the `@ChopperApi` annotation).

Here are a few examples of the described behavior:

| Variable   | URI                           |
| ---------- | ----------------------------- |
| base URL   | <https://example.com/>        |
| Path       | profile                       |
| **Result** | <https://example.com/profile> |

| Variable         | URI                                 |
| ---------------- | ----------------------------------- |
| base URL         | <https://example.com/>              |
| Service base URL | profile                             |
| Path             | /image                              |
| **Result**       | <https://example.com/profile/image> |

| Variable         | URI                                 |
| ---------------- | ----------------------------------- |
| base URL         | <https://example.com/>              |
| Service base URL | profile                             |
| Path             | image                               |
| **Result**       | <https://example.com/profile/image> |

> Chopper detects and handles missing slash (`/`) characters on URL segment borders, but *does not* handle duplicate slashes.

If the service's `baseUrl` concatenated with the request's `path` results in a full URL, the `ChopperClient`'s `baseUrl` is ignored.

| Variable         | URI                           |
| ---------------- | ----------------------------- |
| base URL         | <https://example.com/>        |
| Service base URL | <https://api.github.com/>     |
| Path             | user                          |
| **Result**       | <https://api.github.com/user> |

A `path` containing a full URL replaces the base URLs of both the `ChopperClient` and the service class entirely for a request.

| Variable   | URI                           |
| ---------- | ----------------------------- |
| base URL   | <https://example.com/>        |
| Path       | <https://api.github.com/user> |
| **Result** | <https://api.github.com/user> |

| Variable         | URI                           |
| ---------------- | ----------------------------- |
| base URL         | <https://example.com/>        |
| Service base URL | profile                       |
| Path             | <https://api.github.com/user> |
| **Result**       | <https://api.github.com/user> |

## Path parameters

Dynamic path parameters can be defined in the URL with replacement blocks. A replacement block is an alphanumeric substring of the path surrounded by `{` and `}`. In the following example `{id}` is a replacement block.

```dart
@GET(path: "/{id}")
```

Use the `@Path()` annotation to bind a parameter to a replacement block. This way the parameter's name must match a replacement block's string.

```dart
@GET(path: "/{id}")
Future<Response> getItemById(@Path() String id);
```

As an alternative, you can set the `@Path` annotation's `name` parameter to match a replacement block's string while using a different parameter name, like in the following example:

```dart
@GET(path: "/{id}")
Future<Response> getItemById(@Path("id") int itemId);
```

> Chopper uses String interpolation to replace replacement blocks with the provided values in the request URLs.

## Query parameters

Dynamic query parameters can be added to the URL by adding parameters to a request method annotated with the `@Query` annotation. Default values are supported.

```dart
Future<Response> search(
    @Query() String name, {
    @Query("count") int numberOfResults = 42,
});
```

If the parameter of the `@Query` annotation is not set, Chopper will use the actual name of the annotated parameter as the key for the query parameter in the URL.

If you prefer to pass a `Map` of query parameters, you can do so with the `@QueryMap` annotation.

```dart
Future<Response> search(@QueryMap() Map<String, dynamic> query);
```

Chopper encodes nested query maps and iterables with `qs_dart`. Repeated query parameters are the default list format:

```dart
@GET(path: "/search")
Future<Response> search(@Query("tag") List<String> tags);

await service.search(["dart", "http"]);
// /search?tag=dart&tag=http
```

Use the HTTP method annotation's `listFormat`, `dateFormat` and `includeNullQueryVars` options when an endpoint needs different query encoding:

```dart
@GET(
  path: "/events",
  listFormat: ListFormat.brackets,
  dateFormat: DateFormat.date,
  includeNullQueryVars: true,
)
Future<Response> events({
  @Query("days") List<int?> days = const [1, null, 3],
  @Query("from") required DateTime from,
});
```

If a query value needs custom serialization before the URL is encoded, configure a `ParameterConverter` on the `ChopperClient`, or use a client converter that also implements `ParameterConverter`. Parameter conversion currently applies to query values only; query keys are left unchanged.

## Request body

Use the `@Body` annotation on a request method parameter to specify data that will be sent as the request's body.

```dart
@POST(path: "todo/create")
Future<Response> postData(@Body() String data);
```

{% hint style="warning" %}
Chopper does not automatically convert `Object`s to `Map` and then `JSON`.

You have to pass a [Converter](/chopper/converters/converters.md) instance to a `ChopperClient` for JSON conversion to happen. See [built\_value\_converter](/chopper/converters/built-value-converter.md#built-value) for an example Converter implementation.
{% endhint %}

## Headers

Request headers can be set by providing a `Map<String, String>` object to the `headers` parameter each of the HTTP verb annotations have.

```dart
@GET(path: "/", headers: {"foo": "bar"})
Future<Response> fetch();
```

The `@Header` annotation can be used on method parameters to set headers dynamically for each request call.

```dart
@GET(path: "/")
Future<Response> fetch(@Header("foo") String bar);
```

> Setting request headers dynamically is also supported by [Interceptors](/chopper/interceptors.md) and [Converters](/chopper/converters/converters.md).
>
> As Chopper invokes Interceptors and Converter(s) *after* creating a Request, Interceptors and Converters *can* override headers set with the `headers` parameter or `@Header` annotations.

## Sending `application/x-www-form-urlencoded` data

If no converter is specified for a request (neither on the `ChopperClient` nor with `@FactoryConverter`) and the request body is a `Map<String, String>`, the body will be sent as form URL encoded data.

> This is the default behavior of the http package.

### FormUrlEncoded annotation

Use `@FormUrlEncoded()` or `@formUrlEncoded` on a method to add the correct `content-type` and convert a `Map` into `Map<String, String>` for requests.

```dart
@POST(path: "form")
@FormUrlEncoded()
Future<Response> postForm(@Body() Map<String, String> fields);
```

### FormUrlEncodedConverter

You can also use `FormUrlEncodedConverter` to add the correct `content-type` and convert a `Map` into `Map<String, String>` for requests.

```dart

final chopper = ChopperClient(
  converter: FormUrlEncodedConverter(),
);
```

To do only a single type of request with form encoding in a service, use the provided `FormUrlEncodedConverter.requestFactory` method with the `@FactoryConverter` annotation.

```dart
@POST(
  path: "form",
  headers: {contentTypeKey: formEncodedHeaders},
)
@FactoryConverter(request: FormUrlEncodedConverter.requestFactory)
Future<Response> postForm(@Body() Map<String, String> fields);
```

### Defining fields individually

To specify fields individually, use the `@Field` annotation on method parameters. If the field's name is not provided, the parameter's name is used as the field's name.

```dart
@POST(path: "form")
@FormUrlEncoded()
Future<Response> post(@Field() String foo, @Field("b") int bar);
```

## Sending files with `@Multipart`

### Sending a file in bytes as `List<int>` using `@PartFile`

```dart
@POST(path: 'file')
@Multipart()
Future<Response> postFile(@PartFile('file') List<int> bytes);
```

### Sending a file as `MultipartFile` using `@PartFile` with extra parameters via `@Part`

```dart
@POST(path: 'file')
@Multipart()
Future<Response> postMultipartFile(
  @PartFile() MultipartFile file,
  {
    @Part() String? id,
  },
);
```

### Sending multiple files as `List<MultipartFile>` using `@PartFile`

```dart
@POST(path: 'files')
@Multipart()
Future<Response> postListFiles(@PartFile() List<MultipartFile> files);
```

## Defining responses

ChopperService methods need to return a `Future`. It is possible to define return types of `Future<Response>` or `Future<Response<T>>` where `T` is the type of the response body. When `Response` is not needed for a request, it is also possible to define a return type of `Future<T>` where `T` is the type of the response body.

Chopper will generate a client which returns the specified return type. When the method does not directly return `Response`, Chopper returns `response.bodyOrThrow`; unsuccessful responses throw the response error when it is an `Exception`, otherwise a `ChopperHttpException`. A successful response whose converted body is `null` also throws a `ChopperHttpException`; use `Future<Response<T>>` and read `response.body` directly for endpoints where a successful `null` body is expected, such as HTTP 204/no-content responses.

```dart
// Returns a Response<dynamic>
@GET(path: "/")
Future<Response> fetch();

// Returns a Response<MyClass>
@GET(path: "/")
Future<Response<MyClass>> fetch();

// Returns a MyClass
@GET(path: "/")
Future<MyClass> fetch();
```

> Note: Chopper doesn't convert response bodies by itself to Dart objects. You need to use a [Converter](/chopper/converters/converters.md) for that.

## Add tag

Use the `@Tag()` parameter annotation to set `request.tag` on the underlying Chopper `Request`. Tags can be read in `Converter`s or `Interceptor`s for tracing, analytics, varying behavior, and more.

For example, a converter can use a tag to decide whether null or empty body values should be included for one request.

```dart
class IncludeBodyNullOrEmptyTag {
  const IncludeBodyNullOrEmptyTag({
    this.includeNull = false,
    this.includeEmpty = false,
  });

  final bool includeNull;
  final bool includeEmpty;
}

@GET(path: '/include')
Future<Response> includeBodyNullOrEmptyTag({
  @Tag() IncludeBodyNullOrEmptyTag tag = const IncludeBodyNullOrEmptyTag(),
});
```

Read the tag via `request.tag` in a `Converter` or `Interceptor`:

```dart
class TagConverter extends JsonConverter {
  @override
  Request convertRequest(Request request) {
    final tag = request.tag;
    if (tag is IncludeBodyNullOrEmptyTag) {
      if (request.body is Map) {
        final Map body = request.body as Map;
        final Map bodyCopy = {};
        for (final MapEntry entry in body.entries) {
          if (!tag.includeNull && entry.value == null) continue;
          if (!tag.includeEmpty && entry.value == "") continue;
          bodyCopy[entry.key] = entry.value;
        }
        request = request.copyWith(body: bodyCopy);
      }
    }
    return super.convertRequest(request);
  }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://hadrien-lejard.gitbook.io/chopper/requests.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
