I'm creating a backend using Sequelize. For best practices, I want to return Location header if the user tries to create an duplicated resource. Check my code:
try {
const resource = await Resource.create(data);
return res.status(201).send(resource);
} catch (error) {
// Error handling
switch (error.name) {
case 'SequelizeDatabaseError': return res.status(400).send(error);
case 'SequelizeUniqueConstraintError': {
// Resource location
res.location(`/${_location_}`)
return res.status(409).send(_resource_)
};
}
Obs: I'm not sure if check error.name is the best way to get the error. Please comment others if you know.
Printing the error on the console I found the error details:
{
// ...
ValidationErrorItem {
message: 'name must be unique',
type: 'unique violation',
path: 'name',
value: _value_,
origin: 'DB',
instance: [Resource],
validatorKey: 'not_unique',
validatorName: null,
validatorArgs: []
}
],
fields: { name: _value_ },
detail: 'Key (name)=(_value_) already exists.',
// ...
}
Obs: _value_ refers to duplicated value and name to column name.
There is a way to get the id (primary key, uuid, etc.) of the conflicting resource without do another query? If don't, should I really do the query just for return the Location header param?
I also tried it on my local server. I don't think it is possible to get Primary key of the conflicting row.
I would suggest before making .create() call you make .findOne() query so if you found already existing entry then you can return that row so it will also prevent error while creating new entry and it will also save create query on Database.
Related
I'm trying to insert data to my Wix collection using the API. I'm using a POST function and am posting a JSON document. It's supposed to simply add a new row to a database containing 1 value.
Here is the http-functions.js which I can trigger without issues (it's more or less a copy of the example from the documentation):
import {created, serverError} from 'wix-http-functions';
import wixData from 'wix-data';
export function post_peopleCount(request) {
let options = {
"headers": {
"Content-Type": "application/json"
}
};
// get the request body
return request.body.text()
.then( (body) => {
// insert the item in a collection
return wixData.insert("NumberOfPeopleDB", JSON.parse(body));
} )
.then( (results) => {
options.body = {
"inserted": results
};
return created(options);
} )
// something went wrong
.catch( (error) => {
options.body = {
"error": error
};
return serverError(options);
} );
}
The database looks like this:
and the JSON I am posting looks like this:
But the Error I am getting is:
But the permissions I have set for the collection is:
Do you know why I might be getting that "WD_PERMISSION_DENIED" and 500 Server Error? (The data does not get entered.)
Thanks!
My friend, its not related to creating a collection from scratch it is because of the permissions set to this collection once created. You fixed that by not noticing :).
Permission need to be given in order to perform such queries.
It turns out, if I create a new collection (= table) from scratch, it works. I also changed the field value in the collection to people, maybe value is a reserved term. Nevertheless, now it seems to work:
So if you run into the same problem: Try recreating the collections from scratch.
The critical thing for me which has not been mentioned yet is that you need to set the collection to have form-like permissions so that anyone has permission to submit data to the collection.
Given the following GraphQL mutations:
type Mutation {
updateUser(id: ID!, newEmail: String!): User
updatePost(id: ID!, newTitle: String!): Post
}
The Apollo docs state that it's totally possible to perform multiple mutations in one request, say
mutation($userId: ID!, $newEmail: String!, $postId: ID!, $newTitle: String!) {
updateUser(id: $userId, newEmail: $newEmail) {
id
email
}
updatePost(id: $postId, newTitle: $newTitle) {
id
title
}
}
1. Does anyone actually do this? And if you don't do this explicitly, will batching cause this kind of mutation merging?
2. If you perform run multiple things within on mutation, how would you handle errors properly?
I've seen a bunch of people recommending to throw errors on the server so that the server would respond with something that looks like this:
{
errors: [
{
statusCode: 422,
error: 'Unprocessable Entity'
path: [
'updateUser'
],
message: {
message: 'Validation failed',
fields: {
newEmail: 'The new email is not a valid email address.'
}
},
},
{
statusCode: 422,
error: 'Unprocessable Entity'
path: [
'updatePost'
],
message: {
message: 'Validation failed',
fields: {
newTitle: 'The given title is too short.'
}
},
}
],
data: {
updateUser: null,
updatePost: null,
}
}
But how do I know which error belongs to which mutation? We can't assume, that the first error in the errors array belongs to the first mutation, because if updateUser succeeds, the array would simple contain one entry. Would I then have to iterate over all errors and check if the path matches my mutation name? :D
Another approach is to include the error in a dedicated response type, say UpdateUserResponse and UpdatePostResponse. This approach enables me to correctly address errors.
type UpdateUserResponse {
error: Error
user: User
}
type UpdatePostResponse {
error: Error
post: Post
}
But I have a feeling that this will bloat my schema quite a lot.
In short, yes, if you include multiple top-level mutation fields, utilize the path property on the errors to determine which mutation failed. Just be aware that if an error occurs deeper in your graph (on some child field instead of the root-level field), the path will reflect that field. That is, an execution error that occurs while resolving the title field would result in a path of updatePost.title.
Returning errors as part of the data is an equally valid option. There's other benefits to this approach to:
Errors sent like this can include additional meta data (a "code" property, information about specific input fields that may have generated the error, etc.). While this same information can be sent through the errors array, making it part of your schema means that clients will be aware of the structure of these error objects. This is particularly important for clients written in typed languages where client code is often generated from the schema.
Returning client errors this way lets you draw a clear distinction between user errors that should be made visible to the user (wrong credentials, user already exists, etc.) and something actually going wrong with either the client or server code (in which case, at best, we show some generic messaging).
Creating a "payload" object like this lets you append additional fields in the future without breaking your schema.
A third alternative is to utilize unions in a similar fashion:
type Mutation {
updateUser(id: ID!, newEmail: String!): UpdateUserPayload!
}
union UpdateUserPayload = User | Error
This enables clients to use fragments and the __typename field to distinguish between successful and failed mutations:
mutation($userId: ID!, $newEmail: String!) {
updateUser(id: $userId, newEmail: $newEmail) {
__typename
... on User {
id
email
}
... on Error {
message
code
}
}
}
You can get even create specific types for each kind of error, allowing you to omit any sort of "code" field:
union UpdateUserPayload = User | EmailExistsError | EmailInvalidError
There's no right or wrong answer here. While there are advantages to each approach, which one you take comes ultimately comes down to preference.
I'm having difficult coming up with the best possible way of storing todo list items in the backend. I was told that storing array and object in the backend was not a good idea. I'm trying to clone a google keep inspired web app.
Some context: as soon as the user submits their todo list, it will make an axios call to the backend that will iterate through an array of todo list items and save them individually to the backend.
Which inspired me with this current set up.
CREATE TABLE TODO (
ID SERIAL PRIMARY KEY,
title VARCHAR,
user_id INTEGER REFERENCES users(ID));
CREATE TABLE TODO_ITEM (
ID SERIAL PRIMARY KEY,
item VARCHAR,
complete BOOLEAN,
todo_list_id INTEGER REFERENCES TODO(id));
My frontend call to the backend looks like this
toDoArray.map(ele => {
axios.post('users/postToDoListItems', {
item: ele,
complete: false,
todo_list_id: ?
})
})
axios.post('users/postToDoList', {
title: title,
toDoList: toDoList
})
}
The TODO_ITEM table I would like to to reference my TODO table so that when it's called to the frontend and grouped with the correct table.
With my current setup, is it possible to pass the reference (TODO)ID to TODO_ITEM table?
so aaaww i think you made some little mistakes i dont know how you query on your back-end but you must notice that before making your tables you must make a connection to your db soo i think it's not back to check this
or if you did it before plz complete your info about your problem , but the right thing for making queries is this :
var mysql = require('mysql');
var connection = mysql.createConnection({
host : 'localhost',
user : 'me',
password : 'secret',
database : 'my_db'
});
connection.connect();
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
if (error) throw error;
console.log('The solution is: ', results[0].solution);
});
connection.end();
and for query from front-end you should do this :
<< fron-end >>
axios.post('users/postToDoListItems', {
item: ele,
complete: false,
todo_list_id: 1
})
<< back-end >>
route : postToDoListItems
connection.query(`SET complete = ${req.body.complete} FROM todo WHERE id =${req.body.id}`, function (error, results, fields) {
if (error) throw error;
res.json({results,fields})
});
From graphql yoga, inside of my resolvers I check before resolver call, if this resolver is protected or not.
If resolver is protected, and user is not signed in I can throw an error like this:
return new Error('Token is missing');
This stops execution of the request and returns correct shape of message, with an error field.
{
"data": null,
"errors": [
{
"message": "Token is missing",
"locations": [
{
"line": 3,
"column": 3
}
],
"path": [
"users"
]
}
]
}
The response has status 200 though, which is not correct. I'd like to be able to choose my own status, like 403 for example.
Here is my current implementation of resolvers:
const withAuth = authed => (_, args, context, ...rest) => {
if (!context.token) {
return new Error('Token is missing');
}
let result = null;
try {
result = jwt.verify(context.token, process.env.HASH);
} catch (__) {
return new Error('Incorrect token');
}
const { username, email } = result;
if (!username || !email) {
return new Error('Incorrect token');
}
return authed(_, args, { ...context, user: { username, email } }, ...rest);
};
const resolvers = {
Query: {
users: withAuth(resolver(User)), //get users from db
}
I would add a before request middleware in express, but there is no way of telling, which query is being called, as all calls are done to the same endpoint.
Any input will be appreciated!
As per graphql specification, endpoint should always return status 200:
http://facebook.github.io/graphql/October2016/#sec-Errors
The errors entry in the response is a non‐empty list of errors, where
each error is a map.
If no errors were encountered during the requested operation, the
errors entry should not be present in the result.
Every error must contain an entry with the key message with a string
description of the error intended for the developer as a guide to
understand and correct the error.
If an error can be associated to a particular point in the requested
GraphQL document, it should contain an entry with the key locations
with a list of locations, where each location is a map with the keys
line and column, both positive numbers starting from 1 which describe
the beginning of an associated syntax element.
GraphQL servers may provide additional entries to error as they choose
to produce more helpful or machine‐readable errors, however future
versions of the spec may describe additional entries to errors.
If the data entry in the response is null or not present, the errors
entry in the response must not be empty. It must contain at least one
error. The errors it contains should indicate why no data was able to
be returned.
If the data entry in the response is not null, the errors entry in the
response may contain any errors that occurred during execution. If
errors occurred during execution, it should contain those errors.
IBM MobileFirst 6.3.0 in Windows
I have few warning and exceptions when I work with Json Store.
Can that be ignored or any fix is available, Since I am using latest MobileFirst studio installed from Eclipse Market place
JSON STORE Code:
var jsonStoreObject = { };
jsonStoreObject.collectionName = 'people';
jsonStoreObject.collections = {
people : {
searchFields : {name: 'string', age: 'integer'}
}
};
jsonStoreObject.options = {
username : "Hello",
password : "123"
};
function openJSON(){
WL.JSONStore.init(jsonStoreObject.collections, jsonStoreObject.options)
.then(function(data) {
WL.Logger.info("After Init::"+ JSON.stringify(data));
return WL.JSONStore.get(jsonStoreObject.collectionName).findAll();
})
.then(function(findAllResult) {
WL.Logger.info("findAllResult::"+ JSON.stringify(findAllResult));
if (findAllResult.length == 0) {
var data = [{name: 'carlos', age: 10}];
return WL.JSONStore.get(jsonStoreObject.collectionName).add(data);
}
})
.fail(function (errorObject) {
console.log("Json Failure:: " + WL.JSONStore.getErrorMessage(errorObject));
});
}
Exceptions/Warnings:
03-18 05:23:17.332: I/dalvikvm(1669): Could not find method
org.json.JSONException., referenced from method
com.worklight.androidgap.jsonstore.security.DPKBean.
03-18 05:23:17.332: W/dalvikvm(1669): VFY: unable to resolve direct method
34098: Lorg/json/JSONException;. (Ljava/lang/Throwable;)V
Also, when I call the openJSON() for the first time I used to get following log like database already exists.
03-18 06:50:05.518: D/JSONSTORE(1053): JSONStoreLogger.logDebug in
JSONStoreLogger.java:174 :: provisioning database "people" (already
exists: false)
The first one is just a warning, and it always shows up. It does not affect anything. The second one is just a debug message telling you if the collection you are creating was previously created or not; if it had already existed, it would just return that one, and say "already exists:true".
Neither of them affect the execution, so you don't have to worry about them.