zenstackhq / zenstack

Fullstack TypeScript toolkit that enhances Prisma ORM with flexible Authorization layer for RBAC/ABAC/PBAC/ReBAC, offering auto-generated type-safe APIs and frontend hooks.
https://zenstack.dev
MIT License
2.07k stars 88 forks source link

File Upload API POST #561

Closed 1Map closed 1 year ago

1Map commented 1 year ago

I Understand that zenstack generates all the routes for me. My problem is:

How would I declare a model that handles multiple file uploads?

For example, I have a model:

model Upload {
    id String @id @default(cuid())
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
    expireDays Int @default(60)
    origFileName String
    fileName String
    filePath String
    fileSize Int
    uploadedByUserId String
    uploadedForUserId String
    uploadedBy User @relation(fields: [uploadedByUserId], references: [id], name: "uploadsBy")
    uploadedFor User @relation(fields: [uploadedForUserId], references: [id], name: "uploadsFor")
    downloads Download[] @relation(name: "fileDownloads")

    // Any user can upload a file
    @@allow('create', auth() == uploadedBy)

    // Users can read their own uploads or uploads assigned to them
    @@allow('read', auth() == uploadedBy || auth() == uploadedFor)
}

Now, I need a custom POST route that receives the Files, read the filename, size, etc. Saves the file to a folder and create an entry in the model above. After that sends back a result to the client. Because zenstack creates the above route for me, it does not allow me to override it with my custom code as explained above.

Will appreciate it if I can have an example of how this is done server side as I am new to zenstack and prisma.

ymc9 commented 1 year ago

Hi @1Map , just to understand your setup here. What stack are you using with zenstack? Like using it in the backend with expressjs/fastify, or using tRPC?

1Map commented 1 year ago

Hy @ymc9 . Thanks, I followed the blog at: https://zenstack.dev/blog/openapi and adapted to have a file upload model "Upload".

ymc9 commented 1 year ago

Got it. In this case, you can just implement a separate Express route for the file upload, and after the upload succeeds, create a record of the Upload model. In that route, you can simply use a regular Prisma Client (if you do permission checks by yourself) or continue using the "zenstack-enhanced" client.

Using ZenStack doesn't prevent you from building the app with standard Express.js features.

@1Map

1Map commented 1 year ago

Thanks @ymc9

I am not sure about how to set the jsdoc for an upload route that handles a file and some extra parameters as well, for example

/**
 * Upload input
 * @typedef {object} UploadInput
 * @property {string} file.required - The file (--- NOT SURE HOW TO USE type ---)
 * @property {string} extraparam1.required - Extra Parameter
 * @property {string} extraparam2.required - Extra Parameter
 */

/**
 * Upload response
 * @typedef {object} UploadResponse
 * @property {string} id.required - The upload id
 * @property {string} message.required - The upload message
 */

/**
 * POST /api/upload
 * @tags upload
 * @summary Uploads a new file
 * @param {UploadInput} request.body.required - fileandsomeparams - multipart/form-data
 * @return {UploadResponse} 200 - upload response
 * @security Bearer
 */

Will appreciate it if you can help me on an example of this as I am left in the dark.

ymc9 commented 1 year ago

Hi @1Map , this issue appears out of the scope of ZenStack. I'm closing it for now.