Конфигурация
Каждый параметр клиента, что он читает из окружения и что отклоняет.
Опции
using var http = new HttpClient(); var client = new OpenEmailClient(new OpenEmailOptions{ ApiKey = Environment.GetEnvironmentVariable("OPENEMAIL_API_KEY"), BaseUrl = "https://api.openemail.uk", Timeout = TimeSpan.FromSeconds(30), MaxRetries = 2, HttpClient = http, Headers = { ["X-Team"] = "billing" },}); Console.WriteLine($"{client.Mode} {client.Raw.BaseUrl}");| Опция | Что делает |
|---|---|
| ApiKey | API-ключ рабочего пространства, который начинается с oe_live_ или oe_test_. |
| AccessToken | Токен доступа OAuth для приложения, которое подключил человек. Передайте ключ или токен, но не оба. |
| AccessTokenProvider | Функция, возвращающая токен доступа. Она выполняется перед каждым запросом, поэтому именно здесь стоит обновлять токен. |
| BaseUrl | Источник API. К голому хосту, такому как localhost:2222, добавляется схема. |
| HttpClient | HttpClient, который уже есть в вашем приложении, например полученный из IHttpClientFactory или с тестовым обработчиком. Клиент никогда его не освобождает. |
| Timeout | Сколько может длиться одна попытка. По умолчанию 30 секунд, TimeSpan.Zero отключает ограничение, а загрузки ждут не меньше десяти минут. |
| MaxRetries | Сколько раз повторяется неудавшийся запрос. По умолчанию 2, а 0 отправляет один раз. |
| UserAgent | Заменяет заголовок User-Agent, который состоит из openemail-dotnet/ и версии. |
| Headers | Заголовки, которые добавляются к каждому запросу. |
Всё, что вы не указали, читается из окружения: OPENEMAIL_API_KEY, затем OPENEMAIL_ACCESS_TOKEN и OPENEMAIL_BASE_URL. client.Mode сообщает, какой это ключ: live или test.
Отмена и таймауты
Каждый метод последним принимает CancellationToken. Его отмена сразу останавливает вызов вместе с повторами и вызывает OperationCanceledException, тогда как Timeout ограничивает каждую попытку.
using var deadline = new CancellationTokenSource(TimeSpan.FromSeconds(10)); var thread = await client.Threads.GetAsync("CAHk7pQ2x9LmZ4-mail.example.com", cancellationToken: deadline.Token); Console.WriteLine(thread["messageCount"]);Параметры вызова
Параметры запроса и настройки вызова передаются именованными аргументами под именами API, например limit:, cursor: и idempotencyKey:. Каждый метод принимает apiKey:, чтобы действовать с другим ключом только в этом вызове, поэтому один процесс может обслуживать несколько рабочих пространств одним клиентом.
var page = await client.Emails.ListAsync( status: new[] { "failed", "bounced" }, limit: 50, apiKey: Environment.GetEnvironmentVariable("OTHER_WORKSPACE_KEY")); Console.WriteLine($"{page.Count} {page.HasMore}");Токены доступа OAuth
Приложение, которое человек подключил через OAuth, хранит токен доступа вместо API-ключа. Передайте его как AccessToken или передайте AccessTokenProvider и обновляйте токен там, когда срок его действия подходит к концу, чтобы клиент никогда не приходилось создавать заново.
var current = "token-from-your-oauth-flow"; var client = new OpenEmailClient(new OpenEmailOptions{ AccessTokenProvider = _ => Task.FromResult(current),}); var me = await client.Me.GetAsync(); Console.WriteLine(me["workspaceId"]);ASP.NET Core
Зарегистрируйте один клиент на всё приложение. У него нет собственного соединения, которое нужно освобождать, поэтому синглтон является правильным временем жизни.
using OpenEmail; var builder = WebApplication.CreateBuilder(args); builder.Services.AddSingleton(new OpenEmailClient(new OpenEmailOptions{ ApiKey = builder.Configuration["OpenEmail:ApiKey"],})); var app = builder.Build(); app.MapPost("/invoices/{number}/send", async (string number, OpenEmailClient client, CancellationToken cancellationToken) =>{ var sent = await client.Emails.SendAsync(new Body { ["from"] = "[email protected]", ["to"] = "[email protected]", ["subject"] = $"Invoice {number}", ["text"] = "The invoice is attached.", }, idempotencyKey: $"invoice-{number}", cancellationToken: cancellationToken); return Results.Ok(new { id = (string?)sent["id"] });}); app.Run();Что клиент отклоняет
- Ключ, который не начинается с
oe_live_илиoe_test_, и ключ вместе с токеном доступа. - Отправку учётных данных по обычному
http:, если только сервер не находится на этой машине по адресуlocalhost,127.x.x.xили::1. - Базовый URL на
0.0.0.0, то есть на адресе, который сервер слушает. Используйте127.0.0.1с тем же портом. - Пустой идентификатор или состоящий только из точек, который парсер URL удалил бы.
- Переход по перенаправлению. HTTP-клиент, который создаёт пакет, никогда по нему не переходит, поэтому учётные данные никогда не уходят на другой хост.
Вывод клиента или исключения никогда не показывает учётные данные. ToString() у клиента возвращает его режим и базовый URL и больше ничего.
Конечная точка без метода
client.Raw.RequestAsync() вызывает любой путь с учётными данными, базовым URL, таймаутом и правилами повторов клиента. Путь должен начинаться с одного /, а путь, покидающий источник базового URL, отклоняется.
var label = await client.Raw.RequestAsync("/labels", "POST", body: new Body { ["name"] = "Invoices" }); Console.WriteLine(label?["id"]);