2

So the goal is to have included only those endpoints (and its methods e.g. get, post...) which are defined in the configuration file.

Example structure object that holds all the endpoints.

et swaggerApis = {
  header: {
    propertyHeader: "valueHeader"
  },
  blocks: [
    {
      tags: ["Tenant & User"],
      paths: {
        "/tenants": {
          post: {
            property: "value"
          },
          get: {
            property: "value"
          }
        },
        "/tenants/{id}": {
          post: {
            property: "value"
          },
          get: {
            property: "value"
          },
          delete: {
            property: "value"
          }
        }
      }
    }
  ]
};

Example of the configuration file that holds only those endpoints and its methods we want to have included in the final object.

const CONFIG = {
  api: {
    include: {
      "/tenants/{id}": ["get"]
    }
  }
};

So far here is my second version of the JavaScript code that works but introduces a high cyclometric complexity and is hard to read. I'm pretty new to JavaScript and looking a way not just to improve this code.

function includeEnpointsByConfig(data) {
  for (let blockItem of data.blocks) {
    for (let path in blockItem.paths) { //console.log(blockItem.paths[path])
      let result = setMethodsOfEndpoint(path, blockItem.paths[path]);
      if (result === 'undefined') {
        delete blockItem.paths[path] // if the config does not contain, remove
      } else {
        blockItem.paths[path] = result;
      }
    }
  }
  return data;
}

function setMethodsOfEndpoint(path, value) {
  let newMethods = {};

  for (let confPath in CONFIG.api.include) {
    if (path === confPath) { // match endpoint in config and swaggerApis object
      if (CONFIG.api.include[confPath].length > 0) { // if array in config is not empty , filter
        for (let c of CONFIG.api.include[confPath]) { //console.log(c); // get
          for (let v in value) {// properties of object tenants/{id} => {get{}, post{}}
            if (v === c) {
              newMethods = { ...newMethods, [v]: value[v] };
            }
          }
        }
      } else {// if array in config is empty , return param "value" from setMethodsOfEndpoint so we will include all methods of endpoint
        return value;
      }
  } else {
    return 'undefined'
  }
}
if (Object.keys(newMethods).length !==0) { // if in the config is in the array (nothing that match with swaggerEndpoints e.g. typo get --> gte)
  return newMethods
}  else {
  return value;
}
}

console.log(includeEnpointsByConfig(swaggerApis));

Code can be found also here https://codesandbox.io/s/blazing-worker-1emzl?file=/src/index2.js

I believe there is a way to do it much easier, cleaner and more effective. Thank you

2
  • 1
    To prevent people from having to try to understand your code, what's your expected output for the given example? Commented Jun 18, 2021 at 7:56
  • @RobbyCornelissen header: { propertyHeader: "valueHeader" }, blocks: [ { tags: ["Tenant & User"], paths: { "/tenants/{id}": { get: { property: "value" } } } ] }; Commented Jun 18, 2021 at 8:03

1 Answer 1

2

With some creative usage of Array.prototype.forEach(), Object.keys() and Object.entries():

swaggerApis.blocks.forEach(block => {
  Object.entries(block.paths).forEach(([path, methods]) => {
    if (!CONFIG.api.include[path]) {
      delete block.paths[path];
    } else {
      Object.keys(methods).forEach(method => {
        if (!CONFIG.api.include[path].includes(method)) {
          delete methods[method];
        }
      });
    }
  });
});

Complete snippet:

const swaggerApis = {
  header: {
    propertyHeader: "valueHeader"
  },
  blocks: [
    {
      tags: ["Tenant & User"],
      paths: {
        "/tenants": {
          post: {
            property: "value"
          },
          get: {
            property: "value"
          }
        },
        "/tenants/{id}": {
          post: {
            property: "value"
          },
          get: {
            property: "value"
          },
          delete: {
            property: "value"
          }
        }
      }
    }
  ]
};

const CONFIG = {
  api: {
    include: {
      "/tenants/{id}": ["get"]
    }
  }
};

swaggerApis.blocks.forEach(block => {
  Object.entries(block.paths).forEach(([path, methods]) => {
    if (!CONFIG.api.include[path]) {
      delete block.paths[path];
    } else {
      Object.keys(methods).forEach(method => {
        if (!CONFIG.api.include[path].includes(method)) {
          delete methods[method];
        }
      });
    }
  });
});

console.log(swaggerApis);

Sign up to request clarification or add additional context in comments.

1 Comment

you solved the problem from a different perspective, each programmer thinks in a different way and learns how to approach and break down problems uniquely but in my case I feel sometimes overkill but now I see need to update my skills in JavaScript. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.