yndlingsfar / serverless-openapi-integration-helper

The plugin separates x-amazon-apigateway extension syntax from your openapi3 files
MIT License
6 stars 5 forks source link

Support multiple APIs #17

Closed henhal closed 1 year ago

henhal commented 1 year ago

Support multiple APIs by allowing openApiIntegration to be an array of configurations, where each item has an apiResourceName property determining which Aws::ApiGateway::RestApi resource to inject the merged specification into.

Update README accordingly to describe how to process multiple APIs.

henhal commented 1 year ago

Fixes #15

yndlingsfar commented 1 year ago

Hey henhal,

amazing job!!! Thank you very much. There are two little bugs in your PR, could you please have a look?

1) the cors:true option isn't working when using an config array 2) the last path of the first file processed isn't merged into the output file.

Assuming you have the following input files:

api-1.yml ` openapi: 3.0.0 info: description: User Registration version: 1.0.0 title: UserRegistrationDemo paths: /api/v1/user: post: summary: adds a user requestBody: content: application/json: schema: $ref: '#/components/schemas/Customer' responses: '201': description: user created get: summary: get a user responses: '200': description: user fetched content: application/json: schema: $ref: '#/components/schemas/Customer' /api/v1/user/{email}: post: summary: provide a password reset token parameters:

api-2.yml ` openapi: 3.0.0 info: description: User Registration version: 1.0.0 title: UserRegistrationDemo paths: /api/v2/user: post: summary: adds a user requestBody: content: application/json: schema: $ref: '#/components/schemas/Customer' responses: '201': description: user created get: summary: get a user responses: '200': description: user fetched content: application/json: schema: $ref: '#/components/schemas/Customer' /api/v2/user/{email}: post: summary: provide a password reset token parameters:

and the following configuration ` openApiIntegration:

Then the /api/v1/user/{email}: path is missing in the output file

henhal commented 1 year ago

Thanks @yndlingsfar! However, I didn't quite understand your setup. You have two APIs with the same output directory and was expecting them to be merged into one spec? Does that make sense...?

When I add unique outputDirectory to each item in the array such as api/v1 and api/v2 I get two successful APIs created, and both are injected into their respective ApiGatewayRestApi.

I will look into the cors problem.

yndlingsfar commented 1 year ago

@henhal oh yes, you are absolutely right. With two different output files everything is fine. Could you please add the output_file configuration in your README example... just to avoid misunderstandings in the future.

After fixing the cors issue, I will merge the PR. Thanks a lot

henhal commented 1 year ago

Ah, of course, I missed that. Should I perhaps even add validation so that in case of multiple APIs, each one must specify apiResourceName and a unique outputDirectory + outputFile tuple? It would avoid some easy user mistakes.

henhal commented 1 year ago

Could you clarify a bit what the cors problem was? I was a bit surprised that detailed functionality would break when basically the only change I made was to iterate the same code as before over an array instead of a single object, and when I set cors like this:

openApiIntegration:
  - package: true
    cors: true
    inputFile: api-1.yml
    outputFile: api-1.yml
    apiResourceName: ApiGatewayRestApi1
    autoMock: true
    mapping:
    stage: [ dev, prod ]
    path: integrations
  - package: true
    cors: true
    inputFile: api-2.yml
    outputFile: api-2.yml
    apiResourceName: ApiGatewayRestApi2
    autoMock: true
    mapping:
    stage: [ dev, prod ]
    path: integrations```

Then both my output files contain options paths for both routes:

paths:
  /api/v1/user:
    ...
    options:
      summary: Provide CORS
      ...
  /api/v1/user/{email}:    
    ...
    options:
      summary: Provide CORS
      ...

If I set cors: false on api-2, only the output file for api-1 has the options paths. Is anything else expected?

yndlingsfar commented 1 year ago

this is my configuration

openApiIntegration:
  - package: true
    inputFile: api-1.yml
    outputFile: api1.yml #optional, defaults to api.yml
    apiResourceName: ApiGatewayRestApi1
    cors: true
    autoMock: true
    mapping:
      - stage: [dev, prod]
        path: integrations
  - package: true
    inputFile: api-2.yml
    outputFile: api2.yml #optional, defaults to api.yml
    apiResourceName: ApiGatewayRestApi2
    cors: true
    autoMock: true
    mapping:
       - stage: [dev, prod]
         path: integrations

and I get the following error

