# `dio`

| Package | Kind | Provides the role | Needs | Choose with |
| --- | --- | --- | --- | --- |
| [`smf_dio`](https://pub.dev/packages/smf_dio) | infrastructure | REST API | Values in .env | `-m dio` |

`dio` sends the requests of `appRest`, the REST client of the app, with [dio](https://pub.dev/packages/dio). The code of the app calls `appRest.get('notes')` and knows nothing of the package. What the client guarantees, such as its failures, its repeats and where the token of the user goes, comes from the role and holds with every provider; see [REST API](https://doc.saymyframe.com/guides/rest.md).

The role reads the address of the API from `REST_BASE_URL` in `.env`, so the module brings [`dart_define`](https://doc.saymyframe.com/modules/dart-define.md) while that module is the only provider of the values in `.env`. The role uses the authentication: in an app with it, the client adds the token of the user.

## What it adds to the app

| In the app | What it is |
| --- | --- |
| `dio: ^5.11.1` in the dependencies | The package. In `lib/`, only the file below imports it. |
| `lib/core/rest/dio_rest_transport.dart` | `DioRestTransport`, which implements `RestTransport` of the role on one `Dio`, and `createDio()`, which creates that `Dio` at the first request |
| The section "dio" of the README | What an interceptor may do, and what another adapter needs |

Whichever module provides it, the role adds `lib/core/rest/app_rest.dart`, `lib/core/rest/rest_transport.dart`, `lib/core/rest/session_tokens.dart` in an app with sign-in, the key `REST_BASE_URL`, the section "REST API" of the README, two test files and the permission `android.permission.INTERNET`.

In the [guide for coding agents](https://doc.saymyframe.com/guides/coding-agents.md) of the app, the role describes the client under "REST API". The module adds where the transport is, where an interceptor goes and what it may do.

## An interceptor

`createDio()` is where an interceptor goes, such as one of a tracing service:

```dart
Dio createDio() => Dio()..interceptors.add(TracingInterceptor());
```

- An interceptor that logs leaves out the header `authorization` and the query of the address, where a token or a key may be.
- None repeats a request or follows a redirect. `appRest` does both, since it knows which header may go where.
- What `createDio()` adds to a request goes to every address, also after a redirect and to a full address such as a presigned upload. So a credential goes through the token of the session or `headers:` of the call.

Several `set-cookie` values cannot be told apart in the `headers` of a response, since a value of that header may have a comma. An API with cookies reads them in an interceptor.

## How it sends

The app has one `Dio`, which keeps a connection open while requests follow within seconds, so those requests need no new TLS handshake. It sends each exchange as it is, with no header of `Dio` and no timeout of its own: the client stops each exchange itself.

Dio sends over `dart:io`, which reaches an `http://` address with no key in the Android manifest or in `Info.plist`. Another adapter, such as one of [native_dio_adapter](https://pub.dev/packages/native_dio_adapter) for the stack of the platform, goes into `httpClientAdapter` in `createDio()`. It then needs those keys for an `http://` address.

A stop ends the call at once. It closes the connection too, unless the connection is still being made. A TLS handshake on its way cannot be ended on `dart:io`, and since the module shares one `HttpClient`, neither can a TCP connect on its way: the socket closes once the system ends it.

`HttpClient` decodes a `content-encoding` of exactly `gzip`, and the module then leaves out that header and its `content-length`. A body in any other coding keeps its bytes and those headers.

## In tests

`RestTestServer` of `test/core/rest/rest_test_server.dart`, which the role generates, is a local server for the tests of the app; see [REST API](https://doc.saymyframe.com/guides/rest.md#in-tests). `dio` has no platform side, so a test needs no mocks.

The module keeps a test for what only it does, on the real package: that an exchange reaches `Dio` as it is, that a reply keeps its status and headers, how each error of `Dio` becomes a failure of the role, and what a stop leaves behind on a socket. See [Contributing](https://doc.saymyframe.com/contributing.md#the-roles-at-run-time).

## Choosing it

`smf create` asks which module provides the REST API, and the answer may be none. To choose it without the question:

```bash
smf create my_app -m dio
```
