I'm stuck trying to solve a problem. I'm using express js to build a rest api. I want the user to be able to update their profile.
I've created a User model:
export type User = {
email: string
creation_date: number
first_name?: string
last_name?: string
payment_detals?: {
iban: string
last_updated: string
}
address?: {
city: string
street: string
house_number: string
postal_code: string
}
products?: string[]
}
But I want to receive the request body and update the value for that user in the database (No SQL, Firebase). But I don't want the user to add fields which are not specified in the User type.
How do I check if the request body has type User, if not throw an error?
The route:
const edit = async (req: Request, res: Response) => {
try {
let data = req.body
if (data instanceof User)
} catch (err) {
return res.status(501).json({ error: err.message })
}
return res.status(200).json({ status: 'ok' })
I can't find any help on the internet, so maybe someone could help me out?
So for example, if the payload of the post request is:
{
"name": "Jack"
}
It should throw an error, because name
is not a member of User.
How can I solve this? All help is appreciated!
Updated now trying with classes:
export class CUser {
email: string
creation_date: number
first_name?: string
last_name?: string
payment_detals?: {
iban: string
last_updated: string
}
address?: {
city: string
street: string
house_number: string
postal_code: string
}
products?: string[]
}
The route
const edit = async (req: Request, res: Response) => {
let data = req.body
console.log(data instanceof CUser)
return res.status(200).json({ status: 'ok' })
}
When the request.body is:
{
"email": "[email protected]",
"creation_date": 849349388935
}
The data instanceof CUser
will always result to false. Wait is it maybe because data is an object?..
I'm stuck trying to solve a problem. I'm using express js to build a rest api. I want the user to be able to update their profile.
I've created a User model:
export type User = {
email: string
creation_date: number
first_name?: string
last_name?: string
payment_detals?: {
iban: string
last_updated: string
}
address?: {
city: string
street: string
house_number: string
postal_code: string
}
products?: string[]
}
But I want to receive the request body and update the value for that user in the database (No SQL, Firebase). But I don't want the user to add fields which are not specified in the User type.
How do I check if the request body has type User, if not throw an error?
The route:
const edit = async (req: Request, res: Response) => {
try {
let data = req.body
if (data instanceof User)
} catch (err) {
return res.status(501).json({ error: err.message })
}
return res.status(200).json({ status: 'ok' })
I can't find any help on the internet, so maybe someone could help me out?
So for example, if the payload of the post request is:
{
"name": "Jack"
}
It should throw an error, because name
is not a member of User.
How can I solve this? All help is appreciated!
Updated now trying with classes:
export class CUser {
email: string
creation_date: number
first_name?: string
last_name?: string
payment_detals?: {
iban: string
last_updated: string
}
address?: {
city: string
street: string
house_number: string
postal_code: string
}
products?: string[]
}
The route
const edit = async (req: Request, res: Response) => {
let data = req.body
console.log(data instanceof CUser)
return res.status(200).json({ status: 'ok' })
}
When the request.body is:
{
"email": "[email protected]",
"creation_date": 849349388935
}
The data instanceof CUser
will always result to false. Wait is it maybe because data is an object?..
- You have to understand that TypeScript is piled to normal JavaScript, which means all typehinting is stripped off. This means that the JavaScript that will be left, does not check for a class values to match with your input. You really have to create custom validation to make sure the object properties match your input. – PIDZB Commented Oct 10, 2020 at 20:32
- Thanks for your reply. Yes I understand how it works now, but how can I tackle this problem? To deny unwanted fields? – Steven Soekha Commented Oct 10, 2020 at 21:01
- You can use instanceof when you create a Class instead of a Type if im correct. Then you just do if(!data instanceof User) { throw new Error('Not a User');} – PIDZB Commented Oct 10, 2020 at 21:04
- But I see in a different ment that you cannot use Class, so that wont work as well... – PIDZB Commented Oct 10, 2020 at 21:10
- The only solution then is very ugly... You have to validate all fields in the object, e.g. for(let k in data), and check if it matches all properties in the Type... – PIDZB Commented Oct 10, 2020 at 21:11
3 Answers
Reset to default 2Types or interfaces that you define in Typescript are stripped when it's converted into Javascript, so you won't be able to able to check the type during runtime.
What you'll need to do is create a type-guard function that asserts true or false whether or not your request has those specific User
properties.
For a good example see: How to check the object type on runtime in TypeScript?
You can create a constructor or function in a typescript class , which will take the req.body and only pick the required keys from the object, assign to this member variable and return you a new instance of the User object.
Now you can apply the checks on User instance or also can create a validateObject method inside the User class
I've solved this by writing a function which pares the request body with the types that I expect, and it works great! If there is something wrong with the fields or the required is wrong, the server will throw an error immediately. Here are some code snippets:
The functions
export type Schema = {
fields: { [key: string]: string }
required?: string[]
}
const required = (obj: any, required: string[]) => {
for (let key of required) {
if (obj[key] === undefined) return false
}
return true
}
export const validate = async (obj: any, model: Schema) => {
if (model.required) {
const status = required(obj, model.required)
if (!status) return false
}
for (let key of Object.keys(obj)) {
if (model.fields[key] === undefined) return false
else if (typeof obj[key] !== model.fields[key]) return false
}
return true
}
Example type
import { Schema } from './'
export type User = {
email: string
creation_date: number
subscription: string
first_name?: string
last_name?: string
payment_detals?: {
iban: string
last_updated: string
}
address?: {
city: string
street: string
house_number: string
postal_code: string
}
categories?: string[]
products?: {
ean: number
category?: string
notes?: string
}[]
}
export const UserSchema: Schema = {
fields: {
email: 'string',
subscription: 'string',
first_name: 'string',
last_name: 'string',
payment_details: 'object',
address: 'object',
categories: 'object',
products: 'object',
},
required: ['email']
}
On the server
let status = await validate(body, UserSchema)
if (!status) return res.status(422).json(Message.error.wrong_request_body)
// else continue