Amplify AppSync subscription on update of a single record - react-native

My request table is:
type RequestService
#model
#auth(
rules: [
{ allow: groups, groups: ["Consumers"], operations: [read, create, update] }
{ allow: groups, groups: ["Providers"], operations: [read, update] }
]
) {
id: ID!
consumerID: ID!
providerID: ID
request_detail: String
}
I have a subscription on the updateRequestService mutation:
type Subscription {
onUpdateRequestServiceByID(id: ID!): RequestService
#aws_subscribe(mutations: ["updateRequestService"])
}
I have a page that lists all the records for the RequestService, upon clicking on one record, it opens a details page for the single record.
On the details page, I've called the subscription to listen to any updates done on the RequestService.
const [request, setRequest] = React.useState(route.params.requestID)
React.useEffect(() => {
(async () => {
const abortController = new AbortController();
const subscribe = await API.graphql(graphqlOperation(onUpdateRequestServiceByID, { id: request.id })).subscribe(
{
next: (data) => {
console.log("data", data.value.data.onUpdateRequestServiceByID);
setRequest(data.value.data.onUpdateRequestServiceByID);
},
error: (err) => console.log("err", err),
}
);
return () => {
subscribe.unsubscribe();
abortController.abort();
};
})();
}, []);
Unfortunately, I don't get any console.log's back, I get no response. I've also tried this on the AppSync Queries interface, but doesn't listen to updates on a record.
Any assistance on why I'm not getting the response?

Related

How to log HTTP response header value for all cypress requests?

One of my ideas would be to overwrite the request command, but I don't know how to handle the response object.
A snippet I already have:
Cypress.Commands.overwrite(
'request',
(
originalFn: Cypress.CommandOriginalFn<'request'>,
options: Partial<Cypress.RequestOptions>
): void | Cypress.Chainable<Cypress.Response<unknown>> => {
return originalFn(options);
}
);
My other idea would be to intercept all requests, but there are already interceptors added and you can not have two for one request.
beforeEach(() => {
cy.intercept(
{
url: '*/**',
},
req => {
// tried with 'after:response' too
req.on('response', res => {
cy.log(`${res.headers['x-custom-header']}`);
});
}
);
});
Is there any other way to log a custom header value for all request?
My final working solution was to add this code to /support/index.ts
beforeEach(() => {
cy.intercept({ url: '*', middleware: true }, req => {
req.on('after:response', (res => {
const customHeaderKey = 'x-custom-header';
const customHeaderValue = res.headers[customHeaderKey];
if (customHeaderValue) {
const message = JSON.stringify({ [customHeaderKey]: customHeaderValue });
Cypress.log({ message }).finish();
}
}));
});
});

Query result doesn't give the list of items, but just an empty array [ ] in aws-amplify

I try to make a query to see the list of users. My custom lambda function (which I attached as policy) is as follows:
const aws = require('aws-sdk');
const ddb = new aws.DynamoDB();
exports.handler = async (event, context) => {
if (!event.request.userAttributes.sub) {
console.log("Error: No user was written to DynamoDB")
context.done(null, event);
return;
}
// Save the user to DynamoDB
const date = new Date();
const params = {
Item: {
'id': { S: event.request.userAttributes.sub },
'__typename': { S: 'User' },
'username': { S: event.userName },
'email': { S: event.request.userAttributes.email },
'createdAt': { S: date.toISOString() },
'updatedAt': { S: date.toISOString() },
},
TableName: process.env.USERTABLE,
}
try {
await ddb.putItem(params).promise();
console.log("Success");
} catch (e) {
console.log("Error", e);
}
context.done(null, event);
}
And the schema model is as follows:
type User #model
#auth(rules: [
{ allow: public, operations: [read]}
{ allow: owner }
])
{
id: ID!
username: String!
email: String!
}
Although there is one user in the dynamoDb, when I make a query by:
query listUsers {
listUsers {
items {
email
id
username
}
}
}
the result is as follows:
{
"data": {
"listUsers": {
"items": []
}
}
}
As can be seen, the array of "items" is empty, the items are not shown, when I look at the console dynamoDb table, I see user items with id, username and email values. But it should give the results, where do I make mistake? Meanwhile I am new on aws-amplify.

Graphql, node.js and sql,Cannot return null for non-nullable field

