laconicman/swift-gitlab
A modern, type-safe, async/await GitLab REST API client for Apple platforms, generated
API coverage
The entire GitLab REST API is available — coverage is a build-time choice, not a limitation. To keep compile times reasonable the package ships the review tier by default; switch tiers by copying a template over Sources/GitLabOpenAPI/openapi-generator-config.yaml and rebuilding:
| Tier | Operations | Config file | |---|---|---| | review (default) | ~218 | openapi-generator-config.yaml | | core | ~494 | openapi-generator-config.core.yaml | | full (whole API) | ~1,721 | openapi-generator-config.full.yaml |
The default review tier covers merge requests, approvals, notes, discussions, draft notes, award emoji, commits, branches, and repository diffs.
Install
.package(url: "https://github.com/laconicman/swift-gitlab.git", from: "0.1.0")
// target dependency:
.product(name: "GitLabKit", package: "GitLabKit")Requires Swift 6, iOS 16 / macOS 13 (also tvOS 16 / watchOS 9).
Usage
import GitLabKit
import GitLabOpenAPI
let client = try Client(token: "glpat-…") // gitlab.com
// let client = try Client(token: "…", hostname: "gitlab.example.com") // self-managed
// let client = try Client(token: "…", bodyLoggingPolicy: .upTo(maxBytes: 2048)) // debug
// Add a review comment to a merge request:
let note = try await client.postApiV4ProjectsIdMergeRequestsNoteableIdNotes(
.init(path: .init(id: "42", noteableId: 7), body: .json(.init(body: "LGTM 🚀")))
).created.body.json
// Handle documented statuses exhaustively:
let output = try await client.getApiV4ProjectsIdMergeRequestsMergeRequestIid(
.init(path: .init(id: .case1("42"), mergeRequestIid: 7))
)
switch output {
case .ok(let ok): print(try ok.body.json.title ?? "")
case .notFound: print("no such MR")
case .undocumented(let s, _): print("status \(s)")
}Authentication is a static bearer token (PAT or OAuth2 access token) via HeaderMiddleware; logging uses OSLogLoggingMiddleware.
Response decoding. GitLab's published spec under-types arrays — list endpoints and fields like
assignees/reviewersare typed as single objects, which would break decoding. GitLabKit ships a normalized spec (gitlab-spec-toolretypes them), so list endpoints and array fields decode correctly out of the box. One residual class remains — scalar mismatches such asmilestone.group_id(spec saysString, the API returns a number) — and the opt-inliveDecodeReviewEntitiestest reports any it finds. See the Tech Debt doc andUpstream/for the fixes in flight.
Layout
| Path | What | |---|---| | Sources/GitLabOpenAPI/openapi.yaml | Vendored, normalized GitLab spec (produced by gitlab-spec-tool) | | Sources/GitLabOpenAPI/openapi-generator-config*.yaml | Active review tier + preserved core/full templates | | Sources/GitLabKit/ | Façade: Client factory, HeaderMiddleware, GitLabDateTranscoder, generated Identifiable | | Sources/gitlab-spec-tool/ | Maintainer tool: fetch + normalize + retype the spec, emit Identifiable | | Sources/GitLabKit/GitLabKit.docc/ | DocC: Design, Roadmap, Tech Debt, Upstream Spec Fix | | Upstream/ | Pasteable issue drafts + PR handoffs for the upstream spec fixes |
The generated client (Client/Operations/Components/Servers) is built from the vendored spec at build time — run swift build; nothing generated is committed (except the Identifiable conformances, which aren't something the generator can emit).
Regenerate from a newer spec
swift run gitlab-spec-tool # fetch latest from master, normalize, retype arrays
swift run gitlab-spec-tool --ref v17.8.0 # pin to a tag / branch / commit sha
swift run gitlab-spec-tool --no-fetch # normalize the already-vendored spec in place
swift build # regenerate the clientgitlab-spec-tool retypes GitLab's under-typed array fields/responses so real payloads decode, and regenerates Types+Identifiable.generated.swift. Its transforms are idempotent — harmless on an already-correct spec — so pinning --ref to an upstream fix lets the retyping become a no-op. See the Tech Debt doc.
Documentation
swift package generate-documentation (via swift-docc-plugin) or Product ▸ Build Documentation in Xcode; also hosted on the Swift Package Index (see .spi.yml). Start with the Design, Roadmap, Tech Debt, and Upstream Spec Fix articles.
License
Apache 2.0 — see LICENSE.txt.
Package Metadata
Repository: laconicman/swift-gitlab
Default branch: main
README: README.md