apigee2openapi - A Node.Js command line tool to generate a OpenAPI 2.0 spec from Apigee API proxies

Hello Everyone,

We have a new tool that will help you connect a missing piece in the Apigee developer ecosystem. I am sure many of you love SmartDocs in the Apigee Developer Portal. SmartDocs, which allow you to create documentation for your APIs using a beautiful Swagger-like UI, are generated from either a WADL or a OpenAPI 2.0 specification. One thing that was missing, though, was out-of-the-box support for generating SmartDocs directly from your Apigee Edge API proxies.

The apigee2openapi tool will help you bridge that gap to some extent. In this article, I'll describe apigee2openapi and show you how to use it.

apigee2openapi

apigee2openapi is a Node.JS command line tool that will help you convert an Apigee API proxy to a Swagger 2.0 spec that can be used to generate SmartDocs. (It does the opposite of what the swagger2api tool does: lets you generate Apigee API proxies from openapi 2.0 specs.)

Installation

Installing apigee2openapi is as simple as any other node module from NPM. Requirements to use this tool are Node.JS and NPM. You can install this tool by running the following command after you have Node.JS and NPM installed on your local machine.

$ sudo npm install -g apigee2openapi

Once you have apigee2openapi installed, you are ready to generate a OpenAPI 2.0 spec from API proxies. In this article, I'll use the popular Swagger 2.0 Petstore API to first create an API proxy, then generate a OpenAPI 2.0 spec from that proxy.

Here's what apigee2openapi does:

  • Queries for Apigee Edge API proxy details.
  • Downloads the API proxy bundle.
  • Unzips the bundle and reads the API proxy XML files.
  • Generates OpenAPI JSON files. (It currently supports only JSON. You can generate YAML from JSON using API Studio as described later in this article.)
  • apigee2openapi supports multiple proxy endpoints.

How to use apigee2openapi (Earlier called Apigee2Swagger)

First, create an Apigee API proxy that will later be converted to a OpenAPI 2.0 spec.

Create the API proxy

Attached to this article is the petStore sample API proxy that you can import into your own Apigee Edge environment. The following image shows this being done in the Edge management UI. (The process is described here in the Apigee documentation.)

1152-screen-shot-2015-09-13-at-113707-am.png

You can also generate the API proxy from a OpenAPI 2.0 spec using the swagger2api tool using the following command.

$ swagger2api generateApi petStore -s <a href="http://petstore.swagger.io/v2/swagger.json">http://petstore.swagger.io/v2/swagger.json</a> -D -d /Users/Anil/Desktop/

Your petStore API proxy should look like the following once you have successfully imported it into your Edge environment.

1154-screen-shot-2015-09-13-at-115434-am.png

Generate the OpenAPI spec

Now generate the OpenAPI 2.0 spec from the API Proxy using apigee2openapi

Run the following command in a terminal. Change the the path in option -d to the destination directory on your local machine where you want to download the API proxy and generated Swagger files.

$ apigee2openapi -d /Users/Anil/Documents

