Swagger definitions parsing to simplified JS Objects (Complex Object manipulation)

Viewed 374

I'm trying to build some documentation to my project with TypeDoc, Swagger and SwaggerJsDoc. Since TypeDoc and swagger have different annotation types and Swagger annotations are much more detailed I want TypeDoc to read my Swagger annotations. I've managed to tap into TypeDoc's comment parser and successfully created beautiful custom documentation for my code and API combined, like this for example:

Documentation generated with Typedoc

I'm pretty exited with this but having a reeeal hard time parsing Swagger's schema definition into plain Javascript objects to show my response or Body examples. Swaggers definitions are too complex, in my opinion. They could be greatly simplified while keeping the same information. They come like this:

  {
    "type": "object",
    "properties": {
      "minStockProds": {
        "type": "array",
        "items": {
          "type": "object",
          "properties": {
            "sku": {
              "type": "string"
            },
            "minStock": {
              "type": "number"
            },
            "ref": {
              "type": "string"
            }
          }
        }
      },
      "ordersCount": {
        "type": "number"
      }
    }
  }

Or this!, to be extreme:

{
        "type": "object",
        "properties": {
          "test": {
            "type": "object",
            "properties": {
              "test1": {
                "type": "string"
              },
              "test2": {
                "type": "object",
                "properties": {
                  "test3": {
                    "type": "number"
                  },
                  "test4": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "test5": {
                          "type":"string"
                        },
                        "test6": {
                          "type": "number"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "test7": {
            "type":"array",
            "items":{
              "type": "object",
              "properties": {
                "name":{
                  "type": "string"
                },
                "value": {
                  "type": "number"
                }
              }
            }
          }
        }
      }

how can I parse it to this?

{
  minStockProds: [
    {
      sku: "string",
      minStock: "number",
      ref: "string"
    }
  ],
  ordersCount: "number",
}

or, this?

{
  test: {
    test1: "string",
    test2: {
      test3: "number",
      test4: [
        {
          test5: "string",
          test6: "number",
        }
      ]
    }
  },
  test7: [
    {
      name: "string",
      value: "number",
    }
  ]
}

I have tried so many ways to adapt to all these types of object that my code now looks horrible and confusing to display here, it would be an effort to read through it.

Could anyone give a hint or tell a library that could facilitate this for me? no need to resolve this entirely, only looking for options. I've even tried to look into the Swagger-UI package to see how they do it, but still searching for the functions that do it.

Thank you very much!

1 Answers

After lots of head banging against the wall I managed to come um with something like this. Not beautiful at all, but it works. I'm going to post it here because I wouldn't want anyone to go through days of trial and error like I did.

function sanitizeObjectPropertyTypes(swaggerObj) {
  let copyObj = JSON.parse(JSON.stringify(swaggerObj));
  if(copyObj.$ref){
    copyObj = copyObj.$ref;
  } if (copyObj.description) {
    delete copyObj.description;
  }

  let parsedObj = {};

  function parse(obj, current) {
    let ikey;
    let value;
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        value = obj[key];
        ikey = current ? `${current}.${key}` : key;
        if (typeof value === 'object') {
          parse(value, ikey);
        } else if (ikey !== 'type') {
          const path = ikey.replace(/(properties|\.properties|\.items|\.schema|\.type)/g, '').replace(/^\.*|\.*$/, '').replace('..', '.');
          lodash.set(parsedObj, path, obj[key]);
        }
      }
    }
  }

  function insertArray(obj) {
    function recurse(objRec) {
      const keys = Object.keys(objRec);
      for (let i = 0; i < keys.length; i++) {
        if (typeof objRec[keys[i]] === 'object') {
          if (objRec[keys[i]].type === 'array') {
            const path = getObjPathByKey({ obj, key: keys[i] })[0].replace(/(properties|\.properties|\.items|\.schema|\.type)/g, '').replace(/^\.*|\.*$/, '').replace('..', '.');
            const val = lodash.get(parsedObj, path);
            lodash.set(parsedObj, path, [val]);
          }
          recurse(objRec[keys[i]]);
        }
      }
    }
    recurse(obj);
    if (parsedObj.items) {
      parsedObj = [parsedObj.items];
    }
    if(parsedObj.schema){
      parsedObj = parsedObj.schema;
    }
  }
  parse(copyObj, '');
  insertArray(copyObj);

  return parsedObj;
}
Related