OpenAPI Integration with DocC Project
Hi Everyone!
I've been working on OpenAPI Integration with DocC Project for the Google Summer of Code @Swift Project.
I'm excited to share my current progress on integrating OpenAPI specifications with DocC documentation. This project aims to create a seamless experience for Swift developers by converting OpenAPI documents into DocC compatible documentation, making API references consistent with the rest of the Swift ecosystem.
Current Progress
I've developed a working conversion tool that transforms OpenAPI documents into SymbolKit symbol graphs, which can then be processed by DocC to generate documentation.
Mapping OpenAPI to SymbolKit
Mapping OpenAPI to SymbolKit starts with defining a central container. A top level module symbol, that acts as the root of the API structure. Everything else is organised under this container to form a clear, modular layout that reflects the overall design of the API.
Each schema or model in the OpenAPI document is turned into a corresponding symbol in SymbolKit. The properties within these schemas are mapped as variables, with their types, constraints, and descriptions all preserved. This helps ensure the documentation remains accurate, readable, and fully aligned with the API's intended behavior.
API operations, like GET
and POST
are handled like functions. Each one includes its input parameters such as path, query, and body data and clearly defines what it returns by linking to the right model. This gives a structured, predictable view of how the API behaves.
To tie everything together, we define relationships between these symbols using SymbolKit’s built in types like .memberOf
and .returns
. These links show how different pieces are related, for example, which functions belong to which modules, and which models are returned from which endpoints. The result is a clean, well organised symbol graph that makes the entire API easy to explore and document using DocC.
Right now, most of this logic lives in the SymbolMapper
struct located in Sources/SymbolMapping.swift
, which implements the core logic for mapping OpenAPI elements to SymbolKit
symbols.
OpenAPISymbolKind
Enum
Defines internal symbol types (.namespace
, .endpoint
, .schema
) for mapping OpenAPI content to SymbolKit constructs.
enum OpenAPISymbolKind {
case namespace
case endpoint
case schema
case property
}
mapSchemaType
Function
This function takes an OpenAPIKit.JSONSchema
and recursively maps OpenAPI data types to their Swift equivalents, extracting constraints along the way.
static func mapSchemaType(_ schema: OpenAPIKit.JSONSchema) -> String {
switch schema.coreContext.type {
case .string:
return "String"
case .number:
return "Double"
case .integer:
return "Int"
case .boolean:
return "Bool"
case .array:
if let items = schema.items {
return "[\(mapSchemaType(items))]"
}
return "[Any]"
case .object:
default:
return "Any"
}
}
createSymbol
Function
Creates a symbol based on the given kind, name, identifier, and path. Converts OpenAPISymbolKind
into SymbolKit
types like .schema → swift.struct
.
static func createSymbol(
kind: OpenAPISymbolKind,
identifier: String,
title: String,
description: String?,
pathComponents: [String]
) -> (SymbolGraph.Symbol, SymbolGraph.Relationship?)
createOperationSymbol
Function
Builds symbols for HTTP methods like GET
, POST
, etc., combining route metadata and linking it to relevant schemas.
static func createOperationSymbol(
operation: OpenAPI.Operation,
path: String,
method: String
) -> (symbol: SymbolGraph.Symbol, relationships: [SymbolGraph.Relationship]) {
createSchemaSymbol
Function
Maps each schema into a swift.struct
, including nested properties and relationships back to parent models.
static func createSchemaSymbol(
name: String,
schema: OpenAPIKit.JSONSchema
) -> (symbol: SymbolGraph.Symbol, relationships: [SymbolGraph.Relationship]) {
All the above logic comes together to generate a SymbolGraph
, which DocC then uses to build final documentation.
let symbolGraph = SymbolKit.SymbolGraph(
metadata: SymbolKit.SymbolGraph.Metadata(
formatVersion: SymbolKit.SymbolGraph.SemanticVersion(major: 1, minor: 0, patch: 0),
generator: "OpenAPItoSymbolGraph"
),
module: SymbolKit.SymbolGraph.Module(
name: "API",
platform: SymbolKit.SymbolGraph.Platform(/* details */)
),
symbols: symbols,
relationships: relationships
)
I've added a code base link for the complete mapping process as this post just summarizes the mapping process. You can refer to the code base if I missed something here.
OpenAPI to Symbol Graph Code link
So far, I’ve only used existing SymbolKit symbol kinds - I haven't needed to create new ones.
Swift Build Command Output
$ swift build
Building for debugging...
[7/7] Linking openapi-to-symbolgraph
Build complete! (1.37s)
After building, I ran a sample API file
$ swift run openapi-to-symbolgraph api.yaml
Building for debugging...
[7/7] Applying openapi-to-symbolgraph
Build of product 'openapi-to-symbolgraph' complete! (1.37s)
Parsing YAML...
Processing paths...
Processing schemas...
Symbol graph generated at /Users/ayushsrivastava/OpenAPI-integration-with-DocC/openapi.symbolgraph.json
This confirms that the tool is working as expected and the generated symbolgraph.json
is ready for DocC conversion.
This .json
symbol graph is then processed by DocC to produce user friendly documentation.
"metadata": {
"formatVersion": { "major": 0, "minor": 5, "patch": 0 },
"generator": "openapi-to-symbolgraph"
},
"module": { "name": "API", "platform": {} },
"symbols": [
{
"identifier": { "precise": "API", "interfaceLanguage": "swift" },
"kind": { "displayName": "Module", "identifier": "swift.module" },
"names": { "title": "PetStore API" },
"docComment": { "lines": [{ "text": "A sample Pet Store API" }] }
},
{
"identifier": { "precise": "s:API.Pet", "interfaceLanguage": "swift" },
"kind": { "displayName": "Struct", "identifier": "swift.struct" },
"names": { "title": "Pet" },
"docComment": { "lines": [{ "text": "A pet in the store" }] }
}
],
"relationships": [
{
"source": "s:API.Pet",
"target": "API",
"kind": "memberOf"
Symbol graph contains API information for DocC.
dependencies: [
.package(url: "https://github.com/mattpolzin/OpenAPIKit.git", from: "3.1.0"),
.package(url: "https://github.com/swiftlang/swift-docc-symbolkit.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-argument-parser.git", from: "1.2.0"),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.0"),
This tool reads OpenAPI documents in YAML or JSON formats using the OpenAPIKit library
. It takes the entire API structure, including operations, schemas, and relationships, and maps everything into a symbol graph.
This process keeps all the detailed documentation, like descriptions, examples, and status information, intact. After building the symbol graph, the tool outputs a standard JSON file that DocC can process to generate the final, user friendly documentation.
The conversion process involves parsing the OpenAPI document, creating and mapping a symbol graph, linking together all the elements, and then using DocC to produce the final documentation.
Right now, the tool can successfully parse OpenAPI documents.
Read the OpenAPI document
Creates valid symbol graph files
Handles schemas, operations, and their relationships
Has some symbol resolution issues when generating DocC documentation. In coming days, I will try to solve this issue while creating a REST API example.
I'm working on creating a publicly accessible example of a REST API documented with DocC. Currently, test APIs generate valid symbol graphs, but the final DocC integration needs some enhancement before sharing a public demo. But I'll have a well crafted example for a REST API that is documented using DocC before the Google Summer of Code period begins.
You can check out the initial project approach on GitHub
OpenAPI Integration with DocC
Solution
swift run openapi-to-symbolgraph <path-to-openapi.json>: Runs the tool to parse the OpenAPI document and generate `symbolgraph.json`.
docc convert symbolgraph.json --output-path docs: Converts the generated SymbolGraph into HTML documentation
Once we run the command to convert the symbolgraph.json into HTML documentation, the resulting files will be in the docs folder. Then we can host the static docs folder generated by DocC on an HTML server.
After that we can view the generated documentation for a sample User API at
https://ayushshrivastv.github.io/OpenAPI-integration-with-DocC/
While working on the issue in the repository OpenAPIKit, where I was attempting to add a validation that checks all operationIds in Link objects are valid
, during the debugging process I got a better approach from my initial thinking of how we can use the mapping process, and I've started working on that approach as well.
For that, I've opened a pull request that proposes different approaches to the mapping process https://github.com/ayushshrivastv/OpenAPI-integration-with-DocC/pull/34. At present, I'm trying to work on branch before merging it to the main, where initial development is ongoing.
Additionally, these two pull requests have been successfully "Merged" into the OpenAPIKit Code base.
Thank you, @mattpolzin, for taking your time and assisting me!
I’ve spent the last few weeks working on this project and reading the surrounding documentation and code, and this post serves as my current progress after a month!
Since you all have more experience working with OpenAPIKit and DocC Codebases. If you guys can look into the actual code, that would be really helpful to clarify things.
In the coming weeks, I’ll first attempt to generate a REST API documented using DocC. I’ll also improve the code line up, as there are some version related warnings that are need to be addressed. Additionally, I’ll further enhance the path, schema, and query functions for mapping process and api operations.
I'd love to hear your feedback @sofiaromorales @ktoso @Honza_Dvorsky on the mapping approach and any suggestions for improving the integration between OpenAPI and DocC from the Swift community that will be highly helpful!
Thank you, and I look forward to your feedbacks!
Ayush Srivastava