It would be nice to have JSON API support clients that want to operate on entities in specific workspaces (using Workspace module which is planned for core).

JSON API is planned for 8.3, potentially 8.4.
The same for Workspace module, planned for 8.3, potentially 8.4.

If JSON API makes it into core before Workspace, it would be nice not needing to break APIs once workspaces get into core.

Simply, we should coordinate a little bit :)

Aspect A: URL structure

Alternative 1

Consistently embedding workspace ID in the paths, e.g. /api/<workspace ID>/node/1
If JSON API gets into core before Workspace module, we can simple hard-code live as the only workspace ID. That way, when Workspace module gets into core it will continue working.

Alternative 2

/api/node/1 falls back at the "live" workspace, if Workspaces are used.
/api/<workspace ID>/node/1 targets the entity in a specific workspace ID.

The problem here might be path matching, and potential conflicts between workspace ID and entity type ID.

Aspect B: revision support

See #14 + #15.

Comments

dixon_ created an issue. See original summary.

dixon_’s picture

Unfortunately negotiating workspace based on headers isn't an option because of #2364011: [meta] External caches mix up response formats on URLs where content negotiation is in use

dixon_’s picture

e0ipso’s picture

Hello Dick.

I'm open to the idea. For the negotiation, I think we may be on the same page since you mentioned the headers. Since that is not an option (womp womp) maybe we could take that lead and add a _workspace query string parameter, a la _format.

I'm not in love with that idea, since we'd be implying that /api/node/article/36f5f02a-a7ba-4caa-87e1-3c1c8fd5100c?_format=api_json is the same resource entity as /api/node/article/36f5f02a-a7ba-4caa-87e1-3c1c8fd5100c?_format=api_json&_workspace=workspaceId. Which is not necessarily true. Or maybe it is? I'm not sure.

The part that I like the least about the path pattern is that we are shutting down the door to other data realms. Would it even be possible to have a use case that would not be covered by workspaces? Maybe decoupled preview systems?

I'm sorry I come back with more questions than answers, but I agree with you on the need of collaboration.

wim leers’s picture

Perhaps /api/<realm>:<realm ID>/<entity type>/<entity ID> can work? Then you'd end up with /api/workflow:staging/node/1.

e0ipso’s picture

That name pattern on the path is good for me.

Grayside’s picture

The downside of that pattern is the first-time DX of interacting with the API immediately requires understanding the concept of a "realm" and what a workspace is. An implicit default helps people onboard at a more measured pace to the API and minimizes verbosity for use cases where maybe this does not matter.

I am arguing for the querystring parameter or for making sure an alias or redirect system can cover the simpler case of not designating the workspace.

e0ipso’s picture

@Grayside my assumption was always that the URL pattern would remain the same if no realm is needed. Someone without the need of Workspaces integration would use the same old URL /api/node/article, but if they needed to interact with a particular workspace then they'd need to use /api/workspace:the-wsp-id/node/article.

Does this make sense to everyone?

dixon_’s picture

I like that idea. It makes sense to me!

wim leers’s picture

Yep, that's exactly what I meant.

Grayside’s picture

Maybe I'm not fully understanding workspaces, but does that mean /api/node/article and /api/workspace:live/node/article could point to the same resource? If so, which one is canonical? I generally like to use the most specific URL for a resource as the "most canonical", so might we want to encourage developers to find their preferred URL by adding a canonical LINK header from one to the other?

wim leers’s picture

wim leers’s picture

What hasn't been mentioned yet, is the addressability of revisions. JSON API uses UUIDs as the identifier for an entity. But with the Workflow initiative, it will become necessary to be able to access specific revisions (and list revisions of an entity). How will JSON API support that?

It's perhaps out of scope of the originally intended scope, but it seems even more important to discuss?

dixon_’s picture

Yes, supporting revisions will indeed be very important. Core is moving rapidly towards revisions everywhere, which creates the foundation for workspaces.
My thoughts below should probably be captured in a new JSON API issues, specifically about revisions. Anyway, I'll post it here for now:


I think identifying entities with the UUID is good. Fetching specific revisions can be done with a query parameter. And we should not use the "local" revision ID for this, we should use the revision UUID: #1812202: Add UUID support for entity revisions

Furthermore, the revision API in Drupal 8 will continue to evolve over the coming few releases. One of the things we'll introduce are parent revisions, effectively creating a revision hierarchy to handle revision conflicts etc. There's a few things the API needs to consider here:

  1. One need to be able to fetch all "open" revisions (i.e. any tip of the revision hierarchy, because there can be multiple ones when there are open/unsolved conflicts)
  2. The API must stop a client from writing conflicting revisions

