mirror of
https://github.com/alexhopeoconnor/binarylane-dotnet.git
synced 2026-10-04 02:18:11 +10:00
Initial BinaryLane v2 API client
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
# Server actions
|
||||
|
||||
Use a typed `ServerAction` to submit a server action. For example, this powers
|
||||
on a server:
|
||||
|
||||
```csharp
|
||||
using BinaryLane.Api.V2.Models;
|
||||
|
||||
var submission = await client.Servers.SubmitActionAsync(
|
||||
serverId,
|
||||
new PowerOnServerAction(),
|
||||
cancellationToken);
|
||||
```
|
||||
|
||||
Common action types include `PowerOnServerAction`, `PowerOffServerAction`,
|
||||
`RebootServerAction`, `ResizeServerAction`, and `RebuildServerAction`.
|
||||
|
||||
## Waiting for completion
|
||||
|
||||
BinaryLane can accept an action before it has finished. When the response
|
||||
contains an action, use its identifier to wait for the final status:
|
||||
|
||||
```csharp
|
||||
if (submission.Action is { } action)
|
||||
{
|
||||
var completed = await client.Actions.WaitForCompletionAsync(
|
||||
action.Id,
|
||||
cancellationToken: cancellationToken);
|
||||
}
|
||||
```
|
||||
|
||||
Pass `ActionWaitOptions` when you need a different timeout or polling interval.
|
||||
The default is a 15-minute timeout with a two-second polling interval.
|
||||
|
||||
## Status values
|
||||
|
||||
`BinaryLaneAction.Status` and `BinaryLaneAction.Type` are strings. Compare a
|
||||
documented value with `BinaryLaneValues`:
|
||||
|
||||
```csharp
|
||||
if (action.Status == BinaryLaneValues.ActionStatus.Completed)
|
||||
{
|
||||
// Continue with the next step.
|
||||
}
|
||||
```
|
||||
|
||||
If an action request has an uncertain outcome, retrieve the action or server
|
||||
state before submitting it again.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Maintainer guide: API coverage
|
||||
|
||||
This is a maintainer reference. Package consumers can start with the
|
||||
[README](../README.md).
|
||||
|
||||
The SDK's scope is the BinaryLane v2 OpenAPI contract committed at
|
||||
`eng/openapi/binarylane-v2.openapi.yaml`. The raw contract currently declares
|
||||
version `0.39.1`; it is a developer-preview contract and may change without a
|
||||
version change.
|
||||
|
||||
The raw document contains virtual paths such as
|
||||
`/v2/servers/{server_id}/actions#PowerOn`. These are API-reference aliases for
|
||||
action payload variants, not real HTTP routes. Coverage and generated-code
|
||||
checks must use the normalized contract and count only the real
|
||||
`POST /v2/servers/{server_id}/actions` route.
|
||||
|
||||
| API area | Public resource boundary |
|
||||
| --- | --- |
|
||||
| Account | `IAccountApi` |
|
||||
| Balances, invoices, and unpaid invoices | `IBillingApi` |
|
||||
| Actions | `IActionsApi` |
|
||||
| Servers and server subresources | `IServersApi` |
|
||||
| Images | `IImagesApi` |
|
||||
| SSH keys | `ISshKeysApi` |
|
||||
| DNS domains, nameservers, and records | `IDomainsApi` |
|
||||
| Load balancers and forwarding rules | `ILoadBalancersApi` |
|
||||
| VPCs and members | `IVpcsApi` |
|
||||
| Regions, sizes, and software catalogues | `IRegionsApi`, `ISizesApi`, `ISoftwareApi` |
|
||||
| Reverse names | `IReverseNamesApi` |
|
||||
| Data usage | `IDataUsageApi` |
|
||||
| Sample sets | `ISampleSetsApi` |
|
||||
|
||||
Keep this table and the related tests up to date when API support changes.
|
||||
@@ -0,0 +1,72 @@
|
||||
# Configuration
|
||||
|
||||
## Standard registration
|
||||
|
||||
In an ASP.NET Core or generic-host application, `AddBinaryLaneApi` configures
|
||||
`IBinaryLaneClient` and the individual resource interfaces.
|
||||
|
||||
```csharp
|
||||
builder.Services.AddBinaryLaneApi(options =>
|
||||
{
|
||||
options.ApiToken = builder.Configuration["BinaryLane:ApiToken"];
|
||||
options.RequestTimeoutSeconds = 100;
|
||||
});
|
||||
```
|
||||
|
||||
| Setting | Default | Description |
|
||||
| --- | --- | --- |
|
||||
| `BaseUrl` | `https://api.binarylane.com.au/` | API base address. Leave unchanged for BinaryLane's public API. |
|
||||
| `ApiToken` | none | Bearer token used by the default provider. |
|
||||
| `RequestTimeoutSeconds` | `100` | Timeout for an individual HTTP request. |
|
||||
|
||||
The base URL must be an HTTPS URL without credentials, a query string, or a
|
||||
fragment. Options are validated when the application starts.
|
||||
|
||||
## Rotating tokens
|
||||
|
||||
Register `IBinaryLaneTokenProvider` before calling `AddBinaryLaneApi` when the
|
||||
token comes from a vault or changes during the lifetime of the application.
|
||||
`VaultTokenProvider` below is your implementation of that interface.
|
||||
|
||||
```csharp
|
||||
using BinaryLane.Api.V2.Authentication;
|
||||
using BinaryLane.Api.V2.DependencyInjection;
|
||||
|
||||
builder.Services.AddSingleton<IBinaryLaneTokenProvider, VaultTokenProvider>();
|
||||
builder.Services.AddBinaryLaneApi(options => options.RequestTimeoutSeconds = 100);
|
||||
```
|
||||
|
||||
The provider is called for every request. Do not log the returned token.
|
||||
|
||||
## Use without dependency injection
|
||||
|
||||
```csharp
|
||||
using BinaryLane.Api.V2;
|
||||
using BinaryLane.Api.V2.Authentication;
|
||||
|
||||
using var httpClient = new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri("https://api.binarylane.com.au/"),
|
||||
};
|
||||
|
||||
var token = Environment.GetEnvironmentVariable("BINARYLANE_API_TOKEN")
|
||||
?? throw new InvalidOperationException("Set BINARYLANE_API_TOKEN.");
|
||||
|
||||
var client = new BinaryLaneClient(
|
||||
httpClient,
|
||||
new StaticBinaryLaneTokenProvider(token));
|
||||
```
|
||||
|
||||
## HTTP configuration
|
||||
|
||||
`AddBinaryLaneApi` returns an `IHttpClientBuilder`, so you can configure proxy,
|
||||
telemetry, or other application-specific handlers.
|
||||
|
||||
```csharp
|
||||
builder.Services.AddBinaryLaneApi(options => options.ApiToken = token)
|
||||
.ConfigureHttpClient(client => client.DefaultRequestHeaders.Add("X-App", "my-service"));
|
||||
```
|
||||
|
||||
Only add automatic retries when the request is safe to repeat. In particular,
|
||||
POST, PUT, PATCH, and DELETE requests may have already been applied when a
|
||||
network failure is reported.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Error handling
|
||||
|
||||
All API failures derive from `BinaryLaneApiException`.
|
||||
|
||||
| Exception | When it is used |
|
||||
| --- | --- |
|
||||
| `BinaryLaneUnauthorizedException` | The token is missing, invalid, or expired. |
|
||||
| `BinaryLaneForbiddenException` | The token does not have access to the resource. |
|
||||
| `BinaryLaneNotFoundException` | The requested resource does not exist or is not visible to the token. |
|
||||
| `BinaryLaneValidationException` | BinaryLane rejected the request payload. |
|
||||
| `BinaryLaneApiException` | Any other non-success HTTP response. |
|
||||
|
||||
```csharp
|
||||
using BinaryLane.Api.V2.Errors;
|
||||
|
||||
try
|
||||
{
|
||||
var server = await client.Servers.GetAsync(serverId, cancellationToken);
|
||||
}
|
||||
catch (BinaryLaneNotFoundException)
|
||||
{
|
||||
// Handle a missing server.
|
||||
}
|
||||
catch (BinaryLaneValidationException)
|
||||
{
|
||||
// Show an appropriate validation message to the caller.
|
||||
}
|
||||
catch (BinaryLaneApiException exception)
|
||||
{
|
||||
// Use exception.StatusCode to choose an application-specific response.
|
||||
}
|
||||
```
|
||||
|
||||
Each exception provides `StatusCode`, `RequestUri`, `Headers`, and, when
|
||||
available, `Problem` and `ResponseBody`. Provider detail text can contain user
|
||||
data. Do not write `Problem`, `Headers`, or `ResponseBody` to application logs
|
||||
without appropriate redaction.
|
||||
|
||||
Successful JSON responses are limited to 16 MiB. A larger response throws
|
||||
`HttpRequestException` before the client buffers it in memory.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Getting started
|
||||
|
||||
`BinaryLane.Api` connects to BinaryLane's bearer-token v2 API at
|
||||
`https://api.binarylane.com.au/v2/`.
|
||||
|
||||
## 1. Install the package
|
||||
|
||||
```bash
|
||||
dotnet add package BinaryLane.Api --prerelease
|
||||
```
|
||||
|
||||
## 2. Store the token safely
|
||||
|
||||
For local development, initialise user secrets for your application and add
|
||||
the token:
|
||||
|
||||
```bash
|
||||
dotnet user-secrets init
|
||||
dotnet user-secrets set "BinaryLane:ApiToken" "your-token"
|
||||
```
|
||||
|
||||
For hosted applications, use the platform's secret store or supply
|
||||
`BINARYLANE_API_TOKEN` at runtime.
|
||||
|
||||
## 3. Register the client
|
||||
|
||||
```csharp
|
||||
using BinaryLane.Api.V2;
|
||||
using BinaryLane.Api.V2.DependencyInjection;
|
||||
using BinaryLane.Api.V2.Models;
|
||||
|
||||
builder.Services.AddBinaryLaneApi(options =>
|
||||
{
|
||||
options.ApiToken = builder.Configuration["BinaryLane:ApiToken"]
|
||||
?? Environment.GetEnvironmentVariable("BINARYLANE_API_TOKEN")
|
||||
?? throw new InvalidOperationException("A BinaryLane API token is required.");
|
||||
});
|
||||
```
|
||||
|
||||
## 4. Make a request
|
||||
|
||||
Inject `IBinaryLaneClient`, then select the resource you need:
|
||||
|
||||
```csharp
|
||||
public sealed class ServerReader(IBinaryLaneClient binaryLane)
|
||||
{
|
||||
public IAsyncEnumerable<Server> ListAsync(CancellationToken cancellationToken) =>
|
||||
binaryLane.Servers.ListAllAsync(cancellationToken: cancellationToken);
|
||||
}
|
||||
```
|
||||
|
||||
See [Configuration](configuration.md) for custom token providers and
|
||||
[Pagination](pagination.md) for page-by-page access.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Pagination
|
||||
|
||||
List endpoints accept one-based `page` and `per_page` values. `per_page` can be
|
||||
between 1 and 200.
|
||||
|
||||
Use `ListAsync` when you need a specific page or the provider's page links:
|
||||
|
||||
```csharp
|
||||
using BinaryLane.Api.V2.Pagination;
|
||||
|
||||
var page = await client.Servers.ListAsync(
|
||||
new PageRequest { Page = 1, PerPage = 50 },
|
||||
cancellationToken);
|
||||
|
||||
foreach (var server in page.Items)
|
||||
{
|
||||
await ProcessAsync(server, cancellationToken);
|
||||
}
|
||||
```
|
||||
|
||||
Use `ListAllAsync` to process every page as it is needed:
|
||||
|
||||
```csharp
|
||||
await foreach (var server in client.Servers.ListAllAsync(cancellationToken: cancellationToken))
|
||||
{
|
||||
await ProcessAsync(server, cancellationToken);
|
||||
}
|
||||
```
|
||||
|
||||
Pass a cancellation token from the calling request, worker, or command so a
|
||||
stopped operation does not continue fetching pages.
|
||||
@@ -0,0 +1,63 @@
|
||||
# Maintainer guide: releases
|
||||
|
||||
This page is for package maintainers.
|
||||
|
||||
This repository publishes packages with NuGet trusted publishing and GitHub
|
||||
OpenID Connect (OIDC). It must not use a long-lived NuGet API key.
|
||||
|
||||
## One-time setup
|
||||
|
||||
1. On NuGet.org, create or verify the trusted-publishing policy:
|
||||
- publisher: `GitHubActions`;
|
||||
- GitHub owner: `alexhopeoconnor`;
|
||||
- repository: `binarylane-dotnet`;
|
||||
- workflow: `publish.yml`;
|
||||
- environment: `release`.
|
||||
2. In GitHub, create a protected environment named `release` and require a
|
||||
maintainer approval.
|
||||
3. Create a protected `release` environment secret named `NUGET_USER` with
|
||||
the NuGet.org username `alex.hope.oconnor`. It is an identifier, not an
|
||||
API key.
|
||||
4. Protect `main` with CI and restrict creation of `v*` tags.
|
||||
|
||||
The first successful OIDC publication must occur before NuGet's policy
|
||||
activation window expires. After success, NuGet permanently activates the
|
||||
policy for this exact repository/workflow/environment identity.
|
||||
|
||||
## Release checklist
|
||||
|
||||
1. Review BinaryLane contract changes and update the committed snapshot if
|
||||
necessary.
|
||||
2. Update code, tests, docs, API coverage, and `CHANGELOG.md`.
|
||||
3. Set the package `<Version>` to the intended SemVer release.
|
||||
4. Open and merge the release pull request after CI succeeds.
|
||||
5. Tag the exact merge commit. The tag must equal the package version with a
|
||||
leading `v`.
|
||||
|
||||
```bash
|
||||
git tag -a v0.1.0-beta.1 -m "BinaryLane.Api 0.1.0-beta.1"
|
||||
git push origin v0.1.0-beta.1
|
||||
```
|
||||
|
||||
6. Approve the protected `release` environment in GitHub Actions.
|
||||
7. Verify the package page, rendered README, icon, license, repository link,
|
||||
symbols, package ownership, and GitHub Release.
|
||||
|
||||
## What the release workflow does
|
||||
|
||||
`publish.yml` validates the tag, package version, and changelog heading; it
|
||||
then restores, builds, tests, packs, and compiles the maintained demo against
|
||||
the resulting local `.nupkg`. Only then does `NuGet/login@v1` exchange the
|
||||
GitHub OIDC identity for a short-lived one-time publish key. The key is used
|
||||
only in memory by the job.
|
||||
|
||||
The GitHub Release job runs after NuGet publishing and receives no OIDC
|
||||
permission. It attaches the package files and uses the matching changelog
|
||||
section for release notes.
|
||||
|
||||
## Recovery
|
||||
|
||||
NuGet packages cannot be overwritten. If a release has a packaging defect,
|
||||
unlist it if appropriate, publish a new version, and document the correction
|
||||
in the changelog. Do not retag a version or attempt to reuse a published
|
||||
package version.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Maintainer guide: upstream API contract
|
||||
|
||||
This page describes SDK maintenance. Package consumers can start with the
|
||||
[README](../README.md).
|
||||
|
||||
The source of truth for BinaryLane's API is its published OpenAPI document:
|
||||
|
||||
<https://api.binarylane.com.au/reference/openapi.yaml>
|
||||
|
||||
The committed raw snapshot is intentionally reviewable:
|
||||
|
||||
```text
|
||||
eng/openapi/binarylane-v2.openapi.yaml
|
||||
eng/openapi/contract.json
|
||||
```
|
||||
|
||||
`contract.json` records the source URL, provider-declared version, SHA-256,
|
||||
and retrieval time. It describes an upstream artifact; it does not set the
|
||||
NuGet package version.
|
||||
|
||||
## Snapshot purpose
|
||||
|
||||
BinaryLane's preview API can change without a version change. The committed
|
||||
snapshot makes those changes visible during SDK maintenance.
|
||||
|
||||
## Normalization
|
||||
|
||||
The raw document includes virtual `#ActionName` paths for individual server
|
||||
action variants. They exist to improve the provider's reference UI but are not
|
||||
HTTP paths. `eng/normalize-openapi.sh` strips them when producing a normalized
|
||||
document for code generation or coverage checks. Do not issue requests to
|
||||
those virtual paths.
|
||||
|
||||
## Monitoring and updating
|
||||
|
||||
The scheduled `contract-monitor.yml` workflow downloads the live document and
|
||||
runs `eng/verify-openapi-contract.sh`. If the SHA-256 or provider-declared
|
||||
version differs, it opens one issue rather than silently updating the SDK.
|
||||
|
||||
To intentionally refresh the snapshot after review:
|
||||
|
||||
```bash
|
||||
./eng/refresh-openapi-contract.sh
|
||||
git diff -- eng/openapi docs/api-coverage.md
|
||||
```
|
||||
|
||||
Then update affected models, coverage documentation, changelog, and tests in
|
||||
the same pull request. Review the change before merging it.
|
||||
Reference in New Issue
Block a user