1

I'm trying to build a REST API with NodeJS, ExpressJS and Prisma. At the moment, when I want to update a user through the PATH method, I do this:

const data = {}

if (req.body.email != null)
    data.email = req.body.email
if (req.body.password != null)
    data.password = req.body.password
if (req.body.first_name != null)
    data.first_name = req.body.first_name
if (req.body.last_name != null)
    data.last_name = req.body.last_name

await prisma.user.update({
    where: {
        id: parseInt(id)
    },
    data: data
})

I removed the unnecessary code to show you the essential things.

I think this is not the best option, is there an easier way to do the same thing? I've tried a few solutions but none of them work with Prisma, that's why I'm here.

Sn0w
  • 25
  • 5
  • what if you just `const data = {...req.body}` – Jaromanda X Oct 01 '22 at 22:57
  • @JaromandaX - That may include all sorts of properties that shouldn't be there. – jfriend00 Oct 01 '22 at 23:00
  • @jfriend00 true, but then client code would be sending properties it shouldn't :p – Jaromanda X Oct 01 '22 at 23:01
  • 1
    @JaromandaX - Which is always something you have to defend against because a POST can come from any source, not just your own client code. Plus, I think this an an API specifically designed to be other types of clients. – jfriend00 Oct 01 '22 at 23:03
  • @JaromandaX this could work but as jfriend00 says, I don't want any other data to be sent by the user. – Sn0w Oct 02 '22 at 11:14

2 Answers2

1

You could make yourself a function that copies properties that meet some condition:

function copyNamedPropsWithData(props, src, target = {}) {
    for (let prop of props) {
        if (src[prop] != null) {
            target[prop] = src[prop];
        }
    }
    return target;
}

and then use that function:

const validProps = ["email", "password", "first_name", "last_name"];
await prisma.user.update({
    where: {
        id: parseInt(id)
    },
    data: copyNamedPropsWithData(validProps, req.body)
})

This allows you to create a new sterile object that contains only the non-empty properties that you list. It keeps you from specifying empty properties and it blocks other properties that aren't in your named list. I end up using something like this in nearly every project because it's an important part of sterlizing data coming from an unknown source to only contain the fields you want it to contain.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

You could make a helper function to make the code less repetitive

Something like

const copyProps = (src, ...keys) =>
  Object.fromEntries(
    Object.entries(src)
    .filter(([k,v]) => keys.includes(k) && v != null)
  );

Then you can use it like

await prisma.user.update({
    where: {
        id: parseInt(id)
    },
    data: copyProps(req.body, 'email', 'password', 'first_name', 'last_name');
});
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87