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

Update pagination to support v1 API patterns #2111

Merged
merged 9 commits into from
Jan 11, 2023
Merged

Conversation

zephraph
Copy link
Contributor

@zephraph zephraph commented Jan 5, 2023

@ahl pointed out in #2008 that the pagination parameters for the /v1/ endpoints wouldn't work as written. I hadn't converted the tests yet so I'd missed that. This PR converts some aspects of the existing tests to test pagination of the new endpoints and updates the pagination implementation to support the new API approach.

Changes

  • Simplifies pagination where possible by using types introduced in the V1 work like NameOrId
  • Updates PaginateByNameOrId and its associated types to support a Selector generic such that resource selector query parameters are properly included in pagination.
  • Updates organization, project, and instance e2e tests to exercise new endpoints and pagination. This isn't a complete update because at least project and instance include sub routes which aren't implemented yet. It should be enough to exercise pagination for each though.
  • Updates all existing /v1/ endpoints to use PaginateByNameOrId. Going forward all endpoints with a name field will use that pagination strategy. This PR does not update the PaginateByName or PaginateById strategies. The former will likely be removed post the migration. The latter will be updated once the first ID only endpoint with pagination is implemented for the /v1/ API.

Comment on lines 3067 to +3071
async fn instance_serial_console_v1(
rqctx: Arc<RequestContext<Arc<ServerContext>>>,
path_params: Path<params::InstancePath>,
query_params: Query<params::InstanceSerialConsole>,
query_params: Query<params::InstanceSerialConsoleRequest>,
selector_params: Query<params::OptionalProjectSelector>,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, this is a bit weird. It's implemented on the same principle as described in the docs here: https://docs.rs/dropshot/latest/dropshot/#advanced-usage-notes. Even though this endpoint doesn't do pagination, we can't flatten the InstanceSerialConsoleRequest and ProjectSelector structs into a single struct due to nox/serde_urlencoded#33.

@zephraph zephraph marked this pull request as ready for review January 7, 2023 05:56
Copy link
Contributor

@ahl ahl left a comment

Choose a reason for hiding this comment

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

This deserves far deeper of a look than I've given it, but I wanted to share some high level feedback rather than sitting on it. I will look more tonight and tomorrow.

common/src/api/external/http_pagination.rs Outdated Show resolved Hide resolved
Comment on lines +300 to +301
ScanByNameOrId<Selector>,
PageSelectorByNameOrId<Selector>,
Copy link
Contributor

Choose a reason for hiding this comment

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

So in general, it seems like the first parameter to PaginationParams is going to want to be the tuple of NameOrIds needed to find the item in question. The second parameter is going to want to be just the ID of the top level container. That is to say, I think we should only be doing name lookups for the first query; subsequent pages should just have the ID of the container that we're iterating through.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried this, but it's rather difficult and made the handlers a lot messier.

Right now we take the query parameters and resolve them to a lookup and pass that to nexus. My understanding of this approach is that we'll need to resolve the lookup to an ID inside the handler as well as passing it along to be further resolved by Nexus (on the first page). That also means we have to have logic to check if it's a selector or id (or if the selector is an id) so we're not doing wasteful lookups. My attempts at this made both the handler much longer and harder to understand as well as increased the complexity of the types around pagination.

I agree that this would be an ideal approach. I also think it's an optimization that we can defer. From a user documentation perspective the same caveats would apply when looking up a resource by name to paginate as would when just looking up a name in general.

Copy link
Contributor

Choose a reason for hiding this comment

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

I tried this, but it's rather difficult and made the handlers a lot messier.

That's disappointing; I could imagine it being a way to extract common patterns rather than to complicate each handler.

Right now we take the query parameters and resolve them to a lookup and pass that to nexus. My understanding of this approach is that we'll need to resolve the lookup to an ID inside the handler as well as passing it along to be further resolved by Nexus (on the first page).

Not necessarily. It could be as simple as having the nexus function that performs the resolution return the resolved ID.

That also means we have to have logic to check if it's a selector or id (or if the selector is an id) so we're not doing wasteful lookups. My attempts at this made both the handler much longer and harder to understand as well as increased the complexity of the types around pagination.

It could literally be the same types if, for some reason, that's simpler: it could just be that for the page selector only the simplest ID form is encoded in the next_token.

I agree that this would be an ideal approach. I also think it's an optimization that we can defer.

I think of this not as a performance optimization, but a simplification of the handlers. If it's not, agreed, we can defer or just not pursue it.

From a user documentation perspective the same caveats would apply when looking up a resource by name to paginate as would when just looking up a name in general.

Further caveats apply: with this approach a rename of any intermediate collection will cause the iteration to fail whereas using a resolved ID for the container means that renames (e.g. of the parent) won't interfere.

Copy link
Contributor Author

@zephraph zephraph Jan 11, 2023

Choose a reason for hiding this comment

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

Not necessarily. It could be as simple as having the nexus function that performs the resolution return the resolved ID.

Yeah, I was thinking the same. We turn the selector into a lookup and pass that along to the function that lists the resources. I tried returning a tuple of the resource list and ID but I had some issues with the return type no longer being a result list. Maybe it just needed to be a result of a tuple where one member was a result list? Uncertain.

I think of this not as a performance optimization, but a simplification of the handlers. If it's not, agreed, we can defer or just not pursue it.

I don't believe that it simplifies the handlers any. My assumption is that it'll make it more complicated regardless. Because it's somewhat of a correctness issue though, I think that's probably a worthwhile tradeoff assuming we find a way to do it without too much complexity.

Further caveats apply: with this approach a rename of any intermediate collection will cause the iteration to fail whereas using a resolved ID for the container means that renames (e.g. of the parent) won't interfere.

Yep! The current case is no worse than what we had previously though. It's worth improving still, just perhaps as a follow up.

Copy link
Contributor

@ahl ahl left a comment

Choose a reason for hiding this comment

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

I'm Adam Leventhal and I approve this PR

@zephraph zephraph merged commit 3606be3 into main Jan 11, 2023
@zephraph zephraph deleted the v1-api-pagination branch January 11, 2023 21:14
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.

2 participants