I want to return data coming from db to the api. The data is being logged but not showing on the graphql api.
const express = require('express');
const bodyParser = require('body-parser');
const graphqlHttp = require('express-graphql');
const { buildSchema } = require('graphql');
var mysql = require('mysql');
const app = express();
//start mysql connection
var connection = mysql.createConnection({
host : 'localhost', //mysql database host name
user : 'root', //mysql database user name
password : '', //mysql database password
database : 'test' //mysql database name
});
connection.connect(function(err) {
if (err) throw err
})
//end mysql connection
app.use(bodyParser.json());
app.use(
'/graphql',
graphqlHttp({
schema: buildSchema(`
type users {
id: String!
username: String!
password: String!
role: String!
name: String!
photo: String!
}
type RootQuery {
getUsers: [users!]!
}
type RootMutation {
createUsers(name: String): String
}
schema {
query: RootQuery
mutation: RootMutation
}
`),
rootValue: {
getUsers: () => {
connection.query('select * from users', function (error, results, fields) {
if (error) throw error;
console.log(JSON.stringify(results))
return JSON.stringify(results) ;
});
},
createUsers: (args) => {
const eventName = args.name;
return eventName;
}
},
graphiql: true
})
);
app.listen(3000);
RESULT:
query
{
getUsers {
id
}
}
OUTPUT:
{
"errors": [
{
"message": "Cannot return null for non-nullable field RootQuery.getUsers.",
"locations": [
{
"line": 3,
"column": 3
}
],
"path": [
"getUsers"
]
}
],
"data": null
}
This is your resolver:
getUsers: () => {
connection.query('select * from users', function (error, results, fields) {
if (error) throw error;
//users = results;
console.log(JSON.stringify(results));
return JSON.stringify(results) ;
});
},
A GraphQL resolver must return either a value or a Promise that will resolve to a value. However, here, you're not returning either. Keep in mind that callbacks are invoked asynchronously, so returning a value inside a callback does nothing (in most cases).
You really should use something like promise-mysql instead of mysql, but you can still wrap a callback with a Promise and return that Promise. Something like this should work:
getUsers: () => {
// Note, we have to return the Promise here
return new Promise((resolve, reject) => {
connection.query('select * from users', (error, results, fields) => {
if (error) {
reject(error)
} else {
// Don't stringify
resolve(results)
}
})
})
},
getUsers: () => {
/* 👉 return 👈 */ connection.query('select * from users', function (error, results, fields) {
if (error) throw error;
//users = results;
console.log(JSON.stringify(results));
return JSON.stringify(results) ;
});
},
Your getUsers function doesn't return anything. I believe you're missing the return statement I've highlighted in the above comment.
Incidentally, it's best practices in GraphQL to ensure all the root fields (such as getUsers) are nullable, have a read of this article to find out why.
delete (!) from field definition in schema

Vuex - Normalizr doesn't work as expected

