Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(BE): Export route from OpenAPI Specification3.0 #1245

Merged
merged 37 commits into from
Jan 27, 2021

Conversation

Jaycean
Copy link
Member

@Jaycean Jaycean commented Jan 8, 2021

Please answer these questions before submitting a pull request


New feature or improvement

  • Export route from OpenAPI Specification3.0

Related FE PR: #1240

@Jaycean Jaycean marked this pull request as draft January 8, 2021 08:47
@Jaycean Jaycean changed the title Export route from OpenAPI Specification3.0 feat: Export route from OpenAPI Specification3.0 Jan 8, 2021
@liuxiran liuxiran mentioned this pull request Jan 8, 2021
1 task
@Jaycean Jaycean changed the title feat: Export route from OpenAPI Specification3.0 feat(BE): Export route from OpenAPI Specification3.0 Jan 8, 2021
@liuxiran liuxiran added this to the 2.4 milestone Jan 8, 2021
@codecov-io
Copy link

codecov-io commented Jan 11, 2021

Codecov Report

Merging #1245 (0af3fd8) into master (8852e63) will increase coverage by 0.10%.
The diff coverage is 68.67%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1245      +/-   ##
==========================================
+ Coverage   62.75%   62.85%   +0.10%     
==========================================
  Files          41       43       +2     
  Lines        2360     2660     +300     
==========================================
+ Hits         1481     1672     +191     
- Misses        703      783      +80     
- Partials      176      205      +29     
Impacted Files Coverage Δ
api/internal/core/entity/entity.go 62.50% <ø> (ø)
api/internal/handler/data_loader/route_export.go 68.56% <68.56%> (ø)
api/internal/route.go 84.37% <100.00%> (+0.50%) ⬆️
api/cmd/managerapi.go 60.29% <0.00%> (-16.79%) ⬇️
api/internal/conf/conf.go 67.85% <0.00%> (ø)
api/internal/utils/pid.go 26.66% <0.00%> (ø)
api/internal/core/store/store.go 87.34% <0.00%> (+0.63%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 8852e63...0af3fd8. Read the comment docs.

@Jaycean Jaycean force-pushed the export_route_from_openapi branch 2 times, most recently from 74ab4c5 to 0d191cb Compare January 11, 2021 01:24
@starsz
Copy link
Contributor

starsz commented Jan 11, 2021

Hi, @Jaycean. Need unit test.

@Jaycean
Copy link
Member Author

Jaycean commented Jan 11, 2021

Hi, @Jaycean. Need unit test.

At present, the function interface needs to export the existing route data and ensure the correctness of the exported data, so I think E2E should be written more perfectly. I think if the simple unit test only tests whether the interface can export data, it does not represent whether the function of the interface is correct, and if the relevant route data is not created, the interface will not work normally use.

@starsz
Copy link
Contributor

starsz commented Jan 11, 2021

Hi, @Jaycean. Need unit test.

At present, the function interface needs to export the existing route data and ensure the correctness of the exported data, so I think E2E should be written more perfectly. I think if the simple unit test only tests whether the interface can export data, it does not represent whether the function of the interface is correct, and if the relevant route data is not created, the interface will not work normally use.

Not agree with you.
First of all, unit testing is very important. It helps find bugs easily and quickly if someone changes the code.And unit testing can cover more code than e2e test.
For example, in this case.
We need to test these situations at least:

  1. route can't found
  2. Uris contain "*"
  3. plugins with request-validation
  4. different route method
    ...

and if the relevant route data is not created, the interface will not work normally use.

We can mock data in etcd.
See https://github.com/apache/apisix-dashboard/blob/master/api/internal/handler/server_info/server_info_test.go for more details.

@Jaycean
Copy link
Member Author

Jaycean commented Jan 11, 2021

Hi, @Jaycean. Need unit test.

At present, the function interface needs to export the existing route data and ensure the correctness of the exported data, so I think E2E should be written more perfectly. I think if the simple unit test only tests whether the interface can export data, it does not represent whether the function of the interface is correct, and if the relevant route data is not created, the interface will not work normally use.

Not agree with you.
First of all, unit testing is very important. It helps find bugs easily and quickly if someone changes the code.And unit testing can cover more code than e2e test.
For example, in this case.
We need to test these situations at least:

  1. route can't found
  2. Uris contain "*"
  3. plugins with request-validation
  4. different route method
    ...

and if the relevant route data is not created, the interface will not work normally use.

We can mock data in etcd.
See https://github.com/apache/apisix-dashboard/blob/master/api/internal/handler/server_info/server_info_test.go for more details.

Thank you for your advice. I also think unit testing is really necessary. I just thought that this interface test is almost the same as E2E, but unit testing should cover all situations as much as possible

@Jaycean Jaycean marked this pull request as ready for review January 12, 2021 03:18
api/internal/handler/route_export/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/route_export/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/route_export/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/route_export/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/route_export/route_export.go Outdated Show resolved Hide resolved
api/test/e2e/route_export_test.go Outdated Show resolved Hide resolved
api/test/e2e/route_export_test.go Show resolved Hide resolved
@Jaycean Jaycean force-pushed the export_route_from_openapi branch 4 times, most recently from 62cf091 to b0b3c36 Compare January 14, 2021 07:50
@Jaycean
Copy link
Member Author

Jaycean commented Jan 25, 2021

@liuxiran @nic-chen
The unit test and test cases have been supplemented. In the process of testing, I found a problem:

  • At present, the path data structure of OpenAPI 3 is used to store URIs, and the data structure is map [string]. If the URI is repeated, the data will be covered, if the repeated URIs are directly covered, only one URI can be exported, which will lead to the loss of user data.
  • My idea is to add a uniform suffix after the same URI when exporting, so that the import can recognize the URI
    For example:
{
	"components": {},
	"info": {
		"title": "RoutesExport",
		"version": "3.0.0"
	},
	"openapi": "3.0.0",
	"paths": {
		"/hello": {
			"get": {}
		}
		"/hello-repeaturi1": {
			"get": {}
		}
		"/hello-repeaturi2": {
			"get": {}
		}
	}
}
  • My method also has the risk of repeating the user named URI
  • Do you have any better suggestions? We can discuss them. Thks.

api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
return &swagger, nil
}

