ts-rest / ts-rest

RPC-like client, contract, and server implementation for a pure REST API
https://ts-rest.com
MIT License
2.11k stars 91 forks source link

Validate multipart body with @ts-rest/fastify #595

Closed mbenedettini closed 1 month ago

mbenedettini commented 1 month ago

I was trying to get @ts-rest/fastify to validate a multipart body and ended up making this modification for it to happen.

Am I in the right direction? If so, I'm happy to fix types and add tests to make this a proper contribution.

If not, can you point me how I should address validation for a scenario like this where I have a contract as follows and I'm also using @fastify/multipart to get streams for uploaded files? I couldn't find any other place where to hook up such validation:

import { MultipartFile as MultipartFileFastify } from "@fastify/multipart";
const MultipartFile: z.ZodType<MultipartFileFastify> = z.any();
const Schema = z.object({
  from: z.string(),
  to: z.string(),
  text: z.string().optional(),
  subject: z.string().optional(),
  message: z.string().optional(),
  attachmentStreams: z.array(MultipartFile).optional(),
});

Thanks! Mariano.

changeset-bot[bot] commented 1 month ago

⚠️ No Changeset found

Latest commit: f7bdf7ca77a7cc564765b9714c5bd1fb8b042814

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

vercel[bot] commented 1 month ago

@mbenedettini is attempting to deploy a commit to the ts-rest Team on Vercel.

A member of the Team first needs to authorize it.

sonarcloud[bot] commented 1 month ago

Quality Gate Passed Quality Gate passed

Issues
3 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

Gabrola commented 1 month ago

Just use attachFieldsToBody: 'keyValues' when registering @fastify/multipart

mbenedettini commented 1 month ago

It doesn't work for the reason I submitted this PR: body values are no longer the values itself but objects from which you need to read the key value.

Here's a minimal proof of concept that reproduces the issue: https://github.com/mbenedettini/ts-rest-fastify-multipart-proof

Gabrola commented 1 month ago

@mbenedettini It's not validating because you are using a pure typescript type for your schema, not a Zod schema. attachFieldsToBody: 'keyValues' will set the values directly in body, not in .value fields.

If you set the body to this it should work.

z.object({
  requiredField: z.string(),
  file: z.instanceof(Buffer),
})
mbenedettini commented 1 month ago

@Gabrola thanks, that works. For the record, this is how I defined the contract:

import { MultipartFile } from "@fastify/multipart";
const Multipart: z.ZodType<MultipartFile> = z.any();
const BodySchema = z.object({
  requiredField: z.string(),
  file: Multipart,
});