Swift client and models (the FlowboxAPI library) for the Flowbox External API v2, generated from Flowbox's OpenAPI specification with swift-openapi-generator.
Unofficial. This package is not made, endorsed or supported by Flowbox. The generated code is derived from the specification Flowbox publishes on SwaggerHub.
Generated operations: posts of a flow, products, report a post and event tracking.
.package(url: "<repository URL>", from: "<version>")Add the FlowboxAPI product of the swift-flowbox-api package to your target. It re-exports OpenAPIRuntime, OpenAPIURLSession and HTTPTypes. Requires iOS 16 / macOS 13 and a toolchain that supports swift-tools 6.1 packages as dependencies (Xcode 16.3+).
import FlowboxAPI
struct APIKeyMiddleware: ClientMiddleware {
let apiKey: String
func intercept(
_ request: HTTPRequest,
body: HTTPBody?,
baseURL: URL,
operationID: String,
next: @Sendable (HTTPRequest, HTTPBody?, URL) async throws -> (HTTPResponse, HTTPBody?)
) async throws -> (HTTPResponse, HTTPBody?) {
var request = request
request.headerFields[HTTPField.Name("api-key")!] = apiKey
return try await next(request, body, baseURL)
}
}
let configuration = URLSessionConfiguration.default
configuration.urlCache = URLCache(memoryCapacity: 10_000_000, diskCapacity: 50_000_000)
configuration.requestCachePolicy = .useProtocolCachePolicy
let client = Client(
serverURL: URL(string: "https://external-api.getflowbox.com/v2")!,
transport: URLSessionTransport(configuration: .init(session: URLSession(configuration: configuration))),
middlewares: [APIKeyMiddleware(apiKey: "<api key>")]
)
let output = try await client.GetPostsByFlowKey(
path: .init(flowKey: "<flow key>"),
query: .init(_type: .tag, postsPerPage: 30, tags: "tag one,tag two", _operator: .OR, inclusive_feeds: "<flow key>")
)
let posts = try output.ok.body.json.data?.posts ?? []The published specification is not accurate in a few places, and some behaviour is not documented. This is what was observed against the real API:
- Cursor.
data.cursoris an integer page counter (the spec says object). Send it back as thecursorquery parameter to get the next page. The last page is shorter thanpostsPerPageand has"cursor": null; asking for a page beyond the end returns HTTP 200 with no posts and"cursor": null. Stop when the cursor isnilor the page is empty. - Tag flows.
type=tagrequirestags(comma separated), otherwise the API answers 400. - Other flows' posts. Send
inclusive_feeds=<flow key>even though the flow key is already in the path. Without it the API answers 200 with posts from other flows of the account. - Product keys. A post's
productKeysis a JSON array encoded inside a string ("[\"a\", \"b\"]"), possibly with repeated keys. - Products.
/products/{keys}can answer 200 with an emptyproductsarray for a key that exists on a post. - Nulls. Many fields that the spec declares as non-null (
text,userPermalink, several product fields) can benull. - Prices are strings.
- Caching. Responses carry
Cache-Control: max-age=<seconds>and a weakETagonly some of the time; theETagdiffers between identical requests, so conditional requests do not return 304. Withmax-agepresentURLCacheserves repeated requests from cache; responses without it are not cached.
./generate.sh # downloads the upstream spec if missing, patches it, regenerates Sources/FlowboxAPI
./generate.sh --refresh # downloads the upstream spec again first
Spec/patch-openapi.pyapplies the corrections to the upstream spec:cursorbecomes an integer (response and request) andapi-keybecomes asecuritySchemeinstead of a parameter on every operation. It fails loudly if the upstream shape changes.Spec/openapi-generator-config.yamlselects the operations to generate.- The first run builds
swift-openapi-generatorat a pinned version into.build/. - The generated sources are the generator's raw output. Building them prints
UnusedImportAccesswarnings (public import of 'Foundation' was not used in public declarations): the generator (1.13.1) puts the same imports in every file. It is a known upstream issue (swift-openapi-generator#946), harmless, and the CI does not check warnings. - The upstream spec (
Spec/upstream-openapi.json) and the patched one (Spec/openapi.json) are not committed: they are Flowbox's content. The generated sources are committed and must not be edited by hand.
The CI workflow runs on pull requests, on pushes to main and on demand from the Actions tab. The Xcode version comes from .xcode-version. In one job it:
- builds the package (
swift build); - regenerates the sources from the current upstream spec (
./generate.sh --refresh) and fails if they differ from the committed ones.
To update the client (for example when Flowbox changes its API): run ./generate.sh --refresh locally, check that swift build succeeds, commit the result and open a pull request; the workflow confirms that the committed sources are exactly what the generator produces. If Flowbox changes its spec, any later pull request fails the second step until the sources are regenerated and committed.
Apache License 2.0, see LICENSE and NOTICE. The licence covers this package only: it grants no right over the Flowbox API, its specification or its trademarks.