is there any way of change the 'Error' to something like 'Setup Error' followed by the description of something that went wrong?
async allBays() {
try {
let response = await mapService.getBaysList();
let bayList = response.data.data;
if (bayList) {
this.bays = bayList.map((list) => {
return {
value: { id: list.id, name: list.state },
text: list.state,
};
});
}
} catch (e) {
Sentry.captureException(new Error("Could not load bays"), {
tags: {
section: "Farm Setup",
},
});
}
},
This looks like the following:
Thanks for any help, documentation is ridiculously long and I can't find the exact answer
You can extend the JavaScript Error class.
class SetupError extends Error {
constructor(message) {
super(message)
this.name = 'Setup Error'
}
}
async allBays() {
try {
let response = await mapService.getBaysList();
let bayList = response.data.data;
if (bayList) {
this.bays = bayList.map((list) => {
return {
value: { id: list.id, name: list.state },
text: list.state,
};
});
}
} catch (e) {
Sentry.captureException(new SetupError("Could not load bays"), {
tags: {
section: "Farm Setup",
},
});
}
},
Related
I am sending a mutation over from a React Native Frontend to a NodeJs / GraphQL Backend. The mutation request goes through, and a mutation occurs, but back on the frontend, the value of that mutation is undefined when it should instead be returning an ID. My mutation looks like this...
export default {
Mutation: {
driverCreateCollisionAccident: async (_, {
accidentId,
specific_pictures,
contact_info,
collision_report,
extra_info
}, context) => {
const driver = await checkDriverAuth(context)
const foundAccident = await db.accident.findUnique({
where: {
id: accidentId
}
})
if (!foundAccident) {
throw new Error("Accident does not exist")
}
await handleDriverAccidentOwnership(driver.id, accidentId)
console.log("right before create collision mutation")
try {
return await db.collisionAccident.create({
data: {
specific_pictures: specific_pictures,
contact_info: contact_info,
collision_report: collision_report,
extra_info: extra_info,
accident: {
connect: {
id: accidentId
}
},
accidentId: accidentId
}
}).then( (resolved) => {
console.log(resolved)
return resolved
})
} catch (error) {
console.log(error)
throw new Error(error)
}
}
}
}
The most important part of that code is
.then( (resolved) => {
console.log(resolved)
return resolved
})
As the console.log returns exactly what it is supposed to, an object that looks like this...
id: '81b7cc7c-53d7-43d7-bb14-1438ef53a227',
specific_pictures: { 'Pic One': 'Test url' },
contact_info: {
address: 'Have Picture',
lastname: 'Have Picture',
firstname: 'Have Picture',
phone_number: '123456789',
insurance_provider: 'Have Picture',
driver_license_number: 'Have Picture',
insurance_policy_number: 'Have Picture'
},
extra_info: 'null',
collision_report: {
towed: true,
legal_fault: 'I caused the accident',
fire_or_explode: true
},
accidentId: '0b5fd832-9540-475e-9b34-ece6dfdc58df'
}
But for some reason, when I try to log the results of this mutation on the frontend, all I get is undefined, but no errors occur, and I still get the backend's console.logs to hit properly so the mutation itself is working. My front end code looks like this...
const handleSubmit = () => {
handleMutation().then( (resolved) => {
console.log(resolved)
})
}
const handleMutation = async () => {
await driverCreateCollisionAccident({
variables: {
accidentId: collisionData.accidentId,
specific_pictures: collisionData.specific_pictures,
contact_info: collisionData.contact_info,
collision_report: collisionData.collision_report,
extra_info: collisionData.extra_info,
}
})
}
I don't even need the full object returned, I JUST need an ID. Does anyone see what could be going wrong here?
Maybe you can try something like this
const result = await db.collisionAccident.create({
data: {
specific_pictures: specific_pictures,
contact_info: contact_info,
collision_report: collision_report,
extra_info: extra_info,
accident: {
connect: {
id: accidentId
}
},
accidentId: accidentId
}
})
return result
instead of
return await db.collisionAccident.create({
data: {
specific_pictures: specific_pictures,
contact_info: contact_info,
collision_report: collision_report,
extra_info: extra_info,
accident: {
connect: {
id: accidentId
}
},
accidentId: accidentId
}
}).then( (resolved) => {
console.log(resolved)
return resolved
})
I am new to React-Native.
I am trying to cropImage and with the result, cropped.uri, I want to storeData of objects of {key : keyIndex++, productname: object.object, expiryDate: 8, image: cropped.uri}
Below is my code block.
I cannot send the result from cropImage to the line before {key : keyIndex++, productname: object.object, expiryDate: 8, image: cropped.uri}. It prints the right result inside of cropImage but if I print it outside the function, it says 'undefined'.
I tried constructor and states, but it still prints 'undefined'
I think it is a timing problem.. but have no idea. Help please.
export default class AddItems extends React.Component {
componentDidMount() {
const endpoint = `https://foodsaver.cognitiveservices.azure.com/`;
const key = `89625116fce1a`;
const apiPath = `${endpoint}/vision/v2.0/analyze`;
const storeData = async (value)=>{
try {
await AsyncStorage.setItem("items", JSON.stringify(value))
} catch(e){
console.log("error occured during store data", e)
}
}
const readData = async () => {
try {
const data = await AsyncStorage.getItem("items")
if(data != null){
// console.log(JSON.parse(data))
return JSON.parse(data)
} else {
return []
}
}catch(e){
console.log("error occured during reading data", e)
}
}
const cropImage = async (object) => {
cropData = {
originX:object.rectangle.x,
originY:object.rectangle.y,
width:object.rectangle.w,
height:object.rectangle.h
}
try{
await ImageManipulator.manipulateAsync(items.uri, [{crop:cropData}], {compress: 1})
.then(cropped => {
// console.debug(cropped.uri), //ok
object.image = cropped.uri
})
}
catch(error){
console.log('Error caught in this.cropImage:', error)
}
}
const fd = new FormData();
var items = {
uri: "file:///Users/Repositories/FoodSaver/assets/items.jpeg",
name: "items.jpeg",
type: "image/jpeg"
}
fd.append("file", items)
axios.post(
apiPath,
fd,
{
params: {
language : "en",
visualFeatures: "Objects"
},
headers : {
"Ocp-Apim-Subscription-Key" : key,
"Content-Type": "multipart/form-data"
}
}
).then(({data:{objects}})=>{
const res = objects.map(object=>{
if (object.object === "Fruit") {
// want to add image here!
return {key : keyIndex++, productname: object.object, expiryDate: 8, image: cropImage(object).image}
}
return {key : keyIndex++, productname: object.object, expiryDate: 10, image: cropImage(object).image}
})
readData().then((data)=>{
const listOfObject = [...data, ...res]
storeData(listOfObject)
Alert.alert(`Items are added to My Fridge!`)
})
})
.catch((e)=>console.log("error", e));
}
Two parts to the problem:
cropImage doesn't return anything
not waiting for asynchronous behaviour to finish executing
cropImage doesn't return anything
there is no return value from cropImage so
image: cropImage(object).image is effectively the same as image: undefined.image
Let's return the result of manipulateAsync
try{
return ImageManipulator.manipulateAsync(items.uri, [{crop:cropData}], {compress: 1})
}
not waiting for asynchronous behaviour to finish executing
You have another issue related to async execution which you picked up on.
cropImage has async code and you depend on its result so you'll have to use the await syntax when executing cropImage to ensure it finishes executing.
return {key : keyIndex++, productname: object.object, expiryDate: 8, image: await cropImage(object).uri}
I would like to have more than one Validator instance on my service to handle different languages. Is there any way to implement that?
Something like that:
{
en: new Validator({ messages: { ... }}),
de: new Validator({ messages: { ... }})
// ...
}
It is not available. You should create a custom multi-validators. Here is a quick example:
"use strict";
const _ = require("lodash");
const { ServiceBroker } = require("moleculer");
const BaseValidator = require("moleculer").Validators.Base;
const Validator = require("fastest-validator");
const DefaultMessages = require("fastest-validator/lib/messages");
const { ValidationError } = require("moleculer").Errors;
// --- I18N VALIDATOR CLASS ---
class I18NValidator extends BaseValidator {
constructor(messages) {
super();
0;
this.validators = {};
Object.keys(messages).forEach(lang => {
this.validators[lang] = new Validator();
this.validators[lang].messages = Object.assign({}, DefaultMessages, messages[lang]);
});
}
compile(schema) {
this.checks = {};
Object.keys(this.validators).forEach(lang => {
this.checks[lang] = this.validators[lang].compile(schema);
});
return this.checks;
}
middleware() {
return function I18NValidator(handler, action) {
// Wrap a param validator
if (action.params && typeof action.params === "object") {
const checks = this.compile(action.params);
return function validateContextParams(ctx) {
const check = checks[ctx.meta.lang] || checks["en"];
const res = check(ctx.params);
if (res === true)
return handler(ctx);
else
return Promise.reject(new ValidationError("Parameters validation error!", null, res));
};
}
return handler;
}.bind(this);
}
}
let broker = new ServiceBroker({
logger: true,
validation: true,
validator: new I18NValidator({
"en": {
"string": "The '{field}' field must be a string!"
},
"hu": {
"string": "A '{field}' mezőnek szövegnek kell lennie!"
}
})
});
// --- TEST BROKER ---
broker.createService({
name: "greeter",
actions: {
hello: {
params: {
name: { type: "string", min: 4 }
},
handler(ctx) {
return `Hello ${ctx.params.name}`;
}
}
}
});
broker.start()
// No meta lang
.then(() => broker.call("greeter.hello", { name: 100 }).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data))
// "hu" lang
.then(() => broker.call("greeter.hello", { name: 100 }, { meta: { lang: "hu" }}).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data))
// "en" lang
.then(() => broker.call("greeter.hello", { name: 100 }, { meta: { lang: "en" }}).then(res => broker.logger.info(res)))
.catch(err => broker.logger.error(err.message, err.data));
It reads the lang from the ctx.meta.lang but you can change it for your case.
I am trying to set my components variable using an api rest command. I wanted to handle all responses through a function in its own file called handleResponse() which is below.
// api/tools/index.js
function handleResponse (promise, cb, cbError) {
var cbErrorRun = (cbError && typeof cb === "function")
promise.then(function (response) {
if (!response.error) {
cb(response)
}
else if (cbErrorRun) {
cbError(response)
}
}).catch(function (error) {
console.log(error)
if (cbErrorRun) {
var responseError = {
"status": 404,
"error": true,
"message": error.toString()
}
cbError(responseError)
}
})
}
export {handleResponse}
In my component file I have this
.... More above....
<script>
import { fetchStock } from '#/api/stock'
export default {
data () {
return {
stock: {},
tabs: [
{
title: 'Info',
id: 'info'
},
{
title: 'Listings',
id: 'listings'
},
{
title: 'Company',
id: 'company'
}
],
}
},
validate ({params}) {
return /^\d+$/.test(params.id)
},
created: function() {
var params = {'id': this.$route.params.stockId}
//this.$route.params.stockId}
fetchStock(
params,
function(response) { //on successful data retrieval
this.stock = response.data.payload // payload = {'name': test123}
console.log(response)
},
function(responseError) { //on error
console.log(responseError)
}
)
}
}
</script>
The current code gives me this error: "Uncaught (in promise) TypeError: Cannot set property 'stock' of undefinedAc". I think this happens because I no longer have access to 'this' within the callback I pass in the fetchStock function. How would I fix this without changing the current handleResponse layout.
You can try this trick
created: function() {
var params = {'id': this.$route.params.stockId}
//this.$route.params.stockId}
var self = this;
fetchStock(
params,
function(response) { //on successful data retrieval
self.stock = response.data.payload // payload = {'name': test123}
console.log(response)
},
function(responseError) { //on error
console.log(responseError)
}
)
}
You can either use an arrow function for you callback since arrow functions maintain and use the this of their containing scope:
created: function() {
var params = {'id': this.$route.params.stockId}
//this.$route.params.stockId}
fetchStock(
params,
(response) => { //on successful data retrieval
self.stock = response.data.payload // payload = {'name': test123}
console.log(response)
},
(responseError) => { //on error
console.log(responseError)
}
)
}
Or you can assign const vm = this n the beginning of your method before the callbacks like so.
vm stands for "View Model"
created: function() {
var params = {'id': this.$route.params.stockId}
//this.$route.params.stockId}
const vm = this;
fetchStock(
params,
function(response) { //on successful data retrieval
self.stock = response.data.payload // payload = {'name': test123}
console.log(response)
},
function(responseError) { //on error
console.log(responseError)
}
)
}
I advise using the const as opposed to var in the vm declaration to make it obvious the value of vm is a constant.
I have been having SO much trouble trying to get a mutation to work.
Given this GraphQL Schema, can anyone PLEASE help me create a simple create User mutation? I don't understand what I am missing. I got it to a point where it throws a 400 error from the GraphQL server and it does not fire the resolve function.
var userType = new GraphQLObjectType({
name: 'User',
description: 'User creator',
fields: () => ({
id: {
type: new GraphQLNonNull(GraphQLString),
description: 'The id of the user.'
},
email: {
type: GraphQLString,
description: 'The email of the user.'
},
business: {
type: GraphQLString,
description:
'The name of the business of the user as the app refers to it.'
},
businessDisplayName: {
type: GraphQLString,
description: 'The name of the business of the user as they typed it in.'
},
trips: {
type: new GraphQLList(tripType),
description: 'The trips of the user, or an empty list if they have none.',
resolve: (user, params, source, fieldASTs) => {
var projections = infoToProjection(fieldASTs)
return Trip.find(
{
_id: {
// to make it easily testable
$in: user.trips.map(id => id.toString())
}
},
projections,
function(err, docs) {
return docs
}
)
}
}
})
})
var schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'root',
fields: {
trips: {
type: new GraphQLList(tripType),
resolve: function() {
return Trip.find({})
}
},
users: {
type: new GraphQLList(userType),
resolve: function() {
return User.find({})
}
},
user: {
type: userType,
args: {
id: {
name: 'id',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, { id }, source, fieldASTs) => {
return User.findOne(
{ _id: id },
infoToProjection(fieldASTs),
function(err, doc) {
return doc
}
)
}
},
trip: {
type: tripType,
args: {
id: {
name: 'id',
type: new GraphQLNonNull(GraphQLString)
}
},
resolve: (root, { id }, source, fieldASTs) => {
var projections = infoToProjection(fieldASTs)
return Trip.findOne({ _id: id }, projections, function(err, doc) {
return doc
})
}
}
}
}),
// mutation
mutation: new GraphQLObjectType({
name: 'Mutation',
fields: {
createUser: {
name: 'createUser',
type: userType,
args: {
input: { type: new GraphQLInputObjectType({
name: 'user',
fields: {
business: { type: GraphQLString },
email: { type: GraphQLString },
businessDisplayName: { type: GraphQLString }
}
})
}},
resolve: (parentValue, args) => {
let user = new User({ ...args.input })
user.save()
return user
}
}
})
})
export var getProjections = infoToProjection
export default schema
This works with GraphiQL using the following queries or mutations:
mutation {
createUser(input:{business:"business", email: "e#mai.l", businessDisplayName: "businessDN"}) {
id
email
business
businessDisplayName
}
}
fragment UserFragment on User {
id
business
businessDisplayName
trips{
title
}
}
{
hideya: user(id: "someid") {
...UserFragment
}
}
I finally fixed the problem. Tried to understand the source of the problem so I used a new NetworkLayer to enable appropriate logging and meaningful error messages. Then threw the an error when my mutation failed. The error message was : "Cannot query field clientMutationId". Looked that up and found that to be able to mutate objects you need to have that field on your GraphQL type. So I added it.
Lesson learned: I highly recommend using react-relay-network-layer.
More details:
Here is my code for it:
import {
RelayNetworkLayer,
urlMiddleware,
batchMiddleware,
} from 'react-relay-network-layer';
Relay.injectNetworkLayer(new RelayNetworkLayer([
batchMiddleware({
batchUrl: 'http://localhost:3000/graphql',
}),
urlMiddleware({
url: 'http://localhost:3000/graphql',
}),
]));
Note: This enables logging and by default it's a simple console.log.
Here is how I threw the error:
const params = {
email: email.toLowerCase(),
businessDisplayName: business,
business: business.toLowerCase()
}
var onSuccess = () => {
console.log('Mutation successful!')
}
var onFailure = transaction => {
var error = transaction.getError() || new Error('Mutation failed.')
console.error(error)
}
Relay.Store.commitUpdate(new FindOrCreateUser({ user: { ...params } }), { onFailure, onSuccess })
And of course you always need to clean your cache and restart your packager.