npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@bagatka/openapi-swift

v0.1.1

Published

Writes a typed Swift 6 client of an HTTP API from its OpenAPI 3.1 document, such as Effect's HttpApi writes, on Foundation alone.

Readme

@bagatka/openapi-swift

Writes a typed Swift 6 client of an HTTP API from its OpenAPI 3.1 document, such as Effect's HttpApi writes, on Foundation alone.

Install

npm install @bagatka/openapi-swift effect

Its peer dependency is effect, at the minor version it is built with. It runs wherever a build script does: Bun, Node, or Deno. The Swift it writes needs Swift 6.2 or later, and Foundation alone: it runs on Apple's platforms and on Linux.

Use it

A build script that writes the Swift client of an API defined with Effect's HttpApi:

import { swiftClient } from "@bagatka/openapi-swift"
import { Effect, FileSystem, Schema } from "effect"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, OpenApi } from "effect/http-api"

// The API, as the server defines it: named schemas, which become Swift types.
class Note extends Schema.Class<Note>("Note")({ id: Schema.String, title: Schema.String }) {}
class NoteNotFound extends Schema.TaggedError<NoteNotFound>()(
  "NoteNotFound",
  { id: Schema.String },
  { httpApiStatus: 404 },
) {}
const NotesApi = HttpApi.make("Notes")
  .add(
    HttpApiGroup.make("notes").add(
      HttpApiEndpoint.get("getNote", "/notes/:id", { params: { id: Schema.String }, success: Note, error: NoteNotFound }),
    ),
  )
  .annotate(OpenApi.Title, "Notes")

const writeClient = Effect.gen(function* () {
  const swift = yield* swiftClient(OpenApi.fromApi(NotesApi))
  const fs = yield* FileSystem.FileSystem
  yield* fs.writeFileString("Sources/NotesAPI/NotesAPI.swift", swift)
})
// writeClient: Effect<void, UnsupportedOpenApi | PlatformError, FileSystem>. Run it with your
// runtime's FileSystem, such as NodeServices.layer from @effect/platform-node.
// UnsupportedOpenApi lists every problem at once, where and why:
// { path: "#/components/schemas/NoteList/properties/page", reason: "an inline object: name it as a schema of its own" }

The Swift it writes, for an API titled Notes:

func title(ofNote id: String, at url: URL, token: String) async -> String {
    let api = NotesAPI(baseURL: url, bearerToken: token, userAgent: "Notes/1.0 (12) iOS/27.1")
    do {
        return try await api.getNote(id: id).title
    } catch .noteNotFound(let missing) {
        return "No note \(missing.id)" // An error the API names, as its own type.
    } catch .unreachable {
        return "Offline" // No connection, a timeout, or a cancelled call: keep showing what was there.
    } catch {
        return "\(error)" // .unreadable or .unwritable: a status or a shape this client doesn't know, and why.
    }
}

Contract

src/index.ts. swiftClient takes the document as parsed JSON, such as OpenApi.fromApi gives or JSON.parse of a file, and returns the Swift file's text, or fails with UnsupportedOpenApi, whose problems say where and what to change, every one at once.

Does not own

  • Running it. A build script calls swiftClient and writes the file where the app's Xcode project or Swift package takes it.
  • What to do when a call fails: one request per call, never retried; offline, the app decides.
  • Authentication beyond a bearer token, and other headers; a transport the app passes can add them.

Depends on

effect.