These are some of the reasons why we borrowed the API specification from CouchDB when implementing the Relaxed API module. I look at Realxed as an API specifically useful for replication, content staging and revision management. The API is not equally useful for custom client implementations, decoupled apps etc...

However, there's nothing stopping us from adopting some similar concepts for JSON API to support clients wanting to deal with revisions.

1. Open revisions

The CouchDB spec (hence also Relaxed module) allows you to fetch all open revisions with ?open_revs=all which will return a multipart/mixed response with each revision as a separate response part. Very restful, very clean.

Example with 2 open revisions:

GET /api/node/abc123?open_revs=all HTTP/1.1
Accept: multipart/mixed


HTTP/1.1 200 OK
Content-Type: multipart/mixed; boundary="xyz789"
Transfer-Encoding: chunked

--xyz789
Content-Type: application/json

{
    "uuid": "abc123",
    "revision_uuid": "def456",
    "foo": "bar"
}

--xyz789
Content-Type: application/json

{
    "uuid": "abc123",
    "revision_uuid": "fgh789",
    "foo": "guz"
}
--xyz789--


2. Avoid introducing conflicts

The CouchDB spec stops clients from introducing conflicts by requiring clients to always indicate what parent revision they intend to write on-top of, by essentially including the current revision UUID in the payload. If there exists a newer revision UUID the API should return HTTP 409 to indicate the conflict.

dixon_’s picture

There's lots more to discuss here. But in terms of fetching and listing revisions the CouchDB's approach is pretty simple. With a few simple query parameters you can include some vital meta data in the response. See this for some CouchDB examples:

I'm not saying that we need to copy these concepts straight off, Relaxed module already does this specifically for replication and content staging :)

But some inspiration can certainly be taken from this :)

wim leers’s picture

Category: Feature request » Plan
Issue summary: View changes
e0ipso’s picture

There is a documented issue with the domain module. I suspect that it's on the domain side, but it may affect any potential solution here. #2810307: Interaction with the domain module produces stale caches

#2795279: [PP-2] [META] Revisions support is the issue to track revision support.

I like the idea of the multipart/mixed response. Would it be reasonable to only allow outputting (GET) revisions for single resource entities (as opposed to collections, relationship endpoint and related endpoint).

gabesullice’s picture

Relevant RFC for future reference: https://tools.ietf.org/html/rfc5829

wim leers’s picture

Ohhh!

Snugug’s picture

One thing to consider, given we're also talking about revisions, is grouping language translations (or available translations) in with the revision discussion, too, as it's not entirely obvious now how to get translations of an entity vis JSON:API

wim leers’s picture

Yep, translation support is still missing from JSON API. It also is missing from core's rest module.

wim leers’s picture

Version: 8.x-1.x-dev » 8.x-2.x-dev

#20 + #21: For translations, see #2794431: [META] Formalize translations support. A simple search would've found it: https://www.drupal.org/project/issues/jsonapi?text=translation&version=8....

Also, this is a key new feature, belongs in the next major version.

wim leers’s picture

Title: Forward compatibility with Workspace module » JSON API: forward compatibility with Workspace module
Project: JSON:API » Drupal core
Version: 8.x-2.x-dev » 8.6.x-dev
Component: Code » workspace.module
Issue tags: +API-First Initiative, +Workflow Initiative

#2784921: Add Workspaces experimental module added the Workspace module as experimental to Drupal core 2 months ago. 🎉

I'd like to get advice/wishes/pointers from those actively working on it. How would you like to see this work? We got some feedback from @dixon_ 1.5 years ago, but I'm sure your thoughts on it will have crystalized by now.

Thanks! 🙏

effulgentsia’s picture

Currently, the Workspace module has 2 negotiators for determining the active workspace (the one that the current request applies to): SessionWorkspaceNegotiator and QueryParameterWorkspaceNegotiator. Should JsonApi just use those (which I think it currently does already, since there's nothing disabling those negotiators for jsonapi requests)?

But that means that it's already the case that a jsonapi request could come in for a session whose active workspace isn't the default one. Which I think might require catching exceptions like the ones being added in #2975334: Prevent changes that would leak into the Live workspace as well as making sure that workspace-supported entity saves are happening correctly (in a pending revision associated with the requested workspace). I wonder if temporarily it makes sense for jsonapi to explicitly return a friendly 4xx for any request that comes in for the non-default workspace.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

amateescu’s picture

Component: workspace.module » workspaces.module

Fix component following module rename.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

capita’s picture

Can we use JSON:API to retrieve a node from the 'stage' workspace instead of the usual 'live' one? If so, how would we go about doing that? Thanks a bunch!

amateescu’s picture

@capita that's not possible currently because there's no integration between JSON:API and Workspaces. That's what we're trying to figure out in this issue :)

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.