-
Notifications
You must be signed in to change notification settings - Fork 539
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
refactor: OpenAPI 3 parse and convert #2460
Conversation
Codecov Report
@@ Coverage Diff @@
## master #2460 +/- ##
==========================================
- Coverage 68.98% 68.82% -0.16%
==========================================
Files 131 191 +60
Lines 3456 7547 +4091
Branches 845 842 -3
==========================================
+ Hits 2384 5194 +2810
- Misses 1072 2048 +976
- Partials 0 305 +305
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any proposal on this PR?
// replace parameter in uri to wildcard | ||
realUri := regURIVar.ReplaceAllString(uri, "*") | ||
// generate route name | ||
routeID := o.TaskName + "_" + strings.NewReplacer("/", "-", "{", "", "}", "").Replace(strings.TrimPrefix(uri, "/")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not use base64
or hash to do this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, Thanks for your reminder.
What do you think about using the base64 or hashed content as ID
and the original uri as Name
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe base64 is better. That's more easily to debug (we can decode from the id to get the info)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After testing, using URI + base64 will generate some very long IDs, which may exceed the schema check limit of APISIX on the one hand, and confuse the format of ID display in the route list on the other. The symbols in base64 will also trigger the schema ID check of APISIX, while for Name only the length is required and the content is completely customizable.
So I took the following approach, instead of generating IDs, which are automatically generated by the dashboard storage layer, we store the information in the route name, which has this format TaskName_URI[_Method]
. For a route with a URI of /consumer/{cid}
, the method is GET and POST, it generates this TaskName_consumer/{cid}[_GET/POST]
taskName: test
methodMerge: true
Method + URI:
GET|POST /consumer/{cid} => test_consumer/{cid}
methodMerge: false
Method + URI:
GET|POST /consumer/{cid} => test_consumer/{cid}_GET + test_consumer/{cid}_POST
}, | ||
} | ||
|
||
u, err := url.Parse(servers[0].URL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only parse servers[0] ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is based on the following considerations:
- The first servers are usually the node that is logically "used first".
- Different servers may have different global paths
What's "global paths"?
servers:
- url: https://z.com/test/
- url: https://x.com/non-test/
- url: https://c.com/test-now/
According to the principle of APISIX, we need to set /test, /non-test,
/test-now, respectively, as the prefix of the route uri of APISIX,
for example, set the original /user/* to /test/user/*, at this point
we can't operate.
Do you have any better suggestions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create different routes for each server?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is appropriate, it generates a lot of useless routes. 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the other routes are useless?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hi @bzp2010, please check this, it affects the overall convert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am a little confused about servers, should they be the URL exposed by the gateway or the URL of the API backend service, please confirm, thanks.
@nic-chen We can look at it this way, during API debugging it is the address actually requested by the debugger, so it should be the address provided by APISIX to the outside world, and the original value should be upstream.
So in effect, the debugger requests the open API of APISIX, while APISIX goes and requests the SERVERS in the original values.
我们可以这样看待这个问题,在API调试过程中,它是调试器实际请求的地址,因此它应当是APISIX对外提供的地址,而原始值应该是上游的。
因此实际上,调试器请求APISIX开放的API,而APISIX去请求原始值中的servers。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bzp2010 I suggest that this PR not deal with servers
first, and deal with it later if there is a strong demand; instead of dealing with imperfections now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of the choices to make here is whether to use servers as route.host
or upstream.node
, which is really critical.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nic-chen Well, I decided to remove this feature and replace it with a default empty upstream that the user can simply modify to change the upstream associated with all routes.
Update
Request for CommentsIn response to this, I would like to seek more suggestions and I believe there are the following needs met:
|
will review it later. |
// Route | ||
assert.Equal(t, data.Upstreams[0].ID, data.Routes[0].UpstreamID) | ||
for _, route := range data.Routes { | ||
fmt.Println(route.Name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug line?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, removed
// temporarily save the parsed data | ||
data = &loader.DataSets{} | ||
// global upstream ID | ||
globalUpstreamID = o.TaskName |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the taskName as upstream ID ?
It looks strange.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The taskname can be set to a service name, such as user
or order
, so that it will generate an upstream named order
and generate a route name similar to order_user/list
. I think this is clearer.
|
||
d, ok := input.([]byte) | ||
if !ok { | ||
return nil, fmt.Errorf("input format error: expected []byte but it is %s", reflect.TypeOf(input).Kind().String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basically, it's a sort of programming faults so I would suggest using panic
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tokers 🤔
For the input data error, should we classify it as a 400 Bad Request
instead of a 5xx server-related error? I don't think this should be a programming error on the server.
From a practical point of view, if we use panic
here, the Manager API will simply treat it as a 500 Internal Server Error
and not automatically select the appropriate response code or have us specify it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the input data error, should we classify it as a 400 Bad Request instead of a 5xx server-related error?
Is this an API and will be exposed to the client? If so, you need to use some standards to make sure the data type is correct, such as jsonschema. If not, it means this method will be called by another internal method, and it's that handler's responsibility to make sure it accepts correct data type from the client and pass them to this method. As a result, when this method accepts bad data type, it could be classified to the programming fault.
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this an API and will be exposed to the client? If so, you need to use some standards to make sure the data type is correct, such as jsonschema. If not, it means this method will be called by another internal method, and it's that handler's responsibility to make sure it accepts correct data type from the client and pass them to this method. As a result, when this method accepts bad data type, it could be classified to the programming fault.
Get it, I will change it to panic and move the conversion check logic to the handler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated the input error to panic
|
||
// no paths in OAS3 document | ||
if len(swagger.Paths) <= 0 { | ||
return nil, consts.ErrImportFile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This error message is not enough.
Use errors.Wrap
to carry the context message. See https://github.com/pkg/errors
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it is not enough, I will add more error messages.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error context improved
}, | ||
} | ||
|
||
u, err := url.Parse(servers[0].URL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be the URL exposed by the gateway I guess.
assert.Contains(t, route.Methods, "DELETE") | ||
assert.Equal(t, "Remove customer", route.Desc) | ||
assert.Equal(t, entity.Status(0), route.Status) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should add the default
arm and run t.Fail
since a route with bad name exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
default branch added
put: | ||
tags: | ||
- default | ||
summary: Update customer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we support parse summary
?
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@starsz After confirmation, they are written to the desc field of the route, which is now supported.
// replace parameter in uri to wildcard | ||
realUri := regURIVar.ReplaceAllString(uri, "*") | ||
// generate route Name | ||
routeName := o.TaskName + "_" + strings.TrimPrefix(uri, "/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can follow APISIX's schema to check resources.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tao12345666333 Yes, the ability to check the schema is already built into the storage layer, so no matter what APISIX resource we try to create, it will perform the schema check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, I'm still not sure on the route name generation and can see from #2460 (comment), do you have any suggestions?
Please answer these questions before submitting a pull request, or your PR will get closed.
Why submit this pull request?
What changes will this PR take into?
Improved backend implementation of OpenAPI3 import to enable import of standard OpenAPI3 minimum use cases. In the current PR I will not do the integration work, this separate module will be checked by way of unit tests and in the next PR it will be integrated into the data import interface.
Checklist: