Skip to content

Instantly share code, notes, and snippets.

@lyzadanger
Last active March 26, 2018 13:50
Show Gist options
  • Save lyzadanger/69d908e9c516894bb2979ff397782f0c to your computer and use it in GitHub Desktop.
Save lyzadanger/69d908e9c516894bb2979ff397782f0c to your computer and use it in GitHub Desktop.
H API: Organizations : Groups

What we’re trying to accomplish:

Make it possible for the client to show organization icons (logo) and, at some point in the near future, organization names in the drop-down list of groups available to a user at a particular URI.

This discussion centers around how to make that possible from the API-endpoint perspective, based on what is in place now and what we know now.

What we have now

API

An endpoint (GET /api/groups) that returns an appropriately-sorted list of groups pertinent to the current URI, but without any notion of organization metadata.

We do not (yet) have API endpoints for individual group resources or any endpoints for organizations.

Backend

We have a basic table and model for organization. organizations have a one-to-many relationship with groups. At some point in the near future, every group will be required to have a relation to an organization, defaulting to the default organization hypothesis.

At present, logo images are stored directly as markup in the database.

Frontend

There is a groups service in the client that is a dependency for several components. The client solidly thinks of groups as, well, a list or collection of groups.

Background/Context Discussion

Though the client now needs to think of groups in the context of organizations, I would assert that the client is not asking the question “What are the valid organizations for this request?” At the end of the day, the client is still trying to get at the appropriate list of groups for the current request (user + URI).

Even if the former (“Gimme my organizations”) were accurate, there’s some challenges with the current state of organization as we have it in its youthful modeling: I believe that organizations aren’t (yet) well enough defined to stand on their own as a first-class entity. We’re not quite certain yet where we’re going with them.

To illustrate, the only way at present to determine what is an “appropriate list of organizations” to give to the client at any given time is through the groups’ relationships with organizations. Organizations themselves are “dumb” as of yet: though they are associated with an authority, they don’t have any scoping.

Also, though we certainly want to keep business logic out of clients, I want to avoid us doing backflips in our API design to solve a UI-level problem.

Possible Approaches

Refactor current GET /api/groups endpoint

In this approach, the response from the groups endpoint would be restructured to put group objects under their parent organization objects.

Pros

  • Would provide the client with a response that exactly mirrors what it wants to do with it
  • Would keep any sorting or grouping out of the client

Cons

  • Violates RESTful principles as this is an endpoint about groups
  • Breaks existing groups endpoint
  • Would replace an endpoint structure that may well have future use

Add organizations endpoint(s)

In this approach, new endpoints would be created for retrieving an individual organization resource or collections of organizations. Groups returned via the groups endpoint would contain only an ID reference to their associated organization.

Pros

  • Keeps complete representations of organization data—which may be unnecessary for some or most requests to this endpoint—out of the response.
  • Probably endpoints we’ll want in the future anyway.

Cons

  • Will generate extra HTTP requests
  • There is no meaningful way to query for organizations yet—the correct/valid/accessible organizations can only be determined through group relationships at present. Thus it could be tough to design this endpoint now.
  • Thus there is some fragility with keeping organizations and groups in parity at present…
  • Would require more work to support in the client—the client would need to iterate over groups and make the right request(s) for additional organization information

Add a new hybrid-noun endpoint (composite)

In this approach, an endpoint could be added that expresses that we’re actually dealing with a hybrid resource collection here: the combination of groups and organizations, e.g. organization_groups. The response would be structured by organizations but all groups would be unfurled within their organization objects.

There are some examples of this in certain production APIs, though it’s not overly common (possibly because it points at an API-design smell).

Pros

  • Avoids pollution of groups or organizations endpoint(s) with relational data.
  • Follows certain established RESTful patterns

Cons

  • Still convoluted
  • Requires rework in the client that might be confusing
  • Might back us into a weird corner

Add Capability for Resource Expansion

In this approach, an expand parameter could be provided to certain endpoints to allow expansion of sub-resources within them. e.g. GET /api/groups?expand=organizations.

Pros

  • Allows clients to designate how much data they get back
  • Reduces HTTP requests
  • Simpler implementation in client as it builds on existing groups
  • Backwards-compatible

Cons

  • Requires list-groups component to do some traversal over the response to format it as needed in the UI

Proposed Approach

At present, I am leaning toward the resource-expansion approach. This would adapt the existing groups endpoint to provide the ability to expand sub-resource organization objects (e.g. GET /api/groups?expand=organizations)

This is based on the following arguments in favor:

I believe it will be faster to implement.

Even though the client will need to add a function to traverse and organize the groups response in the list-groups component, I believe that will be a relatively constrained change. Unlike some of the other approaches, it won’t require the creation of a new service or the total restructuring of the groups service in the client.

Initially it won’t require the creation of a new endpoint, but the adaptation of an existing one.

I believe it answers the question the client is actually asking.

This is up for debate still, but I believe at the core that the client is still asking the question “what groups apply here?” not “what organizations are there?” (We also don’t have a way to answer “What organizations are there?” yet).

The response from the groups endpoint is used in other places in the client (to reference group objects in general) and is more generic than the display in a drop-down.

I believe it lends us flexibility later.

If the preceding assertion proves false—if indeed, as we evolve, the client really needs a list of organizations, not groups, we can opt to add additional endpoints (e.g. GET /api/organizations) with or without resource expansion and add services to the client as well.

Put another way, I believe this won’t design us into a corner. It won’t hurt to have an expandable groups response and the investment into this approach is a smaller amount of work: we can change our minds.

I believe it follows RESTful principles appropriately.

There are a good amount of examples of large-scale APIs following this resource-expansion pattern, including Netflix (Netflix is a dead API, whoops), GitHub, Jira, Stripe, Atlassian, etc., in one way or another. It is an established pattern, in other words.

It also leaves the groups endpoint (non-expanded and expanded both) for use for other purposes.

I believe it allows us to manage for performance.

Choosing resource expansion is a decision that puts emphasis on reducing requests and simplifying client logic—coarse-grained, that is.

If later, as we scale, we realize that optimizing for payload or other things is more vital, we can swap over to not expanding resources and instead making additional requests against (to-be-built) organizations (or other) endpoints.

I believe it’s more independent of client-specific/UI needs.

We’ve discussed before how important it is to keep business logic out of clients (ours or others’). However, at the end of the day here, I believe that structuring the response in a way to match the client’s groups drop-down menu could be short-sighted and might be bending the design to an over-specific application of it. That is, I believe it is display logic at this time, not business logic. This may change as time goes on, but refer to some preceding arguments for ways we can address that.

I should note…

I do think that we may well end up wanting to add organizations endpoints in the future (maybe even the near future). I believe the proposed approach shouldn’t get in the way of that.

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