serverless integration merge --stage=dev
Running "serverless" from node_modules
OpenApi Integration Plugin: Merge x-amazon-apigateway-integration integration: integrations/gateway_responses.yml
OpenApi Integration Plugin: Merge x-amazon-apigateway-integration integration: integrations/production.yml
OpenApi Integration Plugin: Add AUTO-MOCK for /api/v1/user/{email}:post with response code 201
OpenApi Integration Plugin: Process default CORS path template
OpenApi Integration Plugin: Process default CORS header template
OpenApi Integration Plugin: Process default CORS integration template
OpenApi Integration Plugin: Process default CORS response-parameters template
OpenApi Integration Plugin: Successfully created openapi-integration/api1.yml
OpenApi Integration Plugin: Merge x-amazon-apigateway-integration integration: integrations/gateway_responses.yml
OpenApi Integration Plugin: Merge x-amazon-apigateway-integration integration: integrations/production.yml
OpenApi Integration Plugin: Add AUTO-MOCK for /api/v2/user:post with response code 201
OpenApi Integration Plugin: Add AUTO-MOCK for /api/v2/user:get with response code 200
OpenApi Integration Plugin: Add AUTO-MOCK for /api/v2/user/{email}:post with response code 201
OpenApi Integration Plugin: Process default CORS path template
OpenApi Integration Plugin: Process default CORS header template
TypeError: Cannot convert undefined or null to object
    at Function.entries (<anonymous>)
    at /Users/danielsteiner/Projects/serverless-openapi-integration-helper/lib/pipelines/add-cors-header.js:15:28
    at Array.forEach (<anonymous>)
    at /Users/danielsteiner/Projects/serverless-openapi-integration-helper/lib/pipelines/add-cors-header.js:14:45
    at Array.forEach (<anonymous>)
    at AddCorsHeader.invoke (/Users/danielsteiner/Projects/serverless-openapi-integration-helper/lib/pipelines/add-cors-header.js:13:43)
    at Pipeline.step (/Users/danielsteiner/Projects/serverless-openapi-integration-helper/lib/pipeline.js:9:41)
    at MergeIntegrationPlugin.process (/Users/danielsteiner/Projects/serverless-openapi-integration-helper/lib/index.js:158:14)
    at MergeIntegrationPlugin.processMergeCommand (/Users/danielsteiner/Projects/serverless-openapi-integration-helper/lib/index.js:166:18)
    at PluginManager.runHooks (/Users/danielsteiner/Projects/examples/node_modules/serverless/lib/classes/plugin-manager.js:530:15)
    at PluginManager.invoke (/Users/danielsteiner/Projects/examples/node_modules/serverless/lib/classes/plugin-manager.js:564:20)
    at async PluginManager.run (/Users/danielsteiner/Projects/examples/node_modules/serverless/lib/classes/plugin-manager.js:604:7)
    at async Serverless.run (/Users/danielsteiner/Projects/examples/node_modules/serverless/lib/serverless.js:174:5)
    at async /Users/danielsteiner/Projects/examples/node_modules/serverless/scripts/serverless.js:771:9
OpenApi Integration Plugin: Process default CORS integration template
OpenApi Integration Plugin: Process default CORS response-parameters template
OpenApi Integration Plugin: Successfully created openapi-integration/api2.yml
yndlingsfar commented 1 year ago

Ah, of course, I missed that. Should I perhaps even add validation so that in case of multiple APIs, each one must specify apiResourceName and a unique outputDirectory + outputFile tuple? It would avoid some easy user mistakes.

THAT would be perfect. I guess either outputDirectory OR outputFile should be enough

henhal commented 1 year ago

I added such a check now and tested it. (However, like other checks, it simply logs and returns, it doesn't throw or return a non-zero exit code in case of errors like conflicting output paths. I don't know if you'd like a harder exit for those errors, but the rest of the plugin did not seem to do that so perhaps that's a different PR in that case?).

Regarding your error above, it seems to be caused by incorrect indentation of path, it shouldn't be a property within a mapping. When I changed your config to the below, it worked for me. I guess just an annoying copy&paste mistake which happens to me with yaml too sometimes?

openApiIntegration:
  - package: true
    inputFile: api-1.yml
    outputFile: api1.yml #optional, defaults to api.yml
    apiResourceName: ApiGatewayRestApi1
    cors: true
    autoMock: true
    mapping:
      - stage: [dev, prod]
    path: integrations # <---- indentation was off
  - package: true
    inputFile: api-2.yml
    outputFile: api2.yml #optional, defaults to api.yml
    apiResourceName: ApiGatewayRestApi2
    cors: true
    autoMock: true
    mapping:
       - stage: [dev, prod]
    path: integrations # <---- indentation was off
yndlingsfar commented 1 year ago

oh my god, of course you are right :-) THANKS A LOT, pr accepted