When you run the command, you'll be prompted for the following:

  • Base URI ? https://api.enterprise.apigee.com
  • Org Name ? [your Edge organization name]
  • User ID ? [your Edge organization administrator email address]
  • Password ? [your Edge organization administrator password]
  • API Proxy Name ? [the name of the API proxy. In our case, it's petStore]
  • Revision Number ? [the API proxy revision number]
  • API Proxy End Point ? [the API proxy target endpoint URL]

1155-screen-shot-2015-09-13-at-122116-pm.png

The OpenAPI 2.0 spec is generated from the Apigee API proxy and stored in the local directory specified; for example, /Users/Anil/Documents/petStore/petStore.json. The contents of petStore.json should look like this:

{
  "swagger": "2.0",
  "info": {
    "description": "Swagger Petstore",
    "version": "1.0.0",
    "title": "petStore",
    "contact": {
      "email": "asagar.nodeapp@gmail.com"
    }
  },
  "host": "asagarnodeapp-test.apigee.net",
  "schemes": [
    "https"
  ],
  "basePath": "/petStore",
  "paths": {
    "/pet": {
      "put": {
        "operationId": "updatePet",
        "summary": "Update an existing pet",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/pet/findByStatus": {
      "get": {
        "operationId": "findPetsByStatus",
        "summary": "Finds Pets by status",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/pet/findByTags": {
      "get": {
        "operationId": "findPetsByTags",
        "summary": "Finds Pets by tags",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/pet/{petId}": {
      "delete": {
        "operationId": "deletePet",
        "summary": "Deletes a pet",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        },
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ]
      }
    },
    "/pet/{petId}/uploadImage": {
      "post": {
        "operationId": "uploadFile",
        "summary": "uploads an image",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        },
        "parameters": [
          {
            "name": "petId",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ]
      }
    },
    "/store/inventory": {
      "get": {
        "operationId": "getInventory",
        "summary": "Returns pet inventories by status",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/store/order": {
      "post": {
        "operationId": "placeOrder",
        "summary": "Place an order for a pet",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/store/order/{orderId}": {
      "delete": {
        "operationId": "deleteOrder",
        "summary": "Delete purchase order by ID",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        },
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ]
      }
    },
    "/user": {
      "post": {
        "operationId": "createUser",
        "summary": "Create user",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/user/createWithArray": {
      "post": {
        "operationId": "createUsersWithArrayInput",
        "summary": "Creates list of users with given input array",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/user/createWithList": {
      "post": {
        "operationId": "createUsersWithListInput",
        "summary": "Creates list of users with given input array",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/user/login": {
      "get": {
        "operationId": "loginUser",
        "summary": "Logs user into the system",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/user/logout": {
      "get": {
        "operationId": "logoutUser",
        "summary": "Logs out current logged in user session",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        }
      }
    },
    "/user/{username}": {
      "delete": {
        "operationId": "deleteUser",
        "summary": "Delete user",
        "responses": {
          "200": {
            "description": "successful operation"
          }
        },
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "type": "string"
          }
        ]
      }
    }
  }
}

Now copy that JSON and use apistudio.io to test the generated OpenAPI 2.0 spec.

Navigate to http://apistudio.io/ and click Get Started to open the editor. In the menu, select File > Paste JSON, paste the JSON into the window (there's currently a bug that won't let you see the pasted text), and click Import. You'll see the petStore Swagger doc in the right pane.

That's it!

To view the doc in the Swagger UI, select File > View SwaggerUI, then click the Show/Hide link. The doc should look like the following. You can also go here and click Show/Hide to see a sample.

Please keep us posted with your comments / suggestions about apigee2openapi

Cheers,

Anil Sagar

Comments
jonesfloyd
Staff

This is awesome, @Anil Sagar! What a great tool. Please move it to whichever forum you want. View revisions to see the detailed edits. I added a couple of navigation tips to the Swagger UI section and updated the link to the example output. Ping me if you have any questions. (This comment is visible only to you and Apigeek moderators.)

anilsr
Staff

Thank you @Floyd Jones 🙂

Not applicable

Getting a segmentation fault for on-premises installation. Any idea what the issue could be?

Getting a segmentation fault. On-premises installation.

➜ apigee2swagger apigee2swagger -d .
? Base URI? http://hub-646.hub.com:8080
? Organization? hub
? User Id? hubteam@hub.com
? Password? ************************
? API Proxy Name ? Eligibility
? Revision Number ? 1
? API Proxy End Point ? http://hub-644.com:9001/rhfapi-1/v1
Downloaded Bundle from Apigee: ./Eligibility/Eligibility.zip
[Error: invalid signature: 0x8080014]
{ [Error: invalid code lengths set] errno: -3, code: 'Z_DATA_ERROR' }
[Error: invalid signature: 0x8080014]
{ [Error: invalid block type] errno: -3, code: 'Z_DATA_ERROR' }
[Error: invalid signature: 0x8080014]
{ [Error: invalid stored block lengths] errno: -3, code: 'Z_DATA_ERROR' }

[1] 88521 segmentation fault apigee2swagger -d .

anilsr
Staff

@Michael Zatko , Which operating system are you using ? I haven't tested it on windows.. I have tested only on mac, linux should work too...

Seems like bundle got downloaded, can you verify bundle contents are vaild ? It might be zip extraction error..

Not applicable

On a Mac.

I ran the script against another proxy and it worked. There must be something specific to the other proxy's zip that is causing the error... not sure what that would be.

Also, I tried running the script against another local edge environment which has a locally signed SSL certificate on it and get the following:

{ [Error: unable to verify the first certificate] code: 'UNABLE_TO_VERIFY_LEAF_SIGNATURE' }

I have the certs trusted in my local keychain.

Relevant:

http://stackoverflow.com/questions/20082893/unable-to-verify-leaf-signature

Not applicable

I have an APIGEE service which I tried to create the swagger json. It was successful but the paths were empty.

Should the APIGEE proxy be created with Swagger docs for apigee2swagger to create the json with all the paths?

anilsr
Staff

@Sudheendra.Singh , It creates paths only if conditional flows exist in your API proxy, otherwise there is no way to read paths information since paths data is only available during API runtime not in the proxy bundle.

Not applicable

I have added condition and it seems to be working.

I am now able to make the path dynamic via condition and enter data on SmartDoc request page.

I am able to edit the swagger json and laod it on SmartDocs and it works.

How can I make the header also dynamic such that I should be able to enter header data while submitting request?

santosh_ghalsas
New Member

Hi @Anil Sagar

Does this tool works on windows now? I tried testing this on windows for one of the proxy and it gave me error like - [Error: Received error 404 when fetching proxy: [object Object]]

Thanks,

Santosh

anilsr
Staff

@santosh_ghalsasi , I haven't tested it on windows. Above error seems like proxy not found. Are you sure you have given right proxy name ?

santosh_ghalsas
New Member

@Anil Sagar - Yes, I tried this with different proxies but still got same error.

chungss
New Member

Hello,

I tried to run the tool on a Windows environment using the petStore sample but received error 400. Is there a way to find out what went wrong?

C:\Users\xxx>apigee2openapi -d c:\users\xxx
? Base URI? http://x.x.x.89:9001
? Organization? xxx-org
? User Id? xxx-user
? Password? **********
? API Proxy Name ? petStore
? Revision Number ? 1
? API Proxy End Point ? http://x.x.x.89:9001
[Error: Received error 400 when fetching proxy: [object Object]]
anilsr
Staff
@Joseph Chung

Welcome to Apigee Community. Are you sure Base URI is your Management API server URI ? Above tool failed to find the proxy using management API. Also, Are you using org admin credentials ?

Can you verify below curl call gives success response ? Update the base64 encode.

curl -X GET -H "Authorization: Basic XXXXXX" -H "Cache-Control: no-cache" "http://10.89.89.89:9001/v1/organizations/jaganr1000"
chungss
New Member

Hello @Anil Sagar,

Thanks for the guidance. I have re-executed the command with the correct Base URI, using an org admin credentials. Kindly refer to the output below:

C:\Users\xxx>apigee2openapi -d c:\users\xxx
? Base URI? http://x.x.x.88:9000
? Organization? xxx-org
? User Id? xxx-user
? Password? **********
? API Proxy Name ? petStore
? Revision Number ? 1
? API Proxy End Point ? http://x.x.x.89:9001
[Error: Received error 404 when fetching proxy:

<!DOCTYPE html>
<html>
<head>

...HTML 404 page, too long to be listed here...

Here is the curl response:

C:\Users\xxx>curl -X GET -H "Authorization: Basic xxx" -H "Cache-Control: no-cache" "http://x.x.x.88:9000/v1/organizations/xxx"

<!DOCTYPE html>
<html>
<head>

...HTML 404 page, too long to be listed here...<br>

Note: Actual Base64 encoded value removed from the above.

Appreciate if you can help to point out what went wrong. Will gladly provide more information if needed.

Thanks!

anilsr
Staff

@Joseph Chung , Management UI runs on port 9000, Management API by default should be running on port 8080 , can you please try Base URI as "http://10.89.20.88:8080" ?

chungss
New Member

Thank you @Anil Sagar! It seems to work now:

C:\Users\xxx>apigee2openapi -d c:\users\xxx
? Base URI? http://x.x.x.88:8080
? Organization? xxx-org
? User Id? xxx-user
? Password? **********
? API Proxy Name ? petStore
? Revision Number ? 1
? API Proxy End Point ? http://x.x.x.89:9001
Downloaded Bundle from Apigee: c:\users\xxx/petStore/petStore.zip
openapi JSON File successfully generated in : c:\users\xxx/petStore/petStore.json<br>
anilsr
Staff

Cool, Glad issue is resolved @Joseph Chung , Keep us posted moving forward if any.

benrodriguez
New Member

I really liked this tool but when I try to use it i'm receiving a

[Error: invalid signature: 0x6a626f5b]

I tried it on multiple computers(windows and macs) and I get the same error. Has anybody else seen this issue?

anilsr
Staff

@Ben Rodriguez , I haven't seen this error. Looks like unzipping the bundle issue. Do you see proxy getting downloaded into your machine ? Do you see proxy bundle folder / zip file in your machine ?

BTB, On a separate note, Did you get a chance to play with http://specgen.apistudio.io/ ? It also helps to generate OpenAPI spec from existing API. Keep us posted.

naggc
New Member

SpecGen seems to be down for couple days... 😞

Not applicable

I get the tool to run successfully against a on-prem version of apigee with the petstore api but I am not gettting all the API paths and parameters. When I run against one of my APIs the paths are empty but the header information is there. Any suggestions?

vinitaoist-1
New Member

Please check the condition you have applied in the flow.

If you have applied a condition like this <Condition>(proxy.pathsuffix MatchesPath "/pet/findByStatus") and (request.verb = "GET")</Condition> it will work.
But you will not get path for

<Condition>(proxy.pathsuffix = "/pet/findByStatus") and (request.verb = "GET")</Condition> it will work not work.

This might be the issue with your API.

Not applicable

Question: when trying to run this against a local bundle, I get "error: unknown option '-l'

why is this? looking at the code, it looks like it supports running against local Apigee bundles...

anilsr
Staff
@Don Long

It should work with -l, just try with --local if it doesn't. For more info see code in github.

terrancedavid
New Member

You make the statement:

"It creates paths only if conditional flows exist in your API proxy, otherwise there is no way to read paths information since paths data is only available during API runtime not in the proxy bundle."

But having conditional flows is not sufficient, is it?

You must have a "request.verb" test in the condition, or it will not create the entry.

What happens if your condition has more than 1 request.verb test? (like GET && POST)?

Will that work?

aneeshananthakr
New Member

Hi,

Tool doesn't seem to work if all the conditional flows for resources are defined in TargetEndpoint (I don't get any errors; just that it creates swagger for the dummy 'default' conditional flow <Condition>(proxy.pathsuffix MatchesPath "/") and (request.verb = "GET")</Condition> defined in ProxyEndoint).

Anyway to add another config input to specify Proxy vs Target for conditional flows?

Thanks,

Aneesh.

Not applicable

Installing apigee2openapi shows four warnings on Linux (Ubuntu / Mint) that I want to note. These were:

sudo npm install -g apigee2openapi<br>
npm WARN deprecated node-uuid@1.4.8: Use uuid module instead<br>
npm WARN deprecated to-iso-string@0.0.2: to-iso-string has been deprecated, use @segment/to-iso-string instead.<br>
npm WARN deprecated jade@0.26.3: Jade has been renamed to pug, please install the latest version of pug instead of jade<br>
npm WARN deprecated minimatch@0.3.0: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue

First run does not work, so I've installed the required tools:

sudo apt-get install nodejs 
sudo apt-get install npm 
sudo apt-get install nodejs-legacy 

Example "petStore" works for me. Just to point out that:

  • Base URI: just hit Enter
  • Organization: Org Name AND environment-name
  • API Proxy Name: in my case, not "petStore", but "1151-petstore-rev1-2015-09-13"

Second run works for me.

Not applicable

I'm not getting any parameters in the generated JSON. I tried with your petstore example also. The generated json does not look like the one you have shown above.

Not applicable

I gave the following command:

C:\Users\krishna.seetharaman>apigee2openapi -d D:\

Base URI(https://api.enterprise.apigee.com)https://krishnaseetharaman-eval-test.apigee.net Organization?krishnaseetharaman-eval

User Id? krishna.seetharaman@aspiresys.com ?

Password? **********

API Proxy Name ? firstproxy

Revision Number ? 3

API Proxy End Point ? https://krishnaseetharaman-eval-test.apigee.net

It gave the below error:

Error: Received error 404 when fetching proxy: [object Object] at Request._callback (C:\Users\krishna.seetharaman\AppData\Roaming\npm\node_ modules\apigee2openapi\lib\downloadApi.js:39:12) at Request.self.callback (C:\Users\krishna.seetharaman\AppData\Roaming\npm\n ode_modules\apigee2openapi\node_modules\request\request.js:185:22) at emitTwo (events.js:126:13) at Request.emit (events.js:214:7) at Request.<anonymous> (C:\Users\krishna.seetharaman\AppData\Roaming\npm\nod e_modules\apigee2openapi\node_modules\request\request.js:1157:10) at emitOne (events.js:116:13) at Request.emit (events.js:211:7) at IncomingMessage.<anonymous> (C:\Users\krishna.seetharaman\AppData\Roaming \npm\node_modules\apigee2openapi\node_modules\request\request.js:1079:12) at Object.onceWrapper (events.js:313:30) at emitNone (events.js:111:20)


Can you please advise what is the reason?

anilpaduchuri
New Member

@Anil Sagar, I have scenario where my apigee resources are like :

GET : /api/clients

POST : /api/clients

node module : apigee2openapi

Generated spec has only one end point with POST /api/clients ,GET is missing.

Please let me know if node module is not handling this scenario . pets example shown in this thread have different end points. Thanks in Advance.

Thanks

Anil P

dieterrandolph-
New Member

Hello -- I'm a huge fan of this tool, but now I'm getting a strange error ("ENAMETOOLONG: name too long, mkdir '/Users/dieter.randolph/desktop/docspock/udr/ources/xsl/deletecontact-add-namespace.xslt�W�o�6~�_q�K�2��#N���݀�" and then some) when I try to use it. Any guidance you can offer would be most welcome. Thanks!

talhasiddique10
New Member

Hello!

I face the following error kindly guide me:

"primordials is not defined"

Thanks!

vgapi2020
New Member

The above article does not mentions the required version of NodeJs, etc.

I am using Windows 10 with latest NodeJs version and getting below error,

fs.js:39 } = primordials; ^ ReferenceError: primordials is not defined

at fs.js:39:5 at req_

(C:\Users\...\AppData\Roaming\npm\node_modules\apigee2openapi\node_modules\natives\index.js:143:24) at Object.req [as require] (C:\Users\...\AppData\Roaming\npm\node_modules\apigee2openapi\node_modules\natives\index.js:55:10) at Object.<anonymous> (C:\Users\...\AppData\Roaming\npm\node_modules\apigee2openapi\node_modules\graceful-fs\fs.js:1:37) at Module._compile (internal/modules/cjs/loader.js:1200:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:1220:10) at Module.load (internal/modules/cjs/loader.js:1049:32) at Function.Module._load (internal/modules/cjs/loader.js:937:14) at Module.require (internal/modules/cjs/loader.js:1089:19) at require (internal/modules/cjs/helpers.js:73:18)

The tool seems to be some pet project and the owner facing challenges with maintaining/supporting it. Why Apigee cannot provide a reliable and stable version of the tool and make this an option to export OpenAPI spect out of existing API Proxies in its online Edge tool UI?

always200
Bronze 1
Bronze 1

It runs for me when i have the proxy zip file downloaded manually in my local machine. 

Command 

$ apigee2openapi -d /Downloads

 

  • Base URI ? https://api.enterprise.apigee.com/v1
  • Org Name ? org name
  • User ID ? emailid
  • Password ? password
  • API Proxy Name ? Proxy Name
  • Revision Number ? 1
  • API Proxy End Point ? i am providing the virtual host url here.

can somebody help here?

@anilsr @ssvaidyanathan @jonesfloyd 

@always200 - this tool is not maintained currently. You can fork the repo and fix it if needed.

 

@anilsr - pls suggest what can be done

anilsagar
Staff

Unfortunately, Tool is no longer maintained. As Sai says, Please fork the repo and fix if needed.

Version history
Last update:
‎09-12-2015 11:14 PM
Updated by: