How to "populate" related:oneToOne datatype in create endpoint

System Information
  • Strapi Version: 4.25.5
  • Operating System: macOS
  • Database: SQLlite
  • Node Version: 20.10.0
  • NPM Version: -
  • Yarn Version: 1.22.21

I am struggling with something really basic and it makes me sad that I can’t find any (working) coverage on this in the documentation. What I like to achieve is fairly simple, I have a content-type “chatMessage” that has a sender and message property. The message is a piece of text and the sender a oneToOne relation. My goal is te create a “create” controller that uses the ctx.state.user value and use that to update the “sender” value. I’ve tried many different things, but nothing works. The new entries only contain the “message” value. According to the documentation it should be as simple as {sender: 1}, in order to add the user with the id of 1 to the database. I am 100% certain that I am using the correct attribute name and value, since I copied those from the populated GET request.

{data: {sender: <number>}}
{data: {sender: {id: <number>}}}
{data: {sender: {set: <number>}}}
{data: {sender: {connect: <number>}}}
{data: {sender: {data: {id: <number>}}}}
{data: {sender: {data: <number>}}}
{data: {sender: {data: {set: {id: <number>}}}}}
{data: {sender: {where: { id: <number> }}}}

schema.json

{
    "kind": "collectionType",
    "collectionName": "chat_messages",
    "info": {
        "singularName": "chat-message",
        "pluralName": "chat-messages",
        "displayName": "ChatMessage",
        "description": ""
    },
    "options": {
        "draftAndPublish": false
    },
    "pluginOptions": {},
    "attributes": {
        "sender": {
            "type": "relation",
            "relation": "oneToOne",
            "target": "plugin::users-permissions.user"
        },
        "message": {
            "type": "string"
        }
    }
}

The easy way out is to change the relational datatype to a text type, and connect the two programmatically via a controller. But that doesn’t solve the issue of me not seeming to understand why/how I am misinterpreting the documentation, and I rather like to use the relational property cause that’s simply what it is for :man_shrugging:.

I was struggling with how to populate query http://localhost:1337/api/chat-messages?populate=* which did not work at first. But this warning that I had found somewhere resolved that;


:raised_hand: Caution

The find permission must be enabled for the content-types that are being populated. If a role doesn’t have access to a content-type it will not be populated (see User Guide for additional information on how to enable find permissions for content-types).


1 Like

It took me quite some hours, but (as usually with Strapi) the solution was very simple, it wasn’t just very straightforward. I had to set the permission of the users-permissions.user find value to true for authorised users. So when I finally figured this out, creating the controller for automatically adding the user id to the post, based on the authorisation header was fairly simple.

I couldn’t find this in the documentation tho, so I’d like to share it here so that whenever someone else is struggling to create a similar flow, this could help them.


async create(ctx) {
    const user = ctx.state.user
    
    if (!user) {
        return ctx.unauthorized("Missing credentials for new chat message")
    }

    // Allow requests that miss the data:{} wrapper
    if (!ctx.request.body.data) {
        const tmp = ctx.request.body
        ctx.request.body = {
            data: tmp
        }
    }

    if (!ctx.request.body.data.message) {
        return ctx.unauthorized("Missing required property: `message`")
    }

    ctx.request.body.data.sender = user.id  
    return await super.create(ctx)
},
1 Like