I'm trying to use the redis-om package to connect to a Redis server, but I'm getting the following error: "TypeError: url_1.URL is not a constructor" when using the built-in URL class from Node.js.
I have tried using the url.parse() function from the url module instead, but the error persists.
Here is my code with an altered password:
import { Client, Entity, Schema, Repository } from "redis-om";
const client = new Client(); async function connect() { console.log("Will connect to redis"); console.log({ client }); if (!client.isOpen()) {
try {
console.log("Attempting to connect to redis");
const res = await client.open("redis://default:0dOoaiVcvwRsadRdOQVqLDdXmhnRR6HA#redis-15206.c269.eu-west-1-3.ec2.cloud.redislabs.com:15206");
console.log({ res });
} catch (err) {
console.log("Error connecting to redis:");
console.log(err);
} } }
class Post extends Entity {}
let schema = new Schema(Post, { media: { type: "string" }, author: { type: "string" }, caption: { type: "string" }, created: { type: "number" }, });
interface Data { media: string; author: string; caption: string; created: number; }
export async function createPost(data: Data) { await connect();
const repository = client.fetchRepository(schema);
const post = repository.createEntity(data as any);
const id = await repository.save(post);
return id; }
Here is the error client.open() throws:
TypeError: url_1.URL is not a constructor
Related
I'm trying to create API factory for node.js, Express, Mongoose Tech stack. I also want to provide full type safety using Typescript and the option to add additional validation for creation and updates. For example I have "validator" like that:
type ICheckIfUnique = <M, T extends Model<M>, K extends keyof M>(
attributes: {
model: T;
key: K;
},
body: M
) => void;
export const checkIfUnique: ICheckIfUnique = async (attributes, body) => {
const { model, key } = attributes;
const value = body[key];
const isUnique = !(await model.findOne({ [key]: value }));
if (!isUnique) {
throw `${key} is not unique!`;
}
};
But I can't get the type right as I get:
I can't also find way to get custom model types for the factory methods:
export const factoryCreateEndpoint =
<T, D extends Model<T>>(model: D, additionalLogic?: any) =>
async (req: Request, res: Response): Promise<Response | undefined> => {
const body = req.body;
if (!body) {
return res.status(400).json({
success: false,
error: `You must provide ${capitalize(
model.collection.name.slice(0, -1)
)}.`,
});
}
if (additionalLogic) {
try {
for (const element in additionalLogic) {
const { validator, additionalVariables } = additionalLogic[element];
await validator(additionalVariables, req.body);
}
} catch (error) {
return res.status(400).json({ success: false, error });
}
}
try {
const object = new model(body);
await object.save();
return res.status(201).json({
success: true,
id: object._id,
message: `${capitalize(model.collection.name.slice(0, -1))} created.`,
});
} catch (error) {
return res.status(400).json({ success: false, error });
}
};
But with this generic type I get:
Everyone!
I'm now learning some microservices principies and i have some doubt's about on error in my query_service when received a event
Commonly my app create a post and in this post the user can put some comments, but i don't know what's going on and i'm tryed everything to solve this on my query service, because it breaks when the user make a comment in a post
The output error is: TypeError: Cannot read property 'comments' of undefined
my router code:
import { Response, Request, Router } from 'express';
const routes = Router();
interface IPost {
id: string;
title: string;
comments: Comments[];
}
type Post = { [key: string]: IPost };
type Comments = { id: string, content: string };
interface IData {
id: string;
content: string;
postId: string;
}
let posts: Post = {}
routes.get('/posts', (req: Request, res: Response) => {
res.send(posts);
});
routes.post('/events', (req: Request, res: Response) => {
try {
const { type, data } = req.body;
if (type === 'PostCreated') {
const { id, title }: IPost = data;
posts[id] = { id, title, comments: [] };
}
if (type === 'CommentCreated') {
const { id, content, postId }: IData = data;
posts[postId].comments.push({id, content});
}
console.log(posts)
res.status(201).send({});
} catch (error) {
console.log(error)
}
});
export default routes;
Everything else works fine.
anyone can help me on this issue?
repo of the project if you want to see the entire program: Microservice API
This error happens when the type equals CommentCreated, but there is no post with the given postId yet. In such a case you should also create the post first (as you do for type PostCreated), e.g;
if (type === 'CommentCreated') {
const {id, content, postId}: IData = data;
if (!posts[postId]) {
posts[postId] = {id:postId, comments: []};
}
posts[postId].comments.push({id, content});
}
Alternatively you could throw an error instead of creating the post if a comment were to be created for a non-existing post:
if (!posts[postId]) {
throw new Error("...");
}
I built the API with apollo server and everything works fine in graphiql. I make requests to the api from front-end react app with apollo client.
const [getUserPosts, { loading, error, data }] = useLazyQuery(GET_USER_POSTS);
useEffect(() => {
getUserProfile();
getUserPosts({ variables: { email: userEmail } });
}, [userEmail]);
SO getUserProfile fetches the user email from the express back end (I have an express serving react and a separate graphql api), then I query the posts of that user on the api. Below is the query itself
export const GET_USER_POSTS = gql`
query User($email: String) {
user(email: $email) {
email
posts {
content
}
}
}
`;
This is the typedefs and resolver on the api server
const typeDefs = gql`
type User {
email: String
posts: [Post]
}
type Post {
id: ID!
email: String
content: String
}
type Query {
users: [User]
posts: [Post]
user(email: String): [User]
post(id: String): [Post]
}
type Mutation {
addPost(email: String, content: String): [Post]
deletePost(id: String): [Post]
}
`;
const resolvers = {
Query: {
users: () => User.find(),
posts: () => Post.find(),
user: (parent, args) => User.find({ email: args.email }),
post: (parent, args) => Post.find({ _id: args.id }),
},
User: {
posts: async user => {
try {
const postsByUser = Post.find({ email: user.email });
return postsByUser;
} catch (error) {
console.log(err);
}
},
},
Mutation: {
addPost: async (parent, args) => {
const newPost = new Post({
email: args.email,
content: args.content,
});
try {
newPost.save();
} catch (err) {
console.log(err);
}
},
deletePost: async (parent, args) => {
try {
const deletedPost = await Post.deleteOne({ _id: args.id });
} catch (err) {
console.log(err);
}
},
},
};
then I try to console.log the data here
if (loading) {
console.log(loading);
}
if (error) {
console.log(error);
}
if (data) {
console.log(loading);
let test = data.user[0];
//I can see the data logged in the console as an object {email: "abc", posts: [array of posts]}
console.log(test);
}
BUT if I try to console.log(test.posts) react results with can not read property "posts" of undefined
UPDATE-1 !!
So when react results with the above error, I try to refresh the page again and it now can logs the "posts" array. But it sometimes take 2 or 3 refresh to make it work and sometimes when I refresh again it does not work anymore. Why is this happening ????
UPDATE-2 !!
So I try to troubleshoot with this line:
{data ? console.log(data.user[0].posts) : console.log("nothing")}
and interestingly it actually does log "nothing" a few times in the console before logging the data. But this is weird because I explicitly write that if only "data" is "true" then log it in the console. But somehow "data" is somtimes null itself. This data is provided by apollo client and it should be always true after loading is false, how is data still null after loading is false already ???
So I found the problem. Turns out it actually comes from within this block:
useEffect(() => {
getUserProfile();
getUserPosts({ variables: { email: userEmail } });
}, [userEmail]);
After observing in the network tab, it seems that my app try to send request to graphQL api before getUserProfile was done pulling user email, so it sent an empty request and hence received nothing. I was naive to think getUserProfile and getUserPosts will be executed synchronously. So I wrap getUserPosts with
if (userEmail) {
getUserPosts({ variables: { email: userEmail } });
}
So now only after I received the uerEmail then getUserPosts will be executed.
I'm currently using Objection.js with WebStorm to build a Rest API. But, when I want to make a relationQuery of Objection.js, my WebStorm shows me one out of two times that $query() is unresolved.
I have installed the Objection.js TypeScript, but it doesn't work. I also tried to invalidate the WebStorm cache, but no better results.
Here are some screenshots of the errors
$query() unresolved:
$query() resolved:
I also watched with Visual Studio Code, and the code in the first screenshot is well detected and solved
$query() resolved inside VSCode:
I use Node 12.17, WebStorm 2020.1 and Objection 2.1.3
Hoping you can help me.
Here is the complete code snipper of the error:
const Users = require('../../../database/Users');
const sendReset = require('../../../email/reset');
const { nanoid } = require('nanoid');
/**
* #api {post} /v1/users/reset ✔ Set a reset email for an account
* #apiName resetPassword
* #apiGroup Users
* #apiVersion 1.0.0
*
* #apiParam {String} email email address of the user
*
* #apiSuccessExample {json} Success-Response :
* HTML 200 Success
* {
* "text": "success"
* }
*/
async function resetPassword(req, res) {
let email = req.body["email"];
if (email) {
try {
let toEdit = await Users.query().findOne("email", email);
if (toEdit) {
let token = nanoid(42);
let edited = await toEdit.$query().patchAndFetch({'token': token});
if (edited)
await sendReset(edited);
}
res.status(200).json({"message": "success"});
} catch (e) {
res.status(500).json({"error": "Internal server error"});
}
}
}
module.exports = resetPassword;
Users.js:
/*
** Created by Frederic GOMEL on 03/03/2020 at 18:07
** Project: api
*/
const knex = require('../init/database');
const {Model} = require('objection');
Model.knex(knex);
class Users extends Model {
static get tableName() {
return 'users';
}
static get jsonSchema() {
return {
type: 'object',
required: ["email", "group_right", "firstName", "lastName", "token"],
properties: {
id: {type: 'integer'},
email: {type: 'string'},
group_right: {type: 'integer'},
firstName: {type: 'string'},
lastName: {type: 'string'},
password: {type: ['string', 'null']},
rfid_uid: {type: ['string', 'null']},
token: {type: ['string', 'null']}
}
};
}
static get relationMappings() {
const Racks = require('./Racks');
return {
racks: {
relation: Model.ManyToManyRelation,
modelClass: Racks,
join: {
from: 'users.id',
through: {
from: 'link_users_racks.user',
to: 'link_users_racks.rack'
},
to: 'racks.id'
}
}
};
}
}
module.exports = Users;
reset.js:
const mail = require('../init/mails');
const twig = require('twig');
function sendReset(user) {
return new Promise((resolve, reject) => {
twig.renderFile('./email/templates/resetPassword.twig', {
name: `${user["firstName"]} ${user["lastName"]}`,
support_email: global["config"]["support_email"],
url: `${process.env["APP_URL"]}/activate?email=${user["email"]}&token=${user["token"]}`,
title: `Demande de changement de mot de passe`,
favicon: `${process.env["API_URL"]}/assets/images/favicon.ico`,
logo: `${process.env["API_URL"]}/assets/images/logo.png`
}, async (err, html) => {
if (err) {
reject(err);
} else {
mail.sendMail({
sender: `JAD Technologie <${process.env["MAIL_MAIL"]}>`,
to: user['email'],
subject: `Demande de changement de mot de passe`,
html: html
}).then(() => {
resolve();
}).catch((err) => {
reject({"mail": true, err});
});
}
});
});
}
module.exports = sendReset;
I use Express.js 4.16.0
I have a GraphQL powered app. The query and mutation parts work well. I try to add GraphQL subscription.
The server GraphQL subscription part code is inspired by the demo in the readme of apollographql/subscriptions-transport-ws.
Please also check the comments in the code for more details.
import Koa from 'koa';
import Router from 'koa-router';
import graphqlHTTP from 'koa-graphql';
import asyncify from 'callback-to-async-iterator';
import { SubscriptionServer } from 'subscriptions-transport-ws';
import firebase from 'firebase-admin';
import { execute, subscribe } from 'graphql';
import { GraphQLObjectType, GraphQLString } from 'graphql';
const MeType = new GraphQLObjectType({
name: 'Me',
fields: () => ({
name: { type: GraphQLString },
// ...
}),
});
const listenMe = async (callback) => {
// Below the firebase API returns real-time data
return firebase
.database()
.ref('/users/123')
.on('value', (snapshot) => {
// snapshot.val() returns an Object including name field.
// Here I tested is correct, it always returns { name: 'Rose', ... }
// when some other fields inside got updated in database.
return callback(snapshot.val());
});
};
const Subscription = new GraphQLObjectType({
name: 'Subscription',
fields: () => ({
meChanged: {
type: MeType,
subscribe: () => asyncify(listenMe),
},
}),
});
const schema = new GraphQLSchema({
query: Query,
mutation: Mutation,
subscription: Subscription,
});
const app = new Koa();
app
.use(new Router()
.post('/graphql', async (ctx) => {
// ...
await graphqlHTTP({
schema,
graphiql: true,
})(ctx);
})
.routes());
const server = app.listen(3009);
SubscriptionServer.create(
{
schema,
execute,
subscribe,
},
{
server,
path: '/subscriptions',
},
);
I am using Altair GraphQL Client to test since it supports GraphQL subscription.
As the screenshot shows, it does get new data every time when the data changes in database.
However, meChanged is null and it does not throw any error. Any idea? Thanks
Finally have a new library can do the work without full Apollo framework.
https://github.com/enisdenjo/graphql-ws
Here are the codes that I have succeed:
Server (GraphQL Schema Definition Language)
import { useServer } from 'graphql-ws/lib/use/ws';
import WebSocket from 'ws';
import { buildSchema } from 'graphql';
const schema = buildSchema(`
type Subscription {
greeting: String
}
`);
const roots = {
subscription: {
greeting: async function* sayHiIn5Languages() {
for (const hi of ['Hi', 'Bonjour', 'Hola', 'Ciao', 'Zdravo']) {
yield { greeting: hi };
}
},
},
};
const wsServer = new ws.Server({
server, // Your HTTP server
path: '/graphql',
});
useServer(
{
schema,
execute,
subscribe,
roots,
},
wsServer
);
Server (GraphQL.js GraphQLSchema object way)
import { execute, subscribe, GraphQLObjectType, GraphQLSchema, GraphQLString } from 'graphql';
import { useServer } from 'graphql-ws/lib/use/ws';
import WebSocket from 'ws';
import { PubSub } from 'graphql-subscriptions';
const pubsub = new PubSub();
const subscription = new GraphQLObjectType({
name: 'Subscription',
fields: {
greeting: {
type: GraphQLString,
resolve: (source) => {
if (source instanceof Error) {
throw source;
}
return source.greeting;
},
subscribe: () => {
return pubsub.asyncIterator('greeting');
},
},
},
});
const schema = new GraphQLSchema({
query,
mutation,
subscription,
});
setInterval(() => {
pubsub.publish('greeting', {
greeting: 'Bonjour',
});
}, 1000);
const wsServer = new ws.Server({
server, // Your HTTP server
path: '/graphql',
});
useServer(
{
schema,
execute,
subscribe,
roots,
},
wsServer
);
Client
import { createClient } from 'graphql-ws';
const client = createClient({
url: 'wss://localhost:5000/graphql',
});
client.subscribe(
{
query: 'subscription { greeting }',
},
{
next: (data) => {
console.log('data', data);
},
error: (error) => {
console.error('error', error);
},
complete: () => {
console.log('no more greetings');
},
}
);
DISCLOSE: I am not associated with the library.