Invalid response of GraphQL request via CORS and valid response via GraphiQL processing authentication with JWT - graphql

The problem is that I always receive a 400 response code without any payload.
Even something goes wrong graphql passes with code 200 and payload with error block. That fact, that GraphiQl works fine, tells me that settings and schema are correct. So... I'm stuck. Maybe, any ideas, where to look?
I don't think it fails because of cors itself. My app worked well under DRF. I decided to try new for me technology and overwrite app using GQL.
My Origin: http://127.0.0.1:8080
Here my Apollo Client:
const cache = new InMemoryCache();
const link = new HttpLink({
uri: "http://127.0.0.1:8000/graphql/",
credentials: "include", // cookies enabled
headers: {
"X-Csrftoken": getTokenCsrf(),
"Content-Type": "application/json"
},
fetchOptions: {
mode: "cors"
}
});
const client = new ApolloClient({
cache,
link
});
There is my request (values of vars coming from the form via the state):
const AUTH_QUERY = gql`
mutation TokenAuth($username: String!, $password: String!) {
tokenAuth(username: $username, password: $password) {
token
}
}
`;
I used react-apollo-hook for performing query:
const [sendCreds, loading, error] = useMutation(AUTH_QUERY);
const handleSubmit = e => {
sendCreds({
variables: { username: state.username, password: state.password }
});
};
my Schema (according docs):
class Mutation(graphene.ObjectType):
token_auth = graphql_jwt.ObtainJSONWebToken.Field()
verify_token = graphql_jwt.Verify.Field()
refresh_token = graphql_jwt.Refresh.Field()
schema = graphene.Schema(query=Query, mutation=Mutation)
Processing this query from GraphiQL gives me a valid response.
GraphiQL is run on http://127.0.0.1:8000/graphql on another tab of browser.
Query:
mutation TokenAuth($username: String!, $password: String!) {
tokenAuth(username: $username, password: $password) {
token
}}
Variables:
{"username": "qwerty", "password": "qwerty"}
Response:
{
"data": {
"tokenAuth": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6InF3ZXJ0eSIsImV4cCI6MTU2NjMwMTkwNiwib3JpZ0lhdCI6MTU2NjMwMTYwNn0.NzgecEfFcnsrudcgrlZyBCC1rutoVJFciUI-ugFq9Fg"
}}}

So, the problem was solved. Don't forget, that when you press the button without explicitly defined type, the type "submit" is used.
<form >
<div className="input-field">
<input type="text" id="username" />
<input type="password" id="password" />
<button
type="button" // that string solved my problem.
onClick={handleSubmit}
>
{msg}
</button>
</div>
</form>
When you press the submit-typed button, render is called and response tries to dispatch content to the unmounted component. But if your button has type "button", request works fine. I hope my torment will save someone his time.

Related

Problem sending file as FormData to GraphQL HotChocolate server using fetch-api

I am trying to send form data to a graphql server using fetch-api
<div>
<!-- HTML5 Input Form Elements -->
<h4>GraphQL API Upload Test</h4>
<input id="fileUpload" type="file" name="fileUpload" />
<input id="fileDetail" type="text" name="fileDetail" />
<button id="upload-button" onclick="uploadFile()"> Upload </button>
<!-- Ajax JavaScript File Upload Logic -->
<script>
var queryTest = `mutation Header($input: Upload!) {
testUploadMutation( file: $input) {
response
}
}`;
async function uploadFile() {
let img = {};
img.file = fileUpload.files[0];
let formData = new FormData();
formData.append("operations",JSON.stringify( { query: queryTest}));
formData.append('map', { "0": ["variables.input"] });
formData.append('0', img.file);
await fetch("/graphql/", {
method: "POST",
body: formData
}).then(response => response.json()).then(data => console.log(data));
}
</script>
</div>
but I keep getting "Invalid JSON in the map multipart field; Expected type of Dictionary<string, string[]> from the server even though the mutation works fine on Banana Cake Pop. I have been using fetch-api to run all other queries and mutation successfully.
This is only code using formData with fetch-api for file upload and its not working . Anybody know what's going on?
Mutaion on Banana Cake Pop
mutation Header($input: Upload!) {
testUploadMutation( file: $input) {
response
}
}
#variables sent using the Banana Cake Pop Variables feature
{
"input": "somefile.jpg"
}
I have also tried sending formData.append('0', img)
instead of formData.append('0', img.file) but the same error