func parseLabels(route *entity.Route, serviceLabels map[string]string, labels map[string]string) (map[string]string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the label args use for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When service and route have labels at the same time, use route's label. When route has no label, service sometimes uses service's label. This function is used to process this logic

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I didn't see the lables args was used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand your question. Do you mean you don't see users or business scenarios using this field? I don't know if my understanding is correct, because more coverage possibilities are considered everywhere to ensure that the data is not lost. After discussing with nic-chen, this processing function is added.

api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
@liuxiran
Copy link
Contributor

liuxiran commented Jan 25, 2021

@liuxiran @nic-chen
The unit test and test cases have been supplemented. In the process of testing, I found a problem:

  • At present, the path data structure of OpenAPI 3 is used to store URIs, and the data structure is map [string]. If the URI is repeated, the data will be covered, if the repeated URIs are directly covered, only one URI can be exported, which will lead to the loss of user data.
  • My idea is to add a uniform suffix after the same URI when exporting, so that the import can recognize the URI
    For example:
{
	"components": {},
	"info": {
		"title": "RoutesExport",
		"version": "3.0.0"
	},
	"openapi": "3.0.0",
	"paths": {
		"/hello": {
			"get": {}
		}
		"/hello-repeaturi1": {
			"get": {}
		}
		"/hello-repeaturi2": {
			"get": {}
		}
	}
}
  • My method also has the risk of repeating the user named URI
  • Do you have any better suggestions? We can discuss them. Thks.

OpenAPI defines a unique operation as a combination of a path and an HTTP method. This means that two GET or two POST methods for the same path are not allowed – even if they have different parameters (parameters have no effect on uniqueness)
refer from https://swagger.io/docs/specification/paths-and-operations/

After communicating with @Jaycean and @nic-chen there are two alternative solutions:

  • A: add a uniform suffix after the same URI when exporting, and add a description to the user guide.
    This solution can meet the platform-wide data is not lost, the disadvantage is that when users need to use the swagger file to generate documents or sdk, they need to modified manually.

  • B: return error when exporting routes with same URI
    In this way exported OAS3.0 file can be used directly, with the disadvantage that there may be data loss for APISIX. The remedy is that we provide additional import and export of platform-wide data, in accordance with the apisix data format.

Neither scheme is perfect though, which one do you perfer? any suggestions are welcome, thanks a lot

@Jaycean @nic-chen @membphis @starsz @juzhiyuan @imjoey

@juzhiyuan
Copy link
Member

juzhiyuan commented Jan 25, 2021

because it's using URI as paths's Key, then data gets covered would happen. I would prefer adding a global prefix to avoid data lost.

@nic-chen
Copy link
Member

I vote for option A, at least it can be imported and exported normally on APISIX platform.

@juzhiyuan
Copy link
Member

juzhiyuan commented Jan 25, 2021

not sure how other platforms would resolve those issues, we should have a search.

@Jaycean
Copy link
Member Author

Jaycean commented Jan 25, 2021

In my opinion, from the perspective of apimix platform, I choose scheme a to satisfy the users of apimix platform A. The function that URI can be renamed is more open and friendly for users.

@liuxiran
Copy link
Contributor

not sure how other platforms would resolve those issues, we should have a search.

I tried Aliyun API Gateway and eolinker( a API management platform):

  • In Aliyun API Gateway, when we export multiple APIs, it will split each API into a single file(It's also a good choice)
  • In eolinker, it does not support export OpenAPI.

As most people choose option A, let's solve the problem with A first, after this feature megerd and released, let's wait for more users feedback ^_^

api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/data_loader/route_export.go Outdated Show resolved Hide resolved
api/internal/handler/data_loader/route_export_test.go Outdated Show resolved Hide resolved
@Jaycean
Copy link
Member Author

Jaycean commented Jan 27, 2021

@starsz @nic-chen PTAL. Thks.

Copy link
Contributor

@liuxiran liuxiran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this pr has covers all the requirements according to #825

@juzhiyuan juzhiyuan merged commit 9cb9aa7 into apache:master Jan 27, 2021
@membphis
Copy link
Member

wow, Congratulations this PR was merged

@Jaycean Jaycean deleted the export_route_from_openapi branch February 3, 2021 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants