fly_io 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +15 -0
  3. data/CONTRIBUTING.md +14 -0
  4. data/LICENSE +21 -0
  5. data/README.md +239 -0
  6. data/Rakefile +30 -0
  7. data/contracts/additional_rest/network_policies.json +94 -0
  8. data/contracts/additional_rest/prometheus.json +103 -0
  9. data/contracts/graphql/fly_go_operations.json +948 -0
  10. data/contracts/graphql/flyctl_named_operations.graphql +316 -0
  11. data/contracts/graphql/flyctl_operations.json +336 -0
  12. data/contracts/graphql/official_examples.json +75 -0
  13. data/contracts/graphql/schema.graphql +10995 -0
  14. data/contracts/graphql/source.json +29 -0
  15. data/contracts/machines/openapi.headers +9 -0
  16. data/contracts/machines/openapi.json +1 -0
  17. data/contracts/machines/source.json +20 -0
  18. data/contracts/public_surface_inventory.json +164 -0
  19. data/contracts/research_metadata.json +17 -0
  20. data/contracts/sources/metrics.html.md +474 -0
  21. data/contracts/sources/network-policies.html.markerb +142 -0
  22. data/docs/API.md +149 -0
  23. data/docs/SURFACES.md +60 -0
  24. data/lib/fly_io/client.rb +52 -0
  25. data/lib/fly_io/configuration.rb +115 -0
  26. data/lib/fly_io/errors.rb +45 -0
  27. data/lib/fly_io/generated/additional_operations.json +123 -0
  28. data/lib/fly_io/generated/graphql_operations.json +1658 -0
  29. data/lib/fly_io/generated/operations.json +6130 -0
  30. data/lib/fly_io/generated/prometheus_operations.json +503 -0
  31. data/lib/fly_io/generated/schemas.json +4237 -0
  32. data/lib/fly_io/graphql_client.rb +103 -0
  33. data/lib/fly_io/model.rb +65 -0
  34. data/lib/fly_io/operation_registry.rb +79 -0
  35. data/lib/fly_io/redactor.rb +34 -0
  36. data/lib/fly_io/resources/base.rb +68 -0
  37. data/lib/fly_io/resources.rb +30 -0
  38. data/lib/fly_io/response.rb +45 -0
  39. data/lib/fly_io/schema_registry.rb +89 -0
  40. data/lib/fly_io/schema_validator.rb +56 -0
  41. data/lib/fly_io/transport.rb +282 -0
  42. data/lib/fly_io/version.rb +5 -0
  43. data/lib/fly_io.rb +23 -0
  44. data/script/check_api_coverage +60 -0
  45. data/script/fetch_openapi +18 -0
  46. data/script/generate_api +302 -0
  47. metadata +197 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4dd8c23a72b3368728387726a4f9c0f549f964c73031fd210f8a452e0b635fed
