Article
· Oct 2 5m read

Automating IAM Configuration from OpenAPI Specs 2.0 with ObjectScript

Why This Matters

Managing IAM can be tedious when done manually — especially when your APIs are already well-documented using OpenAPI (Swagger) specs. Wouldn't it be great if you could automatically generate Kong services and routes directly from your OpenAPI spec?

That's exactly what this ObjectScript method does: it reads an OpenAPI 2.0 spec stored in the XData block of your spec class and generates a decK-compatible YAML file that can be used to sync your IAM configuration.

This approach:

  • Reduces manual configuration errors
  • Keeps your gateway in sync with your API spec
  • Speeds up deployment and onboarding

Prerequisites:

  • InterSystems IRIS or IRIS based platform
  • InterSystems API Manager
  • Deck CLI tool

What the Method Does

The method ConvertOpenAPIXDataToDeckYAML:

  1. Reads the OpenAPI spec from an XData block named OpenAPI in a given class.
  2. Parses the JSON into a dynamic object.
  3. Extracts endpoints and HTTP methods.
  4. Generates a YAML file that defines:
    • A Kong service pointing to the API host and base path
    • Routes for each endpoint
    • A rate-limiting plugin on each route (optional enhancement)

Example Spec Class

You can use the below sample spec class or use the class generated from posting the spec file that is included in the previous post linked below.

Class MyApp.spec
{
XData OpenAPI [ MimeType = application/json ]
{
{
  "swagger": "2.0",
  "host": "api.example.com",
  "basePath": "/v1",
  "paths": {
    "/users": {
      "get": { "summary": "Get users" },
      "post": { "summary": "Create user" }
    },
    "/products": {
      "get": { "summary": "Get products" }
    }
  }
}
}
}

The Method and Use

Below is the ClassMethod. You can of course tweak to suit your needs.

/// Convert OpenAPI XData to Deck YAML
ClassMethod ConvertOpenAPIXDataToDeckYAML(specClassName As %String, outputFilePath As %String = "") As %Status
{
    Try {
        // Read the XData block named "OpenAPI"
        Set reader = ##class(%Dictionary.XDataDefinition).%OpenId(specClassName _ "||OpenAPI")
        If reader = "" {
            Write "Error: XData block 'OpenAPI' not found in class ", specClassName, !
            //Quit $$$ERROR
        }
        // Read the stream content into a string
        Set stream = reader.Data
        Set specJSON = ""
        While 'stream.AtEnd {
            Set specJSON = specJSON _ stream.ReadLine()
        }
        // Test call
        //Do ##class(ConsentAPI.Utils).ConvertOpenAPIXDataToDeckYAML("SpecAPI.spec")

        // Parse the JSON into a dynamic object
        Set spec = ##class(%DynamicObject).%FromJSON(specJSON)

        // Initialize YAML structure
        Set deckYAML = "services:" _ $CHAR(13)

        // Extract host and basePath
        Set host = $PIECE($SYSTEM, ":", 1)
        Set basePath = spec.basePath

        // Create service block
        Set deckYAML = deckYAML _ "  - name: " _ host _ $CHAR(13)
        Set deckYAML = deckYAML _ "    url: "_$c(34)_"http://" _ host _ basePath _$c(34)_ $CHAR(13)
        Set deckYAML = deckYAML _ "    routes:" _ $CHAR(13)

        // Iterate over paths
        Set pathIter = spec.paths.%GetIterator()
        While pathIter.%GetNext(.key, .value) {
            Set pathKey = key
            Set path = spec.paths.key
            Set routeName = $REPLACE(key , "/", "")
            Set deckYAML = deckYAML _ "      - name: " _ routeName _ $CHAR(13)
            Set deckYAML = deckYAML _ "        strip_path: false"_$CHAR(13)
            Set deckYAML = deckYAML _ "        preserve_host: false"_$CHAR(13)
            Set deckYAML = deckYAML _ "        paths:"_$CHAR(13)
            Set deckYAML = deckYAML _ "          - " _ pathKey _ $CHAR(13)
            Set deckYAML = deckYAML _ "        methods:"_$CHAR(13)
            Set methodIter = value.%GetIterator()
            While methodIter.%GetNext(.key, .value) {
                Set methodKey = key
                Set deckYAML = deckYAML _ "          - " _ $ZCONVERT(methodKey, "U") _ $CHAR(13)

            }
            Set deckYAML = deckYAML _ "        plugins:"_$CHAR(13)
            Set deckYAML = deckYAML _ "        - name: " _ "rate-limiting" _ $CHAR(13)
            Set deckYAML = deckYAML _ "          config:"_$CHAR(13)
            Set deckYAML = deckYAML _ $REPLACE($J("",12),"",$C(32))_"minute: 20" _ $CHAR(13)
            Set deckYAML = deckYAML _ $REPLACE($J("",12),"",$C(32))_"hour: 500" _ $CHAR(13)
        }

        // Output to file or console
        If outputFilePath '= "" {
            Set file = ##class(%Stream.FileCharacter).%New()
            Set file.Filename = outputFilePath
            Do file.Write(deckYAML)
            Do file.%Save()
            Write "YAML saved to: ", outputFilePath, !
        } Else {
            Write deckYAML, !
        }
        //Quit $$$OK
    } Catch ex {
        Write "Error: ", ex.DisplayString(), !
        //Quit ex.AsStatus()
    }
}

To use the method and have it generate a yaml file, just call it from a terminal session AKA IRIS CLI

Do ##class(MyUtils.APIConverter).ConvertOpenAPIXDataToDeckYAML("MyApp.spec", "/tmp/deck.yaml")

Or you can just print the yaml to console

Do ##class(MyUtils.APIConverter).ConvertOpenAPIXDataToDeckYAML("MyApp.spec")


What to Do Next

Once the YAML file is generated, you can use decK to sync it with your IAM instance:

deck gateway sync --workspace <WorkSpace> deck.yml

This will create or update services and routes in IAM based on your spec.


Final Thoughts

This method bridges the gap between spec driven development and gateway configuration. It’s ideal for teams using InterSystems IRIS or HealthShare and IAM in their architecture.

Want to extend it?

  • Include authentication plugins
  • Generate multiple services based on tags

Let me know in the comments or reach out if you'd like help customizing it!

Discussion (0)1
Log in or sign up to continue