I am creating a simple chat app. I have three entities: rooms, messages and users.
I have a fake API that returns a response like this:
[{
id: 1,
name: 'room1',
avatar: 'some img url',
messages: [
{
id: 1,
text: 'some text',
user: {
id: 1,
username: 'Peter Peterson',
avatar: 'some img url'
}
]
}]
And my action looks like this:
getAllRooms({ commit }) {
commit(GET_ALL_ROOMS_REQUEST);
return FakeApi.getAllRooms()
.then(
rooms => {
const { entities } = normalize(rooms, room);
console.log(entities);
commit(GET_ALL_ROOMS_SUCCESS, {
rooms: entities.rooms, byId: rooms.map(room => room.id)
});
commit(GET_ALL_MESSAGES_SUCCESS, { messages: entities.messages });
commit(GET_ALL_USERS_SUCCESS, { users: entities.users });
},
err => commit(GET_ALL_ROOMS_ERROR)
)
}
And my mutations look like this:
[GET_ALL_ROOMS_REQUEST](state) {
state.loading = true;
},
[GET_ALL_ROOMS_SUCCESS](state, payload) {
state.rooms = payload.rooms;
state.byId = payload.byId;
state.loading = false;
},
[GET_ALL_ROOMS_ERROR]() {
state.error = true;
state.loading = false;
}
And my component calls the action like this:
{
mounted() {
this.getAllRooms();
}
}
These are my schema definitions:
const user = new schema.Entity('users');
const message = new schema.Entity('messages', {
user: user
});
const room = new schema.Entity('rooms', {
messages: [message]
})
when i check the response in then method after FakeApi.getAllRooms() every object is wrapped in some weird Observer, and I pass it like that to normalize and normalize returns some weird response.
What am I doing wrong?
The problem wasn't with vuejs, it was with the way I made the normalizr schemas. Because my response is an array at the root I should have had a new rooms array schema, like so:
const user = new schema.Entity('users');
const message = new schema.Entity('messages', {
user: user
});
const room = new schema.Entity('rooms', {
messages: [message]
});
const roomsSchema = [room];
And then use it like this: normalize(rooms, roomsSchema)

Unable to set basic auth security rules to FIRESTORE

Im trying to set rules to Firestore allowing all user to read and write around if they're signed in.
I already have my Authentication working with Firebase, using email and password.
But the simplest auth rule I write, it just throw me an error.
Im trying to make Firestore work with this rule:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null;
}
}
}
But when I try to write to Firestore I got this:
If I try the Function Helpers Approach:
service cloud.firestore {
//Function
function isSignedIn() {
return request.auth.uid != null;
//Also tried with "request.auth != null"
}
//Rules
match /databases/{database}/documents {
match /{document=**} {
allow read: if isSignedIn();
allow write: if isSignedIn();
//Also tried with "allow read, write: if isSignedIn();"
}
}
}
It also throw me the same error.
I also tried matching custom paths, like match /Restaurants/{RestaurantsId} ... but also didn’t work…
But if I remove everything and I use the following default rule:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
it does work…
I’ve followed Firestore Documentation, AngularFirebase Video Tutorial, looked at github and here to similar cases and I still cant make it work. I see everybody that has tried this got this working perfectly, but it does not with me :S.
––––UPDATE 1––––
Here is how Im calling the set method of Firestore:
When I press a “Save Button” I call this helper function:
saveMealHandler() {
const { mealImage, mealCategory, mealName, mealIngredients, mealPrice, mealOptions, mealExtras, user } = this.props;
const id = this.props.completeMenu.length;
const { navigation } = this.props;
this.props.saveMeal({
key: id,
name: mealName,
avatar: mealImage,
ingredients: mealIngredients,
price: mealPrice,
category: mealCategory,
options: mealOptions,
extras: mealExtras
}, user);
this.props.cleanAllInputs();
}
and this helper call’s the following action creator which writes on Firestore:
export const saveMeal = (newMeal, user) => {
const db = firebase.firestore();
const docRef = db.collection('Resto').doc(user);
return dispatch => {
docRef.set({
isWorking: 'JALAPEÑO!'
})
.then(() => {
console.log('Document successfully written!');
})
.catch((error) => {
console.error('Error writing document: ', error);
});
dispatch({ type: SAVE_NEW_MEAL_TO_MENU, payload: newMeal });
};
};
––––UPDATE 1––––
––––UPDATE 2––––
This is the function which capture the user and password and calls the action creator:
onButtonPress() {
const { email, password } = this.props;
console.log(email, password);
this.props.loginUser({ email, password });
}
This is the action creator im using for register and login in an user
export const loginUser = ({ email, password }) => {
return (dispatch) => {
dispatch({ type: LOGIN_USER_START });
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => userLoginSuccess(dispatch, user))
.catch(() => {
firebase.auth().createUserWithEmailAndPassword(email, password)
.then(user => userLoginSuccess(dispatch, user))
.catch(() => userLoginFail(dispatch));
});
};
};
//Helpers
const userLoginSuccess = (dispatch, user) => {
dispatch({ type: LOGIN_USER_SUCCESS, payload: user.uid });
};
const userLoginFail = (dispatch) => {
dispatch({ type: LOGIN_USER_FAIL });
};
And this is how I know this functions are working:
––––UPDATE 2––––
With all my attempts I think may be I missed to install something without knowing in or there is something wrong when I add the condition. But It this moment I just prefer to ask.
I also recorded a video so you can see the issue, here it is:
https://youtu.be/9fmWk7-HjZ4
Thanks to everyone.
i came across same problem
import all firebase cdn below
https://www.gstatic.com/firebasejs/6.4.0/firebase-app.js
https://www.gstatic.com/firebasejs/6.4.0/firebase-auth.js
https://www.gstatic.com/firebasejs/6.4.0/firebase-firestore.js