Decisions and constraints

  • Doesn't trust the document's text. A document is usually the product's own, but no title, description or name in it can write code, and what isn't supported is refused. Trusts its caller, who chooses the document.
  • What it reads, as Effect's HttpApi writes it: OpenAPI 3.1; named objects, string enums, and unions of named objects told apart by the one constant property they share (such as _tag, and a discriminator that names it); arrays, dictionaries, free-form JSON ({}), nullable values (anyOf with null, or a type and null), dates (format: date-time), and Effect's numbers, which may be "Infinity", "-Infinity" or "NaN"; path and query parameters of strings, numbers, booleans, dates and enums; JSON bodies of any of these; one success status; and errors, 4xx and 5xx answers of named objects with one constant, all told apart by the same property. Keywords that only describe or validate a value, such as pattern or maximum, are the server's to check, and so is an allOf of such keywords alone, which Effect writes for a Schema's second check or a format beside a check (allOf: [{ "format": "date" }], a String). An integer, number or boolean with an enum of its own type's values, as Effect writes Schema.Literal(true) or Schema.Literals([1, 2]), is that type (Bool, Double; Int for integers); which of its values, the server checks.
  • What it refuses, each with where and why: an inline object, enum or union, which needs a name to become a Swift type; an allOf with any other keyword in it, such as type or $ref; an enum of other values than its type's; any keyword beside a union's members, such as an allOf with a type, anyOf and oneOf together, and a null member with more than its type; not, const, tuples (prefixItems) and any keyword it doesn't know; header and cookie parameters, arrays in a query; default and ranged responses such as 2XX; a body that isn't JSON or isn't required; an error without a JSON body; a type that holds itself other than in an array or a dictionary, which a Swift struct can't; names Swift can't hold, or that Swift, Foundation, or the client itself takes, such as Task, URLRequest, Self, KeyedDecodingContainer, or a property hashValue or RawValue; a schema nested more than 100 deep, references included; and a path that isn't / and segments of letters, digits, -, ., _, ~ and {parameters}, or holds a segment . or .., which could send a request, and its bearer token, to another address.
  • Limits. Time and memory linear in the document and the Swift it writes, whatever the document holds; a schema nests at most 100 deep, through references too, so no document exhausts the stack. The Swift can be longer than the document in one way: each method's doc comment lists its errors, so an error union many operations answer with is listed in each.
  • Effect's names. Effect names a schema's encoded form <Name>Encoded, which is <Name> in Swift, and its own errors effect_HttpApiError_<Name>Encoded, which is EffectHttpApiErrorBadRequest. A schema named <Name>_<n> that is the same as <Name>, a copy a document names when an operation annotates it, is <Name>'s type. Effect 4.0.6 writes a DateTimeUtcFromString as a plain string, without format: date-time, so it is a String in Swift; and query and path parameters as the strings they are encoded as.
  • Newer servers don't break older apps. An enum keeps a value it doesn't know, as a struct with static values rather than a closed enum; a union has an unknown case; unknown properties are ignored. A missing optional property is nil; a required one that may be null is written as null, never left out. An optional property that may also be null, such as Effect's optionalKey(NullOr(...)), is nil when it is missing or null, and left out when nil: the client can't send its null. Constants are written and checked both ways, so a struct sent on its own carries its _tag.
  • Swift 6, in any default isolation: every type is nonisolated, so the file compiles in an app target whose default is the main actor, as Xcode's new ones are, and in a library; value types are Sendable and Hashable; methods are @concurrent, so decoding never runs on the caller's actor; errors are typed (throws(APIError)). Names that aren't Swift identifiers are raw identifiers, .`1m` (Swift 6.2). The client's own names are raw identifiers too, and a document's that is one of them is refused: a property named JSON keys, a parameter named query items, request body or the answer. Any other name works, one of a type included: a property named String, Date or after one of the API's types reads as that property, since the client never writes a type where a property's or parameter's name could stand for it.
  • No text of the document can write code. Titles and descriptions become comments, their line breaks of every kind turned into comment lines; strings are literals with every control character escaped; every name, a constant's key included, is checked before it is written.
  • A path parameter is a segment of its own: its value is escaped, and one that is empty, . or .., which a URL reads as no segment or a step up, is unwritable and isn't sent.
  • Checked as Swift. bun run check:swift compiles the clients its tests write with Swift 6, warnings as errors, in both default isolations, and runs a round trip that calls the Notes API's client through a transport answering as Effect's server does, checking every request, body, result, and error against the JSON Effect writes (test/fixtures/).
  • Linux too: it imports FoundationNetworking where that exists.