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

Contacts index / search / discovery / relationship status #54

Open
jhass opened this issue Feb 15, 2020 · 4 comments
Open

Contacts index / search / discovery / relationship status #54

jhass opened this issue Feb 15, 2020 · 4 comments

Comments

@jhass
Copy link
Member

jhass commented Feb 15, 2020

Four related topics, so I'll start with one issue for all of them.

  1. Currently you can search through all known users to a pod. You can also get a list of contacts per aspect. There's no way to search/list/discover people beyond that. This leaves a couple of use cases without a clear path forward or an efficient implementation.

  2. Some API consumers don't need to care about aspects, only a users contacts. Or maybe the want to build a contacts first, aspects second UI. We shouldn't frame client developers by only offering an aspects first, contacts second API.

  3. For example when mentioning somebody, it would be good to have a route that can search through all the contacts of a user, optionally filtered through a given list of aspects. This could be just new query parameters to /search/users.

  4. Currently there's no (clear) way to trigger a user discovery by diaspora ID. /search/users could implicitly do this (it doesn't currently). But then we have to think of how to communicate the fact that the endpoint may return a result with a second request in a couple of seconds to minutes while the background job does its thing.

  5. Touching Point 1. and 2. heavily, but I felt it can be its own topic: Currently relationship status is only ever returned on the extended profile route. There's no contacts index that returns it. This leaves clients with a N*M query if they want to discover the relationship status of all contacts, where N = number of aspects, M = average amount of users per aspect. Point 1. could remove the N but leaves an 1 + M (M = total number of contacts) amount of queries. While it's nice that the current routes can reuse the "short profile" data structure a lot, it leaves a lot to be desired for usecases like selecting the recipients of a conversation. Getting a list of contacts only sharing with but not receiving from the user is outright impossible currently. So we probably should return relationship status in the current contacts for aspect route, the proposed all contacts route and the user search route. Additionally filter options for relationship status in all those routes seem sensible.

@jhass jhass changed the title Contacts index / search / discovery Contacts index / search / discovery / relationship status Feb 16, 2020
@jhass
Copy link
Member Author

jhass commented Mar 12, 2020

A draft for point 2, adding a new query parameter filter to /search/users:

Filter

The filter parameter can be given zero or more times. Each one narrows down the
search result, in other words multiple filter parameters are joined with a logical and.

The possible values are:

  • contacts: Limits the results to the currently authenticated user's contacts. Requires the contacts:read scope.
  • contacts:receiving: Limits the results to the currently authenticated user's contacts that the user is sharing with. Requires the contacts:read scope.
  • contacts:sharing: Limits the results to the currently authenticated user's contacts that are sharing with the user. Requires the contacts:read scope.
  • aspect:aspect_id,aspect_id,...: For example aspect:123 or aspect:123,567. Limits the results to users that are in either of the given aspects. Requires the contacts:read scope.

Examples:

  • filter[]=contacts:receiving&filter[]=contacts:sharing: Only return users that have a mutal sharing status with the current user.
  • filter=aspect:123,567: Only return users that are either in aspect 123 or in aspect 567 (or in both).
  • filter[]=aspect:123&filter[]=aspect:567: Only return users that in both, aspect 123 and 567.

@denschub
Copy link
Member

Sorry for the late response here, had to take a bit of time to consider your proposal and give it the time it deserves.

I'm not sure I quite like the idea of using the search endpoint. Searches are very different than lists. I can imagine API consumers who want to receive a list of all contacts, thus calling /search/users?filter[]=contacts without an additional search query like name_or_handle. It's fair to assume that a developer would expect a list of all contacts from that query. But what happens when /search/users is called without any parameters? Should it return a list of all known profiles? Should we require either a search query or a filter parameter and throw a 400? Either day feels a bit... surprising, maybe?

What you are suggesting is a generic filter argument, which can be provided once or multiple times. I don't have strong arguments or opinions against it, but I'd like to explore alternative options as well. One thing I don't quite like is the ambiguity of using one parameter to do it all, with magic keywords and magic values. This works, but I don't like the way this could encourage building even more complicated "filter payload" scenarios.

How about this: Instead of mixing search and lists, we could refactor the aspects routes to be below a contacts route? That way, we could have

  • /contacts/aspects as a list of aspects,
  • /contacts/aspect/:id as a list of contacts for an aspect
  • /contacts as a list of contacts,
  • /contacts?receiving=true, /contacts?sharing=true, ... as additional filters?

It seems like a bit more work, and maybe that's not worth it, but maybe that results in more predictable APIs. I would love to hear a third opinion as well. Maybe I'm overcomplicating. :)

@jhass
Copy link
Member Author

jhass commented Mar 15, 2020

The draft is intended to cover the usecases described in 2. For the usecases described in 1 I agree and was roughly planning to have some kind of /contacts. Given we do have the /search namespace it made sense to me to extend it for usecases that search and shouldn't need to load a, potentially enormous, list of contacts just to filter it down locally. So /search/users would still require one of the two existing query parameters but additionally take an optional filter to filter down the results.

I'm not sure I see it as magic values but rather building up a search expression language while avoiding to have a full blown parser for it that could parse something like contacts:receiving AND (aspect:123 OR aspect:567). Reusing filter as query parameter for all possible filters makes it easier to grasp in my mind that each instance continues to filter down (is combined with logical and). Why would a keyword in query parameter value be any more magical than in a query parameter name or a path component? HTTP APIs are inherently full of "magic values".

@denschub
Copy link
Member

Fair points. For some reason, I read your point 1 as point 2 (because you started at 0, tricky!) and then confused myself. Your arguments are good, go for it. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants