Typescript: What is type URL? - typescript1.8

I want to make sure that an interface member of type string is a formally valid URL. I could declare a member as URL but I cannot assign it a string that is a valid URL.
interface test {
myurl: URL;
}
var a : test;
a.myurl = "http://www.google.ch"
When compiling I get:
Type 'string' is not assignable to type 'URL'.
Do I have to use decorators for my task (https://www.typescriptlang.org/docs/handbook/decorators.html)?
And what is URL good for?
I am using typescript 1.8.10

AFAICT, URL is a typescript "built-in" feature, based on the WhatWG Url specifications. The linked to page has both rationale and examples.
In short it offers a structured way of using urls while making sure that they are valid. It will throw errors when attempting to create invalid urls.
Typescript has the according type-definitions set as follows (as of typescript 2.1.5): in node_modules/typescript/lib/lib.es6.d.ts:
interface URL {
hash: string;
host: string;
hostname: string;
href: string;
readonly origin: string;
password: string;
pathname: string;
port: string;
protocol: string;
search: string;
username: string;
toString(): string;
}
declare var URL: {
prototype: URL;
new(url: string, base?: string): URL;
createObjectURL(object: any, options?: ObjectURLOptions): string;
revokeObjectURL(url: string): void;
}
For your use-case you should be able to use it like this:
a.myurl = new URL("http://www.google.ch");
More constructors, samples and explanations can be found in the WhatWG Url specifications.

Related

Nestjs Optional DTO during the Unit test

I have a simple controller:
#Patch('/:userId')
public async updateUser(
#Param('userId') userId: string,
#Body() userUpdate: UpdateUserDto): Promise<any> {
await this.usersService.update(userId, userUpdate);
}
The UpdateUserDto is:
import { IsEmail,IsString, IsOptional, MaxLength, IsNotEmpty} from "class-validator";
export class UpdateUserDto{
#IsEmail()
#IsOptional()
email:string;
#IsString()
#IsOptional()
password:string;
#IsString()
#MaxLength(30)
#IsNotEmpty()
#IsOptional()
name: string;
#IsString()
#MaxLength(40)
#IsNotEmpty()
#IsOptional()
username: string;
}
all fields are optional to create partial updates.
I don't have any error in my unit test if I use all fields
it('test', async () => {
const users = await controller.updateUser('10',{name: "testname",username:"fakeUser",email:"email",password:"S"});
});
but I get an error if I use part of it, like:
it('test', async () => {
const users = await controller.updateUser('10',{name: "testname",email:"email",password:"S"});
Argument of type '{ name: string; email: string; password: string; }'
is not assignable to parameter of type 'UpdateUserDto'.
Property 'username' is missing in type '{ name: string; email: string; password: string; }' but required in type 'UpdateUserDto'.
});
if password is optional (ie., can be undefined), then tell to TS it is: password?: string

Fastify equivalent of express-mongo-sanitize

Hello Fastify Experts,
In MongoDB queries I can pass various operators, which may risks the security aspect by having various attack surfaces.
So before sending the payload, I would like to sanitize the query/filters/sort etc. However I don't think I need to sanitize the request payload as such because Mongo will anyway store it as BSON, hence safer.
Now in Express world, we used to have the express-mongo-sanitize sort of plugin.
What open source plugin you propose for Fastify world to achieve the similar functionality?
Thanks,
Pradip
You have two options:
use the schema eviction: adding additionalProperties as flag into the input schema, will remove all the keys you did not expect from input
With this code, you can submit a payload with:
{
foo: 'hello',
$where: 'cut'
}
and the $where key will be removed.
const fastify = require('fastify')({ logger: true })
fastify.post('/', {
schema: {
body: {
type: 'object',
additionalProperties: false,
properties: {
foo: { type: 'string' }
}
}
}
},
async (request, reply) => {
console.log(request.body)
return request.body
})
fastify.listen(8080)
The framework you linked has a module feature and you can integrate it with an hook:
const mongoSanitize = require('express-mongo-sanitize');
fastify.addHook('preHandler', function hook (request, reply, done) {
mongoSanitize.sanitize(request.body);
done(null)
})

KeystoneJs virtual field cannot use a custom field type

I need to display a json/object in a readonly form and I wrote a custom field type for it but then when I use a virtual to transform it to a string for passing it to the custom field type. I put the custom type into the args but it shows Error: Unknown type "JsonViewer".
Any idea of how to make it work?
const { Virtual } = require("#keystonejs/fields");
const JsonViewer = require("#/components/fields/jsonViewer");
module.exports = {
fields: {
requestData: {
type: Virtual,
args: [{ name: "requestData", type: "JsonViewer" }],
resolver: async (json) => {
return JSON.stringify(json);
},
},
}
}
You have to provide complex type details if they do not exist in the generated schema for graphql.
In your case as you are doing JSON.stringify you can use String return type like this. BTW String type is default return type and you should not need any type declaration there for string type.
Also there is no args option in keystone Virtual field.
const { Virtual } = require("#keystonejs/fields");
module.exports = {
fields: {
requestData: {
type: Virtual,
graphQLReturnType: `String`,
resolver: async (json) => {
return JSON.stringify(json);
},
},
}
}

How do I upload files to a graphql backend implemented using graphql-upload using axios?

I have a GraphQL backend implemented using express, express-graphql, graphql and graphql-upload. My GraphQL schema declaration is as follows:
type OProject {
_id: ID!
title: String!
theme: String!
budget: Float!
documentation: String!
date: Date
}
input IProject {
title: String!
theme: String!
budget: Float!
file: Upload!
}
type Mutations {
create(data: IProject): OProject
}
type Mutation {
Project: Mutations
}
I want to make a create request to my GraphQL API at /graphql using axios. How go I go about it?
Following the GraphQL multipart request specification detailed here you would go about doing so by:
creating a FormData instance and populating it with the following:
The operations field,
the map field and,
the files to upload
Creating the FormData Instance
var formData = new FormData();
The operations field:
The value of this field will be a JSON string containing the GraphQL query and variables. You must set all file field in the variables object to null e.g:
const query = `
mutation($project: IProject!) {
Project { create(data: $project) { _id } }
}
`;
const project = {
title: document.getElementById("project-title").value,
theme: document.getElementById("project-theme").value,
budget: Number(document.getElementById("project-budget").value),
file: null
};
const operations = JSON.stringify({ query, variables: { project } });
formData.append("operations", operations);
The map field:
As its name implies, the value of this field will be a JSON string of an object whose keys are the names of the field in the FormData instance containing the files. The value of each field will be an array containing a string indicating to which field in the variables object the file, corresponding to value's key, will be bound to e.g:
const map = {
"0": ["variables.project.file"]
};
formData.append("map", JSON.stringify(map));
The files to upload
You then should add the files to the FormData instance as per the map. In this case;
const file = document.getElementById("file").files[0];
formData.append("0", file);
And that is it. You are now ready to make the request to your backend using axios and the FormData instance:
axios({
url: "/graphql",
method: "post",
data: formData
})
.then(response => { ... })
.catch(error => { ... });
To complete the answer of #Archy
If you are using definition of what you expect in GraphQl like Inputs don't forget to set your graphql mutation definition after the mutation keyword
You have to put the definition of your payload like this
const query = `
mutation MutationName($payload: Input!) {
DocumentUpload(payload: $payload) {
someDataToGet
}
}`
And your operations like this the operationName and the order doesn't matter
const operations = JSON.stringify({ operationName: "MutationName", variables: { payload: { file: null } }, query })

accessing attributes in sequelize instanceMethods

I'm adding an instance method to a sequelize model. According to the documentation I should be able to reference this.name, but the only value I can see is this.dataValues.name. I have no reason to believe that the high quality documentation is wrong .... but why does this happen?
Also, there are no setters or getters available. this.getDataValue / this.setDataValue work in getters / setters, but not in instanceMethods.
I can't find any relevant samples on the net - if you know of a project that reads (or better, writes) these values, please add that to your response.
module.exports = (sequelize: Sequelize, DataTypes: DataTypes) => {
return sequelize.define<UserInstance, UserPojo>('User', {
name: { type: DataTypes.STRING }
}, {
instanceMethods: {
myMethod: (value) => {
// this.name is undefined
// this.dataValues.name IS defined ??
}
}, ...
As you can probably see, I'm using Typescript. I just examined the generated Javascript, and immediately saw the problem.
Typescript puts this at the top of the module:
var _this = this;
And references that '_this', rather than the one in the context of the function -- didn't realize that! As soon as I changed this to traditional function() { } syntax, it worked. So, if you're using typescript, you can do this:
myMethod: function(value: type) => void {
}
That is, you don't have to give up on typing your arguments and return value.