4
+ data.tar.gz: 5c7cde4c9562e3a5e422b31c253f62eaa27de501e4ee80ef2a045c4934444f46
5
+ SHA512:
6
+ metadata.gz: 537aacc7de6c237c6acfb03107d96c4244ba0e94338e819ec5ac9bd16ca2af122b25abcc143f9e58eee2eeb43d35f70b990f120546266c1db87417ab9eb142a3
7
+ data.tar.gz: 18fb6ba50789303ed0b90154dd650822accbd1c21d4852afbd3bec80876b21167e5597e2f2b5c714c8acff081c17145c46038897eac192d6b1ed2f38a753b2fe
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # Changelog
2
+
3
+ All notable changes follow [Keep a Changelog](https://keepachangelog.com/) and Semantic Versioning.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.1.0] - 2026-08-26
8
+
9
+ ### Added
10
+
11
+ - Complete generated coverage of the Fly Machines OpenAPI contract: 98 operations and 173 schemas.
12
+ - Documentation-derived Network Policies client.
13
+ - Seven-family Fly Prometheus compatibility client.
14
+ - Raw GraphQL client and explicitly experimental flyctl/fly-go/official operation inventory.
15
+ - Typed responses, redaction, bounded safe retries, contract drift gates, offline tests, and packaging/CI workflows.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,14 @@
1
+ # Contributing
2
+
3
+ Use Ruby 4.0.6 for development. Run `bundle install`, then `bundle exec rake` before opening a change.
4
+
5
+ API changes start from committed evidence, not handwritten endpoint lists:
6
+
7
+ 1. Run `bundle exec rake api:fetch_check` to detect Machines OpenAPI drift.
8
+ 2. Review upstream changes and update the relevant snapshot plus provenance/hash.
9
+ 3. Run `bundle exec rake api:generate`.
10
+ 4. Add readable behavior coverage when semantics or risk changes.
11
+ 5. Run `bundle exec rake`, `bundle exec bundle-audit check --update`, and the install smoke test.
12
+
13
+ Do not add undocumented flyctl calls to the stable namespace. GraphQL evidence stays experimental. Never commit tokens,
14
+ live response cassettes, credentials, or unredacted debug output.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Vito Botta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,239 @@
1
+ # fly_io
2
+
3
+ `fly_io` is a contract-driven Ruby client for Fly.io’s documented platform APIs. It covers every operation in the
4
+ Machines REST OpenAPI contract, the documentation-only Network Policies endpoints, Fly’s Prometheus compatibility
5
+ endpoint, and Fly’s explicitly unstable control-plane GraphQL boundary.
6
+
7
+ The Ruby namespace is `FlyIO`. The gem name was unclaimed on RubyGems when checked on 2026-08-26; see
8
+ [`contracts/research_metadata.json`](contracts/research_metadata.json). This repository is not published by or
9
+ affiliated with Fly.io.
10
+
11
+ ## Installation
12
+
13
+ Add the gem to your bundle:
14
+
15
+ ```ruby
16
+ gem "fly_io", "~> 0.1"
17
+ ```
18
+
19
+ Then run `bundle install`. Ruby 3.2 or newer is supported. Development and the primary CI job use Ruby 4.0.6, the
20
+ latest stable release verified from ruby-lang.org on the contract retrieval date.
21
+
22
+ The sole runtime dependency is Faraday 2.x. It provides a maintained, adapter-injectable HTTP foundation; retries,
23
+ redaction, contract mapping, and model coercion are implemented in this gem so their behavior remains explicit.
24
+
25
+ ## Quickstart
26
+
27
+ ```ruby
28
+ require "fly_io"
29
+
30
+ client = FlyIO::Client.new(token: ENV.fetch("FLY_API_TOKEN"))
31
+
32
+ apps = client.apps.list(org_slug: "personal")
33
+ machine = client.machines.create(
34
+ app_name: "my-app",
35
+ body: {
36
+ region: "iad",
37
+ config: {
38
+ image: "registry.example.com/my-image:latest",
39
+ guest: {cpu_kind: "shared", cpus: 1, memory_mb: 512}
40
+ }
41
+ }
42
+ )
43
+
44
+ client.machines.start(app_name: "my-app", machine_id: machine.id)
45
+ client.machines.wait(app_name: "my-app", machine_id: machine.id, state: "started", timeout: 60)
46
+ ```
47
+
48
+ Resource methods return `FlyIO::Response`. `response.body` is coerced to the documented `FlyIO::Models::*` class (or
49
+ an array/primitive where the contract says so), while response methods delegate to a model for concise code such as
50
+ `machine.id`. Models keep unknown fields and preserve exact wire keys for forward compatibility.
51
+
52
+ All named endpoint inputs are keyword arguments. JSON request bodies use `body:` because this gives every generated
53
+ operation one consistent signature. The generated [complete API reference](docs/API.md) maps each Ruby method to the
54
+ official operation ID, method, and path.
55
+
56
+ ## Authentication
57
+
58
+ The official Machines guide and current examples use `Authorization: Bearer <token>`. The generated reference also
59
+ contains contradictory `FlyV1` prose. Consequently, a raw token uses `Bearer` by default and preformatted values are
60
+ explicit:
61
+
62
+ ```ruby
63
+ FlyIO::Client.new(token: ENV.fetch("FLY_API_TOKEN"))
64
+ FlyIO::Client.new(authorization: "FlyV1 #{ENV.fetch("FLY_MACAROON")}")
65
+ FlyIO::Client.new(token: ENV.fetch("FLY_MACAROON"), authorization_mode: :fly_v1)
66
+ ```
67
+
68
+ A token passed to `token:` must be raw, so `Bearer Bearer ...` cannot be produced accidentally. Authorization values,
69
+ tokens, secrets, passwords, credentials, private keys, and certificates are filtered from logs, request metadata, and
70
+ exceptions.
71
+
72
+ ## Configuration and transport behavior
73
+
74
+ ```ruby
75
+ configuration = FlyIO::Configuration.new(
76
+ token: ENV.fetch("FLY_API_TOKEN"),
77
+ base_url: "https://api.machines.dev", # or http://_api.internal:4280 on the Fly private network
78
+ graphql_url: "https://api.fly.io/graphql",
79
+ metrics_url: "https://api.fly.io",
80
+ open_timeout: 10,
81
+ read_timeout: 30,
82
+ write_timeout: 30,
83
+ request_timeout: 45,
84
+ proxy: ENV["HTTPS_PROXY"],
85
+ user_agent: "my-service/1.0 fly_io/#{FlyIO::VERSION}",
86
+ max_retries: 2,
87
+ base_retry_interval: 0.25,
88
+ max_retry_interval: 5,
89
+ retry_jitter: 0.25,
90
+ logger: Logger.new($stderr)
91
+ )
92
+ client = FlyIO::Client.new(configuration)
93
+ ```
94
+
95
+ TLS verification is always enabled by the HTTP adapter. The client parses JSON only when the response content type is
96
+ JSON, represents 204 as a nil body, preserves 202 responses, and safely returns text, binary, empty, or malformed JSON
97
+ bodies. `FlyIO::Response` includes status, headers, parsed body, raw body, safe request metadata, and Fly’s request ID.
98
+
99
+ GET/HEAD/OPTIONS requests retry bounded transient connection failures and 408, 429, 500, 502, 503, and 504 responses.
100
+ `Retry-After` is honored; otherwise delay uses capped exponential backoff with jitter. Unsafe methods are never retried
101
+ unless a caller passes `retry_unsafe: true` to that request or deliberately enables it globally. Fly’s limits are
102
+ per-action and per-resource, so this gem does not pretend a single client-wide throttle is correct.
103
+
104
+ Configuration and resource objects are immutable. All request state is local, making a client safe to share between
105
+ threads. An object responding to `call(method:, url:, headers:, body:, timeout:)` can be supplied as `adapter:` for
106
+ dependency injection; a Faraday adapter symbol is also accepted.
107
+
108
+ ## Errors
109
+
110
+ All failures inherit `FlyIO::Error`. HTTP failures use `FlyIO::APIError` and its typed subclasses:
111
+
112
+ - `AuthenticationError` / `AuthorizationError`
113
+ - `NotFoundError`
114
+ - `ValidationError`
115
+ - `RateLimitError`
116
+ - `RequestTimeoutError`
117
+ - `TransportError`
118
+ - `ServerError`
119
+ - `GraphQLError`
120
+
121
+ API errors retain status, safe headers, redacted parsed details, request ID, and redacted request metadata.
122
+
123
+ ## Raw REST and operation-ID access
124
+
125
+ Use a path template when values are dynamic so every component is escaped independently:
126
+
127
+ ```ruby
128
+ client.request(
129
+ method: :get,
130
+ path: "/v1/apps/{app_name}/machines",
131
+ path_params: {app_name: "my-app"},
132
+ query: {state: "started"}
133
+ )
134
+
135
+ client.operation("Machines_start", app_name: "my-app", machine_id: "machine-id")
136
+ ```
137
+
138
+ The low-level API validates the method, rejects path traversal and URL-shaped paths, supports repeated query values,
139
+ and returns the same response/errors as resource methods. The upstream duplicate `Machines_update_metadata` ID must be
140
+ disambiguated with `method:` and `path:`.
141
+
142
+ ## Network Policies
143
+
144
+ Fly officially documents three Network Policies operations that are missing from its OpenAPI document:
145
+
146
+ ```ruby
147
+ client.network_policies.upsert(
148
+ app_name: "my-app",
149
+ body: {
150
+ name: "web-egress",
151
+ selector: {metadata: {role: "web"}},
152
+ rules: [{action: "allow", direction: "egress", ports: [{protocol: "tcp", port: 443}]}]
153
+ }
154
+ )
155
+ client.network_policies.list(app_name: "my-app")
156
+ client.network_policies.delete(app_name: "my-app", policy_id: "policy-id")
157
+ ```
158
+
159
+ The guide does not document response statuses or schemas. Responses therefore remain forward-compatible raw values;
160
+ the body input is checked only against fields and constraints the guide actually states.
161
+
162
+ ## Prometheus metrics
163
+
164
+ Fly documents seven Prometheus-compatible endpoint families at `https://api.fly.io/prometheus/<org>/`. They are a
165
+ stable observability/data API, not control-plane operations, but are included so the platform-surface audit is honest:
166
+
167
+ ```ruby
168
+ client.metrics.query(org_slug: "personal", query: 'sum(rate(fly_edge_http_responses_count[5m]))')
169
+ client.metrics.query_range(org_slug: "personal", query: "up", start: "-1h", end: "now", step: "60s")
170
+ client.metrics.series(org_slug: "personal", match: ['{__name__="up"}'])
171
+ client.metrics.labels(org_slug: "personal")
172
+ client.metrics.label_values(org_slug: "personal", label_name: "app")
173
+ client.metrics.tsdb(org_slug: "personal")
174
+ client.metrics.federate(org_slug: "personal", match: ["up"])
175
+ ```
176
+
177
+ The JSON envelope becomes `FlyIO::Models::PrometheusAPIResponse`; federation remains text. Endpoint semantics are
178
+ delegated to the stable Prometheus HTTP API and Fly’s stated VictoriaMetrics compatibility.
179
+
180
+ ## GraphQL: experimental and unstable
181
+
182
+ Fly explicitly documents `https://api.fly.io/graphql` as an internal flyctl interface with no stability guarantees.
183
+ It can change without notice. Prefer REST or flyctl where possible. Nothing in this gem presents GraphQL fields as a
184
+ stable public contract.
185
+
186
+ Raw documents, variables, operation names, response parsing, errors, timeouts, and opt-in retries are first class:
187
+
188
+ ```ruby
189
+ graphql = client.graphql
190
+ response = graphql.query(
191
+ document: "query App($name: String!) { app(name: $name) { id name } }",
192
+ variables: {name: "my-app"},
193
+ operation_name: "App"
194
+ )
195
+ ```
196
+
197
+ Schema introspection is double opt-in: construct configuration with `introspection: true`, then call
198
+ `graphql.introspect(document: ...)`. The committed flyctl schema is evidence only.
199
+
200
+ The experimental adapter inventories 29 current flyctl documents, 85 fly-go v0.9.8 documents, and 3 official unstable
201
+ examples. Execute one with `graphql.experimental.execute("flyctl.GetApp", variables: ...)`. Arbitrary raw GraphQL
202
+ documents remain available when Fly adds fields before this gem releases.
203
+
204
+ ## Contracts, development, and tests
205
+
206
+ The [surface inventory](docs/SURFACES.md) records every selected/excluded surface, provenance, hashes, revisions,
207
+ counts, stability, and gaps. Contract artifacts live under `contracts/`; generated runtime metadata is under
208
+ `lib/fly_io/generated/`.
209
+
210
+ ```shell
211
+ bundle install
212
+ bundle exec rake api:check # offline snapshot/ref/mapping/generated-drift checks
213
+ bundle exec rspec # offline; WebMock disables all network access
214
+ bundle exec rubocop
215
+ bundle exec bundle-audit check --update
216
+ bundle exec rake build
217
+ ```
218
+
219
+ For an isolated `--install-dir` smoke under RubyGems 4, use `--ignore-dependencies` for the target gem and include the
220
+ already audited Bundler gem path when requiring it. RubyGems otherwise attempts to rediscover Faraday in a local gem
221
+ repository even when it is already installed. CI performs this install plus a packaged-gem require check.
222
+
223
+ `bundle exec rake api:fetch_check` is the explicit networked upstream-drift check. `script/generate_api` regenerates
224
+ operation/model metadata and [docs/API.md](docs/API.md). Generated code is included in coverage because the small
225
+ runtime generator boundary is exercised by contract-derived RSpec examples; JSON metadata itself has no executable
226
+ lines to exclude.
227
+
228
+ Live tests require `FLY_IO_LIVE_TESTS=1`, `FLY_API_TOKEN`, and `FLY_IO_TEST_APP`. Destructive live work additionally
229
+ requires `FLY_IO_DESTRUCTIVE_LIVE_TESTS=1`; ordinary CI never has network access or credentials.
230
+
231
+ ## Versioning
232
+
233
+ The gem follows Semantic Versioning for its own stable Ruby API. Machines contract changes are reviewed through the
234
+ drift gate. Experimental GraphQL changes may ship in any release and are called out in the changelog because Fly gives
235
+ that upstream interface no compatibility guarantee.
236
+
237
+ ## License
238
+
239
+ MIT. See [LICENSE](LICENSE).
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+ require "rubocop/rake_task"
6
+
7
+ RSpec::Core::RakeTask.new(:spec)
8
+ RuboCop::RakeTask.new(:rubocop) do |task|
9
+ task.options = ["--cache-root", "tmp/rubocop_cache", "--no-server"]
10
+ end
11
+
12
+ namespace :api do
13
+ desc "Verify generated API coverage and committed contract outputs"
14
+ task :check do
15
+ sh RbConfig.ruby, "script/check_api_coverage"
16
+ end
17
+
18
+ desc "Fetch the upstream OpenAPI and fail if it differs from the snapshot"
19
+ task :fetch_check do
20
+ sh RbConfig.ruby, "script/fetch_openapi"
21
+ end
22
+
23
+ desc "Regenerate API metadata and documentation"
24
+ task :generate do
25
+ sh RbConfig.ruby, "script/generate_api"
26
+ end
27
+ end
28
+
29
+ desc "Run offline quality checks"
30
+ task default: ["api:check", :spec, :rubocop]
@@ -0,0 +1,94 @@
1
+ {
2
+ "surface": "network_policies_rest",
3
+ "stability": "stable_documented",
4
+ "base_url": "https://api.machines.dev",
5
+ "documentation_url": "https://fly.io/docs/machines/guides-examples/network-policies/",
6
+ "source_repository": "https://github.com/superfly/docs",
7
+ "source_revision": "1e8cac5f0fd7a82e66e3b01ece3a10a8ecb2b7e3",
8
+ "source_path": "machines/guides-examples/network-policies.html.markerb",
9
+ "source_sha256": "fa64b69db56beb1da2de60e3ff91820b628a1238a120d103c2f3bae16e2fcc1f",
10
+ "retrieved_at": "2026-08-26T21:00:00Z",
11
+ "limitations": [
12
+ "This official guide is not represented in the Machines OpenAPI document.",
13
+ "The guide documents methods, paths, authentication, and request shape, but no response status or schema."
14
+ ],
15
+ "schemas": {
16
+ "NetworkPolicyPort": {
17
+ "type": "object",
18
+ "required": ["protocol", "port"],
19
+ "properties": {"protocol": {"type": "string"}, "port": {"type": "integer"}}
20
+ },
21
+ "NetworkPolicyRule": {
22
+ "type": "object",
23
+ "required": ["action", "direction", "ports"],
24
+ "properties": {
25
+ "action": {"type": "string", "enum": ["allow"]},
26
+ "direction": {"type": "string", "enum": ["ingress", "egress"]},
27
+ "ports": {"type": "array", "items": {"$ref": "#/additional/schemas/NetworkPolicyPort"}}
28
+ }
29
+ },
30
+ "NetworkPolicySelector": {
31
+ "type": "object",
32
+ "properties": {
33
+ "all": {"type": "boolean"},
34
+ "machines": {"type": "array", "items": {"type": "object", "required": ["id"], "properties": {"id": {"type": "string"}}}},
35
+ "metadata": {"type": "object", "additionalProperties": {"type": "string"}}
36
+ }
37
+ },
38
+ "NetworkPolicyRequest": {
39
+ "type": "object",
40
+ "required": ["name", "selector", "rules"],
41
+ "properties": {
42
+ "id": {"type": "string"},
43
+ "name": {"type": "string"},
44
+ "selector": {"$ref": "#/additional/schemas/NetworkPolicySelector"},
45
+ "rules": {"type": "array", "items": {"$ref": "#/additional/schemas/NetworkPolicyRule"}}
46
+ }
47
+ },
48
+ "NetworkPolicy": {
49
+ "type": "object",
50
+ "additionalProperties": true,
51
+ "properties": {
52
+ "id": {"type": "string"},
53
+ "name": {"type": "string"},
54
+ "selector": {"$ref": "#/additional/schemas/NetworkPolicySelector"},
55
+ "rules": {"type": "array", "items": {"$ref": "#/additional/schemas/NetworkPolicyRule"}}
56
+ }
57
+ }
58
+ },
59
+ "operations": [
60
+ {
61
+ "identity": "POST /v1/apps/{app_name}/network_policies NetworkPolicies_upsert",
62
+ "operation_id": "NetworkPolicies_upsert",
63
+ "method": "post",
64
+ "path": "/v1/apps/{app_name}/network_policies",
65
+ "summary": "Create or update a network policy",
66
+ "parameters": [{"name": "app_name", "ruby_name": "app_name", "in": "path", "required": true, "schema": {"type": "string"}}],
67
+ "request_body": {"required": true, "content_types": ["application/json"], "schema": {"$ref": "#/additional/schemas/NetworkPolicyRequest"}},
68
+ "responses": {}
69
+ },
70
+ {
71
+ "identity": "GET /v1/apps/{app_name}/network_policies/ NetworkPolicies_list",
72
+ "operation_id": "NetworkPolicies_list",
73
+ "method": "get",
74
+ "path": "/v1/apps/{app_name}/network_policies/",
75
+ "summary": "List network policies",
76
+ "parameters": [{"name": "app_name", "ruby_name": "app_name", "in": "path", "required": true, "schema": {"type": "string"}}],
77
+ "request_body": null,
78
+ "responses": {}
79
+ },
80
+ {
81
+ "identity": "DELETE /v1/apps/{app_name}/network_policies/{policy_id} NetworkPolicies_delete",
82
+ "operation_id": "NetworkPolicies_delete",
83
+ "method": "delete",
84
+ "path": "/v1/apps/{app_name}/network_policies/{policy_id}",
85
+ "summary": "Delete a network policy",
86
+ "parameters": [
87
+ {"name": "app_name", "ruby_name": "app_name", "in": "path", "required": true, "schema": {"type": "string"}},
88
+ {"name": "policy_id", "ruby_name": "policy_id", "in": "path", "required": true, "schema": {"type": "string"}}
89
+ ],
90
+ "request_body": null,
91
+ "responses": {}
92
+ }
93
+ ]
94
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "surface": "prometheus_metrics",
3
+ "stability": "stable_standard_api_with_qualified_compatibility",
4
+ "base_url": "https://api.fly.io",
5
+ "documentation_url": "https://fly.io/docs/monitoring/metrics",
6
+ "source_repository": "https://github.com/superfly/docs",
7
+ "source_revision": "1e8cac5f0fd7a82e66e3b01ece3a10a8ecb2b7e3",
8
+ "source_path": "monitoring/metrics.html.md",
9
+ "source_sha256": "e22d7b34406b16c2ea75eed6cd92c51ec07d166963155623557295ef24f67e9f",
10
+ "retrieved_at": "2026-08-26T21:00:00Z",
11
+ "limitations": [
12
+ "This is an observability data API, not a control-plane API.",
13
+ "Fly documents support for most common Prometheus query endpoints and delegates their parameter/response contracts to Prometheus/VictoriaMetrics."
14
+ ],
15
+ "schemas": {
16
+ "PrometheusAPIResponse": {
17
+ "type": "object",
18
+ "required": ["status"],
19
+ "additionalProperties": true,
20
+ "properties": {
21
+ "status": {"type": "string", "enum": ["success", "error"]},
22
+ "data": {"type": "object", "additionalProperties": true},
23
+ "errorType": {"type": "string"},
24
+ "error": {"type": "string"},
25
+ "warnings": {"type": "array", "items": {"type": "string"}},
26
+ "infos": {"type": "array", "items": {"type": "string"}}
27
+ }
28
+ }
29
+ },
30
+ "operations": [
31
+ {
32
+ "operation_id": "Prometheus_query", "method": "get", "path": "/prometheus/{org_slug}/api/v1/query",
33
+ "summary": "Run an instant Prometheus query",
34
+ "parameters": [
35
+ {"name": "org_slug", "ruby_name": "org_slug", "in": "path", "required": true, "schema": {"type": "string"}},
36
+ {"name": "query", "ruby_name": "query", "in": "query", "required": true, "schema": {"type": "string"}},
37
+ {"name": "time", "ruby_name": "time", "in": "query", "required": false, "schema": {"type": "string"}},
38
+ {"name": "timeout", "ruby_name": "timeout", "in": "query", "required": false, "schema": {"type": "string"}}
39
+ ]
40
+ },
41
+ {
42
+ "operation_id": "Prometheus_query_range", "method": "get", "path": "/prometheus/{org_slug}/api/v1/query_range",
43
+ "summary": "Run a range Prometheus query",
44
+ "parameters": [
45
+ {"name": "org_slug", "ruby_name": "org_slug", "in": "path", "required": true, "schema": {"type": "string"}},
46
+ {"name": "query", "ruby_name": "query", "in": "query", "required": true, "schema": {"type": "string"}},
47
+ {"name": "start", "ruby_name": "start", "in": "query", "required": true, "schema": {"type": "string"}},
48
+ {"name": "end", "ruby_name": "end", "in": "query", "required": true, "schema": {"type": "string"}},
49
+ {"name": "step", "ruby_name": "step", "in": "query", "required": true, "schema": {"type": "string"}},
50
+ {"name": "timeout", "ruby_name": "timeout", "in": "query", "required": false, "schema": {"type": "string"}}
51
+ ]
52
+ },
53
+ {
54
+ "operation_id": "Prometheus_series", "method": "get", "path": "/prometheus/{org_slug}/api/v1/series",
55
+ "summary": "Find series by label matchers",
56
+ "parameters": [
57
+ {"name": "org_slug", "ruby_name": "org_slug", "in": "path", "required": true, "schema": {"type": "string"}},
58
+ {"name": "match[]", "ruby_name": "match", "in": "query", "required": true, "schema": {"type": "array", "items": {"type": "string"}}},
59
+ {"name": "start", "ruby_name": "start", "in": "query", "required": false, "schema": {"type": "string"}},
60
+ {"name": "end", "ruby_name": "end", "in": "query", "required": false, "schema": {"type": "string"}}
61
+ ]
62
+ },
63
+ {
64
+ "operation_id": "Prometheus_labels", "method": "get", "path": "/prometheus/{org_slug}/api/v1/labels",
65
+ "summary": "Get label names",
66
+ "parameters": [
67
+ {"name": "org_slug", "ruby_name": "org_slug", "in": "path", "required": true, "schema": {"type": "string"}},
68
+ {"name": "match[]", "ruby_name": "match", "in": "query", "required": false, "schema": {"type": "array", "items": {"type": "string"}}},
69
+ {"name": "start", "ruby_name": "start", "in": "query", "required": false, "schema": {"type": "string"}},
70
+ {"name": "end", "ruby_name": "end", "in": "query", "required": false, "schema": {"type": "string"}}
71
+ ]
72
+ },
73
+ {
74
+ "operation_id": "Prometheus_label_values", "method": "get", "path": "/prometheus/{org_slug}/api/v1/label/{label_name}/values",
75
+ "summary": "Get values for a label",
76
+ "parameters": [
77
+ {"name": "org_slug", "ruby_name": "org_slug", "in": "path", "required": true, "schema": {"type": "string"}},
78
+ {"name": "label_name", "ruby_name": "label_name", "in": "path", "required": true, "schema": {"type": "string"}},
79
+ {"name": "match[]", "ruby_name": "match", "in": "query", "required": false, "schema": {"type": "array", "items": {"type": "string"}}},
80
+ {"name": "start", "ruby_name": "start", "in": "query", "required": false, "schema": {"type": "string"}},
81
+ {"name": "end", "ruby_name": "end", "in": "query", "required": false, "schema": {"type": "string"}}
82
+ ]
83
+ },
84
+ {
85
+ "operation_id": "Prometheus_tsdb", "method": "get", "path": "/prometheus/{org_slug}/api/v1/status/tsdb",
86
+ "summary": "Get TSDB statistics",
87
+ "parameters": [
88
+ {"name": "org_slug", "ruby_name": "org_slug", "in": "path", "required": true, "schema": {"type": "string"}},
89
+ {"name": "limit", "ruby_name": "limit", "in": "query", "required": false, "schema": {"type": "integer"}},
90
+ {"name": "match[]", "ruby_name": "match", "in": "query", "required": false, "schema": {"type": "array", "items": {"type": "string"}}}
91
+ ]
92
+ },
93
+ {
94
+ "operation_id": "Prometheus_federate", "method": "get", "path": "/prometheus/{org_slug}/federate",
95
+ "summary": "Federate selected metrics",
96
+ "parameters": [
97
+ {"name": "org_slug", "ruby_name": "org_slug", "in": "path", "required": true, "schema": {"type": "string"}},
98
+ {"name": "match[]", "ruby_name": "match", "in": "query", "required": true, "schema": {"type": "array", "items": {"type": "string"}}}
99
+ ],
100
+ "response_content_type": "text/plain"
101
+ }
102
+ ]
103
+ }