How to solve cy.type() failed because it targeted a disabled element

I am accessing my Gmail account by command loginByGoogleApi under commands.js, then getting the requested email body and pulling the required data from the body, and saving it in a const variable code typing the pulled email data (code) in my testFile.cy.js.
I am able to login after this but cypress throwing me an error cy.type() failed because it targeted a disabled element.
commands.js
/// <reference types="cypress"
import { parseString } from "xml2js";
Cypress.Commands.add('loginByGoogleApi', () => {
cy.request({
method: 'POST',
url: 'https://www.googleapis.com/oauth2/v4/token',
body: {
grant_type: 'refresh_token',
client_id: Cypress.env('googleClientId'),
client_secret: Cypress.env('googleClientSecret'),
refresh_token: Cypress.env('googleRefreshToken'),
},
}).then(({ body }) => {
const { access_token, id_token } = body
cy.log('Opening emails including code to verify')
cy.request({
method: 'GET',
url: 'https://mail.google.com/mail/feed/atom/verifyCode',
headers: { Authorization: Bearer ${access_token} },
}).then(({ body }) => {
parseString(body, function (err, results) {
let data = JSON.stringify(results)
let codeTitle = JSON.parse(data).feed.entry[0].title[0];
let code = codeTitle.replace('Chaine confirmation code: ','');
cy.log(code)
});
});
})
})
testFile.cy.js
const { Code } = require("#chaine/keychaine");
describe('Open login page', () => {
it('Enter your email to login', () => {
cy.visit('https://chaineapp.com/staging/login%27)
cy.get('#field-1').click().type('paras#loadtap.com');
cy.get('[class*="chakra-button css-yg51i0"]').click();
cy.get('#pin-input-2-0').type(<need to put code here>);
})
it('get code', () => {
cy.loginByGoogleApi()
})
})
CypressError
cy.type() failed because it targeted a disabled element.
The element typed into was:
<input aria-label="Please enter your pin code" inputmode="numeric" type="tel" id="pin-input-2-5" autocomplete="one-time-code" placeholder="" class="chakra-pin-input css-jyb0wy" value="1" data-index="5" disabled="">
Ensure the element does not have an attribute named disabled before typing into it.
image of error
You can add force: true with type to disable actionability checks -
cy.get('#pin-input-2-0').type('text to type', {force: true});
"{"post
_0":["blob"],"q":["[{"app_id":"936619743392459","posts":"0","user":"17841452298923592","webSessionId":":xsehw9:s7q6v3","send_method":"beacon","compression":"snappy","snappy_ms":8}]"],"ts":["1656260390276"]}",
The digits are entered into separate inputs and the cursor is moved right after each character, but the Cypress .type() command is entering the digits faster than the cursor can move.
Add a delay to the type command.
cy.get('#pin-input-2-0')
.type(code, {delay:100})

GraphQLError: Syntax Error: Cannot parse the unexpected character "."

I am currently using Apollo-server as my GraphQL server of choice and anytime I try to run tests I get the error indicated in the title. However, my server implementation works as expected.
import 'cross-fetch/polyfill';
import ApolloClient, { gql } from 'apollo-boost';
const client = new ApolloClient({
uri: 'http://localhost:4000/',
});
const USER = {
invalidPassWord : {
name: 'Gbolahan Olagunju',
password: 'dafe',
email: 'gbols#example.com'
},
validCredentials: {
name: 'Gbolahan Olagunju',
password: 'dafeMania',
email: 'gbols#example.com'
},
usedEmail: {
name: 'Gbolahan Olagunju',
password: 'dafeMania',
email: 'gbols#example.com'
}
};
describe('Tests the createUser Mutation', () => {
test('should not signup a user with a password less than 8 characters', () => {
const createUser = gql`
mutation {
createUser(data: USER.invalidPassWord){
token
user {
name
password
email
id
}
}
}
`
client.mutate({
mutation: createUser
}).then(res => console.log(res));
})
})
There is a problem with the document used in your test. USER.invalidPassWord is not valid GraphQL syntax. Presumably you meant to use a template literal there to reference the USER variable defined earlier.
Doing the GrapQL tutorial at
https://www.howtographql.com/react-apollo/1-getting-started/
gives the same error.
I have razed the "same" issue at their site, though is the problem another in my case.
https://github.com/howtographql/howtographql/issues/1047

broadcast to others and dont broadcast to current user are not working

In my TaskList.vue I have the code below:
<template>
<div>
<ul>
<li v-for="task in tasks" v-text="task"></li>
</ul>
<input type="text" v-model="newTask" #blur="addTask">
</div>
</template>
<script>
export default {
data(){
return{
tasks: [],
newTask: ''
}
},
created(){
axios.get('tasks')
.then(
response => (this.tasks = response.data)
);
Echo.channel('task').listen('TaskCreated', (data) => {
this.tasks.push(data.task.body);
});
},
methods:{
addTask(){
axios.post('tasks', { body: this.newTask })
this.tasks.push(this.newTask);
this.newTask = '';
}
}
}
</script>
When I hit the axios.post('tasks') end point, I got duplicate result in my current tab that i input the value and the another tab got only 1 value which is correct.
To avoid this, I tried to use
broadcast(new TaskCreated($task))->toOthers();
OR
I put $this->dontBroadcastToCurrentUser() in the construct of my TaskCreated.php
However, both methods are not working. Any idea why?
The image below is from network tab of mine. One of it is pending, is that what caused the problem?
https://ibb.co/jpnsnx (sorry I couldn't post image as it needs more reputation)
I solved this issue on my Laravel Spark project by manually sending the X-Socket-Id with the axios post.
The documentation says the header is added automatically if you're using vue and axios, but for me (because of spark?) it was not.
Below is an example to show how I manually added the X-Socket-Id header to an axios post using the active socketId from Laravel Echo:
axios({
method: 'post',
url: '/api/post/' + this.post.id + '/comment',
data: {
body: this.body
},
headers: {
"X-Socket-Id": Echo.socketId(),
}
})
Laravel looks for the header X-Socket-ID when using $this->dontBroadcastToCurrentUser(); Through this ID, Laravel identifies which user (current user) to exclude from the event.
You can add an interceptor for requests in which you can add the id of your socket instance to the headers of each of your requests:
/**
* Register an Axios HTTP interceptor to add the X-Socket-ID header.
*/
Axios.interceptors.request.use((config) => {
config.headers['X-Socket-ID'] = window.Echo.socketId() // Echo instance
// the function socketId () returns the id of the socket connection
return config
})
window.axios.defaults.headers.common['X-Socket-Id'] = window.Echo.socketId();
this one work for me..!!

Logged in state doesn't reactively update in React, Apollo Client 2, Graphcool

Im using React, Apollo Client 2 and Graphcool. Ive implemented a login form. On the login page either a login form or a logout button are shown depending on weather the client is logged in.
My code works but does not update reactively. After a user logs in or out nothing changes until they refresh the page. How can I make my code reactive?
import React from 'react';
import { graphql, compose } from 'react-apollo';
import gql from 'graphql-tag';
class Login extends React.Component {
constructor(props) {
super(props);
this._confirm = this._confirm.bind(this);
}
_confirm = async e => {
e.preventDefault();
const result = await this.props.LoginMutation({
variables: {
email: '5#gmail.com',
password: 'password',
},
});
const token = result.data.authenticateUser.token;
this._saveUserData(token);
};
_saveUserData = token => {
localStorage.setItem('auth-token', token);
};
render() {
return (
<div>
{this.props.LoginQuery.user ? (
<button onClick={() => localStorage.removeItem('auth-token')}>
Logout
</button>
) : (
<form onSubmit={this._confirm}>
<input type="email" id="email" />
<input type="password" id="password" />
<button type="submit">Login</button>
</form>
)}
</div>
);
}
}
const LoginMutation = gql`
mutation authenticateUser($email: String!, $password: String!) {
authenticateUser(email: $email, password: $password) {
token
}
}
`;
const LoginQuery = gql`
query AppQuery {
user {
id
}
}
`;
const LoginContainer = compose(
graphql(LoginMutation, { name: 'LoginMutation' }),
graphql(LoginQuery, { name: 'LoginQuery' }),
)(Login);
export default LoginContainer;
Anything that concerns UI, doesn't necessarily need to be protected. Therefore you can easily just use state or a data store (such as redux, mobx etc.) to triggers updates to the UI.
If you want reactive updates to your UI based off of your mutations with GraphQL. I would honestly recommend implementing Subscriptions which will give you the sort of reactive data flow that you're looking for.
Subscriptions ~ Apollo Client

Resources