I've been successfully calling Meteor methods until I created a new Mongo collection. Both collections are found under /imports/collections/, so I know it's available to both client and server.
Here is the Meteor.method, which is pretty much the same as my working collection.:
import { Mongo } from 'meteor/mongo';
Meteor.methods({
'messages.insert': function(data) {
return Messages.insert({
otherCollectionId: data.otherCollectionId,
type: data.type,
createdAt: new Date(),
sender: this.userId,
text: data.text
});
}
});
export const Messages = new Mongo.Collection('messages');
Here's how I call it:
import React from 'react';
import { Messages } from '../../imports/collections/messages';
// other imports
export default class Chat extends React.Component {
// other code
handleComposeClick() {
if (this.refs.text) {
let data = {
playlistId: this.props.playlist._id,
type: 'user',
text: this.refs.text.value
};
Meteor.call('messages.insert', data, (error, playlistId) => {
if (!error) {
this.setState({error: ''});
this.refs.text.value = '';
} else {
this.setState({ error });
console.log(error);
}
});
}
}
// render()
}
Whenever I click and trigger handleComposeClick(), I get this error:
errorClass {error: 404, reason: "Method 'messages.insert' not found", details: undefined, message: "Method 'messages.insert' not found [404]", errorType: "Meteor.Error"}
Remember that anything inside the /imports folder will not work unless it's actually imported, either with this syntax:
import somethingINeed from '/imports/wherever/stuff';
import { somethingElseINeed } from '/imports/wherever/things';
or:
import '/imports/server/stuff';
So for methods, you may want to set up a structure where you have the following:
/lib/main.js
import '../imports/startup/lib';
/imports/startup/lib/index.js
import './methods';
// any other shared code you need to import
/imports/startup/lib/methods.js
import { Meteor } from 'meteor/meteor';
import { Messages } from '/imports/collections/messages'; // don't define your collections in a methods file
Meteor.methods({
'messages.insert': function(data) {
return Messages.insert({
otherCollectionId: data.otherCollectionId,
type: data.type,
createdAt: new Date(),
sender: this.userId,
text: data.text
});
}
});
Though if I were you, I'd use validated methods, where you actually import the method you want to use in order to use it, e.g.:
import { messagesInsert } from '/imports/common-methods/message-methods';
// code...
messagesInsert.call({ arg1, arg2 }, (error, result) => { /*...*/ });
With this structure, you would instead have /server/main.js import ../imports/startup/server which would import ./methods, which (in my particular project) looks like this:
// All methods have to be imported here, so they exist on the server
import '../../common-methods/attachment-methods';
import '../../common-methods/comment-methods';
import '../../common-methods/tag-methods';
import '../../common-methods/notification-methods';
import '../../features/Admin/methods/index';
import '../../features/Insights/methods';
import '../../features/Messages/methods';
Keep in mind, this doesn't actually execute the methods, it just makes sure they're defined on the server, so that when you import these validated methods on the client side and run them, it doesn't bomb out saying the method can't be found on the server side.
Import 'Messages' in your server side (/server/main.js)
Shout out to #MasterAM for helping me find my typo. Turns out I just had an incorrect path in /server/main.js
Related
I'm building a custom API, with an endpoint defined as follow:
I have a created a Profiling Controller to handle the logic for this endpoint. My controller directory contains 2 files:
controller.ts
import { Request, Response } from 'express';
import ProfilingService from '../../services/profiling.service';
export class Controller {
enrich_profile(req: Request, res: Response): void {
console.log(req);
ProfilingService.enrich_profile(req).then((r) =>
res
.status(201)
.location(`/api/v1/profile_data/enrich_profile/data${r}`)
.json(r)
);
}
}
export default new Controller();
routes.ts
/* eslint-disable prettier/prettier */
import express from 'express';
import controller from './controller';
export default express.
Router()
.post('/enrich_profile', controller.enrich_profile)
;
However, when I sent a call to the endpoint, I get the following error:
And finally, to allow a full picture, here's the content of profiling.service.ts:
import L from '../../common/logger';
interface Profiling {
data: never;
}
export class ProfilingService {
enrich_profile(data: never): Promise<Profiling> {
console.log(data);
L.info(`update user profile using \'${data}\'`);
const profile_data: Profiling = {
data,
};
return Promise.resolve(profile_data);
}
}
export default new ProfilingService();
The error clearly states that POST to the defined endpoint is not possible, and I'm not sure I understand why.
How can I fix this issue?
I'm not sure what was causing the issue, but after cleaning my npm cache, and deleting node_modules about 100X, the issue finally went away.
I am trying to implement this library with my React applicaiton however, I get an error when I import the package.
Error - TypeError: Object prototype may only be an Object or null: undefined
Package - https://www.npmjs.com/package/dukascopy-node
I tried importing it both ways, using require and using import from however it gives the same output
Function
import { getHistoricRates } from "dukascopy-node";
export const getHistoricalData = async (
instrument = "btcusd",
from = new Date("2018-01-01"),
to = new Date("2019-01-01"),
timeframe = "d1"
) => {
try {
const data = await getHistoricRates({
instrument: instrument,
dates: {
from: from,
to: to,
},
timeframe: timeframe,
format: "json",
});
console.log(data);
} catch (error) {
console.log("error", error);
}
};
As the import statement looks OK, there must be something wrong with your packages. I would try to delete the node_modules folder and reinstall all packages.
This is my go-to solution in such strange, unexplainable cases with imports.
I'm writing an app using Next.js + TypeORM and running in to an issue with the integration.
RepositoryNotFoundError: No repository for "User" was found. Looks like this entity is not registered in current "default" connection?
From what I can tell I have everything configured correctly but continue to get this error. I've debugged and inspected the active connection and see the entities on connection.options.entities so they are registered. Really stumped by this one.
Repo: https://github.com/kyleect/bolt
Server:
import "reflect-metadata";
import { createServer } from "http";
import { parse } from "url";
import { createConnection } from "typeorm";
import path from "path";
import next from "next";
import { Link } from "../entities/Link";
import { Post } from "../entities/Post";
import { User } from "../entities/User";
const dev = process.env.NODE_ENV !== "production";
const app = next({ dev });
const handle = app.getRequestHandler();
app
.prepare()
.then(() =>
createConnection({
type: "sqlite",
database: "local.db",
synchronize: true,
logging: true,
entities: [Link, Post, User],
})
)
.then(() => {
createServer((req, res) => {
handle(req, res, parse(req.url, true));
}).listen(3000, () => {
console.log("> Ready on http://localhost:3000");
});
});
One of the endpoint handlers. There is a similar one for all of them and they all throw an error:
const db = await getConnection();
const repo = db.getRepository(User);
const users = await repo.find();
res.json(users);
Entities:
import {
Entity,
Column,
PrimaryGeneratedColumn,
OneToMany,
CreateDateColumn,
UpdateDateColumn,
DeleteDateColumn,
} from "typeorm";
import { Post } from "./Post";
#Entity()
export class Link {
#PrimaryGeneratedColumn("uuid")
id: string;
#CreateDateColumn()
createdDate: Date;
#UpdateDateColumn()
updatedDate: Date;
#DeleteDateColumn()
deletedDate: Date;
#Column({ type: "varchar" })
url: string;
#OneToMany((type) => Post, (post) => post.link)
posts: Array<Post>;
}
import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
CreateDateColumn,
UpdateDateColumn,
DeleteDateColumn,
} from "typeorm";
import { User } from "./User";
import { Link } from "./Link";
#Entity()
export class Post {
#PrimaryGeneratedColumn("uuid")
id: string;
#CreateDateColumn()
createdDate: Date;
#UpdateDateColumn()
updatedDate: Date;
#DeleteDateColumn()
deletedDate: Date;
#ManyToOne((type) => User, (user) => user.posts)
user: User;
#Column({ type: "varchar" })
title: string;
#Column({ type: "varchar" })
body: string;
#ManyToOne((type) => Link, (link) => link.posts)
link: Link;
}
import {
Entity,
Column,
PrimaryGeneratedColumn,
OneToMany,
DeleteDateColumn,
UpdateDateColumn,
CreateDateColumn,
} from "typeorm";
import { Post } from "./Post";
#Entity()
export class User {
#PrimaryGeneratedColumn("uuid")
id: string;
#CreateDateColumn()
createdDate: Date;
#UpdateDateColumn()
updatedDate: Date;
#DeleteDateColumn()
deletedDate: Date;
#Column({ type: "varchar" })
username: string;
#OneToMany((type) => Post, (post) => post.user)
posts: Array<Post>;
}
The reason it's not finding your entity is because the way your project is set up you are transpiling your server.ts to JavaScript and running node ./dist/src/server.js, however the api endpoint in users.ts is not being transpiled ahead of time but instead is being webpacked and loaded as an ESModule via your framework.
I'm not sure what is the right way to set this up, but I believe the fact that you've got two different ways to transpile the TypeScript is the cause of the problem. In the TypeORM internals, it compares the class you want, User to the class that has been given to TypeORM as an entity. This equality comparison will fail because of what I mentioned above. In JavaScript an equality comparison for an object actually looks at the memory location and that'll be different with two different node processes.
You have a couple options from here:
If you just want to see something, happen, change line 9 of users.ts to const repo = db.getRepository('User'); - quote the entity name. TypeORM can also find entities by name. This works. I got a successful response when I did this.
Dig more into best practices in Vercel and TypeScript. Sorry, can't help you there!
I don't know if this is just a learning project or a million-dollar app. If it's the latter, I would definitely want to make sure the way Vercel handles your API endpoints is a best practice. I only know this framework by reputation, but looks to me like the approach there is suited for static content. I'm not sure why you wouldn't want your API to be transpiled along with your server.
UPDATE:
Can anyone help? I have been pursuing this without luck for the better half of this week. I do notice that the client is generating two POSTs. I have added code for the adapter. Is there anywhere else I should be looking?
I am going through the video tutorial provided below and am unable to resolve two errors when I click the submit button to save data to the database.
No model was found for 'user'
Two POSTs are being generated. This results in an Assertion Failed error, which I suspect is because the ID returned from the server does not match the current ID on the front-end.
I see that the database has two new records. When I click on the submit button again then the application takes me back to the todo-items page where it shows the two records. Can anyone advise what I am doing wrong?
Current versions:
Ember : 3.2.2
Ember Data : 3.2.0
jQuery : 3.3.1
Ember Simple Auth : 1.7.0
Video tutorial (the error occurs at the 11:30 mark): https://www.youtube.com/watch?v=bZ1D_aYGJnU. Note: the author of the video seems to have gotten the duplicate POST issue to go away right at the end of the video, but I do not see how.
Component/forms/todo-item-form/component.js
import Component from '#ember/component';
export default Component.extend({
actions:{
save(){
this.get('submit')();
}
}
});
Component/forms/todo-item-form/template.hbs
<form {{action "save" on="submit"}}>
{{input placeholder="description" value=todoItem.description}}
<br />
{{#if todoItem.validations.isValid}}
<button type="submit">Add</button>
{{else}}
<button type="submit" disabled>Add</button>
{{/if}}
</form>
templates/s/todo-items/add.hbs
{{forms/todo-item-form
todoItem=model
submit=(route-action "submitAction")
}}
{{outlet}}
models/todo-item.js
import DS from 'ember-data';
import { validator, buildValidations } from 'ember-cp-validations';
const { attr, belongsTo } = DS;
const Validations = buildValidations({
description: [
validator('presence', true),
validator('length', {
min: 4
})
]
});
export default DS.Model.extend(Validations, {
description: attr('string'),
owner: belongsTo('person')
});
adapter/Application.js
import DS from 'ember-data';
import ENV from 'todo-list-client/config/environment';
const {computed, inject :{service} } = Ember;
export default DS.JSONAPIAdapter.extend({
session: service(),
namespace: ENV.APP.namespace,
host: ENV.APP.host,
headers: computed('session.data.authenticated.token', function() {
let token = this.get('session.data.authenticated.access_token');
return { Authorization: `Bearer ${token}` };
}),
})
routes/s/todo-items/add.js
import Route from '#ember/routing/route';
export default Route.extend({
model(){
return this.store.createRecord('todo-item');
},
actions: {
submitAction() {
this.get('controller.model')
.save()
.then(() => {
this.transitionTo('s.todo-items');
});
}
},
});
The author adds Ember-Data-Route at about 15m5s for the add.js route as a mixin. This cleans up after the model.
He starts the explanation at that point, adds it in over the next minute or two in the video:
https://youtu.be/bZ1D_aYGJnU?t=15m5s
import Ember from 'ember';
import DataRoute from 'ember-data-route';
export default Ember.Route.extend(DataRoute, {
model() {
return this.store.createRecord('todo-item');
},
actions: {
save() {
this.get('controller.model')
.save()
.then(() => {
this.transitionTo('s.todo-items');
});
}
},
});
I'm using ember 2.7.0, and I am trying to set up my ember app with a currentUser.organization derived from the authenticated token. I am able to resolve the currentUser, but I'm unable to resolve the properties of the user's organization in my routes/controllers.
My user model:
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string'),
email: DS.attr('string'),
organization: DS.belongsTo('organization', { polymorphic: true, async: false } )
});
I've created a service which pulls the user like this:
//app/services/session-account.js
import Ember from 'ember';
import jwtDecode from 'npm:jwt-decode';
const { inject: { service }, RSVP } = Ember;
export default Ember.Service.extend({
session: service('session'),
store: service(),
loadCurrentUser() {
return new RSVP.Promise((resolve, reject) => {
const token = this.get('session.data').authenticated.access_token;
if (!Ember.isEmpty(token)) {
var token_payload = jwtDecode(token);
return this.get('store').findRecord('user', token_payload.user_id, { include: 'organization' }).then((user) => {
this.set('account', user);
this.set('organization', user.organization);
resolve();
}, reject);
} else {
resolve();
}
});
}
});
I'm triggering loadCurrentUser after the user logs in, and I've verified it successfully fetches the user from the back-end (and the organization data is included in the jsonapi response), but while I can inject the service into my controllers/routes and access the user and fetch its direct properties, I can't access any properties of the related organization, via either myservice.get('currentUser.organization.name') (comes back undefined), or myservice.get('currentOrganization.name'), which throws the following error:
Uncaught TypeError: Cannot read property '_relationships' of undefined.
If I load a user as a model and reference properties of the user.organization in a template, everything works fine- but on the javascript side, I can't get to the organization model.
EDIT:
I've subsequently tried the following variant:
return this.get('store').findRecord('user', token_payload.user_id, { include: 'organization' }).then((user) => {
this.set('currentUser', user);
user.get('organization').then((organization) => {
this.set('currentOrganization', organization);
}, reject);
resolve();
}, reject);
and this version (which draws from the ember guides relationship documentation) throws the error TypeError: user.get(...).then is not a function
I'd suggest to try:
1) Replace this.set('organization', user.organization); with this.set('organization', user.get('organization'));
2) Put console.log(user.get('organization')) after this.set('account', user); and look at output