Updating relations using the REST API

System Information
  • Strapi Version: v4.6.0
  • Operating System: Linux
  • Database: MySQL
  • Node Version: v18.15.0
  • NPM Version:
  • Yarn Version: 1.22.19

I am implementing a user “bookmarks” feature. I have the User table with relation “user has many bookmarks”, and a “bookmarks” collection type which has relation “bookmark has exactly one user”. I am trying to use the REST API to update the User and bookmark tables when a client bookmarks a page in my site. The first call looks like:

POST /api/bookmarks

request body:

JSON.stringify({
data: {
key: ,
value: ,
users_permissions_user: {
connect: [{id: <current_user_id>}]
}
}}

This works as expected - bookmark is created, and the 1->1 bookmark-> user relation is made. The id of the new bookmark is returned.

To update the user record to include the new bookmark, I do:

PUT /api/users/<current_user_id>

request body:

JSON.stringify({
data: {
bookmarks: {
connect: [{id: <new_bookmark_id>}]
}
}}

The response is 200 OK, with the user record returned in the response. Examining the “bookmarks” field (many-to-one relation) indicates that the new bookmark was NOT added as expected. The PUT request above did not update the Users table. I have tried “set” in the above request instead of “connect” with the same result, and all the combinations of arrays, integer versus string, all to no effect. Relations | Strapi Documentation suggests the above syntax is correct?

First question - am I going about this in the best way, making two REST API calls to achieve the desired result?

Second question - if this is indeed how I need to do this, why is the second call having no effect on the user record? I have checked permissions for updates on the user table, and these are all as expected. I get no errors (e.g. 403 FORBIDDEN).

Many thanks for any help,

David Herbert.

Further experimentation revealed that removing the {data:…} wrapper from the PUT request payload seems to achieve what is required. This is contradicting the documentation however.

I am having the same issue but when I remove the data property I get a validation error. What version of Strapi are you using and have you been able to get this to work consistently?
Any insight is much appreciated!! I’ve been running circles on this for hours now :confused:

I also am hitting this nasty wall. Does not work in any combo - disconnect/connect, set, no set (direct array or single value usage) - nothing. Just does not save - any relation (1:1 and 1:n). Even more - in my case it does not work with POST or PUT. Very very nasty issue which gives me headaches for 3 days now - docs are clear but behavior is just not as described.

@ITLackey did you try to report this as a bug (because it sure seems like one)?

As sometimes happens, it finally dawned on me to try custom controller call.

So - route is added:

{
    method: "PUT",
    path: "/service/storeService/:id",
    handler: "api::service.service.storeService",
  },

and in controller - this code saves the service successfully. Relation that I need is saved with just giving an ID of the related record.

async storeService(ctx) {
		try {
			const { id } = ctx.params
			const { data } = ctx.request.body

			await strapi.db.query('api::service.service').update({
				where: { id: id },
				data: data
			})

			ctx.body = {
				status: "ok"
			}
		} catch (err) {
			console.error(err)
			ctx.body = {
				status: "error"
			}
		}
	},

The front-end code that is using this is basically the same as for API call - just the URL link to this new method.

// finally, save the record
          res = await fetch(
            // STRAPI_URL + "/api/services/" + activeService.id,
            STRAPI_URL + "/api/service/storeService/" + activeService.id,
            {
              method: "PUT",
              headers: {
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + props.auth.jwt
              },
              body: JSON.stringify({ data: activeRecord })
            }
          )

activeRecord is just a JSON object - as you would expect.

In order to get populated relation data - you do need to reload the record via normal API call.

I do need to test this like hell - just to be sure, but for now, this workaround is doing that API call was supposed to do.

Hopefully this helps you out - even though I really would prefer API calls to work as described :confused:

I would have to check, but I believe part (or all) of the issue was permissions for the related entities. I had not granted the authenticated role permissions to the child entities only the parent. Changing the permissions allowed the update to work if I remember correctly.

1 Like

OMG - now I feel like an idiot :slight_smile: That did not occur to me at all - especially since my record is in fact related to itself (a recursive relation). I added find/findOne/update/create (I will play around to see which minimum set is really needed) to Authorized role and now it works. Damn :slight_smile:

Thank you!

I understand and am glad I’m not the only one that overlooked that :wink:

Glad it’s working for you now!