Unhandled Rejection (SyntaxError): Unexpected end of JSON input - reactjs

I have a login form (Username and Password) written in a React JS environment; the form consumes a REST API that contains the user credentials. I'm using the Fetch method to consume the API, but it errors out. I need to access the service via POST, but when I check (via chrome console - Network tab ) how my application is accessing the service, it states that the request method used is GET. How do I modify my code to access the form using post? Here is my code snippet I'm using to consume the web APT:
class Login extends Component {
//constructor
constructor() {
super();
this.state={
data: [],
}
}
//componet did mount method
componentDidMount(){
return fetch('http://myjson.com/file')
.then((response)=>response.json())
.then((responseJson)=>
{
this.setState({
data:responseJson.token
})
console.log(this.state.data)
})
}
I researched using the request.method but I'm uncertain how to implement it into the code. Could I get some help with this please? ...thanks in advance

fetch('http://myjson.com/users/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: 'userName',
password: 'pwd',
})
})
Here is fetch docs
Edit
componentDidMount(){
return fetch('http://myjson.com/users/', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: 'userName',
password: 'pwd',
})
})
.then((response)=>response.json())
.then((responseJson)=>
{
this.setState({
data:responseJson.token
})
console.log(this.state.data)
})
}

Related

React/Rails Stack with Devise Gem and ActiveStorage - How to Add Profile Picture?

For my project, I'm trying to add a profile picture, sent from a React frontend to a Rails API backend by leveraging ActiveStorage. I'm already using the devise and devise-jwt gems for authentication.
I'm having trouble understanding how to customize the devise user create action, user Model, and user_controller to accept a profile picture. I can set up the ActiveStorage migrations and run them fine.
The other main issue is how to customize my POST request from my React frontend. The guides linked above (and from my other searches) indicate that I need to create a new FormData object and should not specify a 'Content-Type' header since the FormDataAPI will handle everything so we post this in the body of the request like this:
`
fetch('http://localhost:3000/posts', {
method: 'POST',
body: formData
})
`
However, the way I have it set up in my frontend React code is formatted like this so that the devise gem on my Rails API backend will understand where to get what data to create a user:
`
fetch("http://localhost:3000/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: {
username: username,
email: email,
password: password,
}
})
`
Where the body is stringified with the JSON Object:
`
{
user: {
username: username,
email: email,
password: password,
}
}
`
I'm having trouble reconciling this with the devise gem in my Rails API backend and haven't found a way to integrate this so I need a way to customize the create action in the devise registration controller to include a profile picture association in ActiveStorage.
So far my Rails controllers looks like this:
`
class Users::RegistrationsController < Devise::RegistrationsController
respond_to :json
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found_response
rescue_from ActiveRecord::RecordInvalid, with: :render_unprocessable_entity_response
rescue_from JWT::ExpiredSignature, with: :expired_token_response
private
def respond_with(resource, _opts = {})
if resource.persisted?
render json: {
status: {code: 200, message: 'Signed up sucessfully.'},
# data: UserSerializer.new(resource).serializable_hash[:data][:attributes]
data: UserSerializer.new(resource)
}
else
render json: {
status: {message: "User couldn't be created successfully. #{resource.errors.full_messages.to_sentence}"}
}, status: :unprocessable_entity
end
end
end
`
And my routes.rb for users looks like this:
`
devise_for :users, path: '', path_names: {
sign_in: 'login',
sign_out: 'logout',
registration: 'signup'
},
controllers: {
sessions: 'users/sessions',
registrations: 'users/registrations'
}
`
I've tried reformatting my frontend fetch request like this:
`
async function exampleSubmit(e) {
e.preventDefault();
setLoading(true);
const form = document.getElementById('sign-up-form');
const formData = new FormData(form);
const userObj = {
username: formData.get('username'),
email: formData.get('email'),
password: formData.get('password'),
};
let photoInput = document.getElementById('profile-photo-input');
if (photoInput.files[0]) {
const uploadedPicture = photoInput.files[0];
userObj['profilePicture'] = uploadedPicture;
}
await fetch("http://localhost:3000/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: userObj
}),
})
.then(res => res.json())
.then((data) => {
console.log(data);
});
}
`
I'm wondering if this will work as well:
`
async function exampleSubmit(e) {
e.preventDefault();
setLoading(true);
const form = document.getElementById('sign-up-form');
const formData = new FormData(form);
let photoInput = document.getElementById('profile-photo-input');
if (photoInput.files[0]) {
const uploadedPicture = photoInput.files[0];
formData.append('profilePicture', uploadedPicture);
}
await fetch("http://localhost:3000/signup", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user: formData
}),
})
.then(res => res.json())
.then((data) => {
console.log(data);
});
}
`
Or if this will throw an error in the backend if Rails cannot recognize the formData in their params when receiving the POST request.
As for the Rails API Backend, I need some help in understanding how to customize the user with strong params to incl an ActiveStorage association + a way to give someone a default profile picture.
Thanks so much!

Cant Save Post Request Body Data

I am having trouble saving the data from a fetch post request using Node.js and React.js. I am calling the fetch request from a function inside a React component class. I want to query some userid from my database then save it to one of the React component instance variables ie "this.userid" however, whenever I assign the value to one of the empty variables I check it outside of the ".then" statements you can see it was never assigned.
Does anyone know of a run around or the proper way to perform the fetch request? I am creating a simple login post request and want to save the userid once its returned from the API.
class LandingPage extends React.Component {
constructor(props) {
super(props)
this.data = data
}
login(e){
var that = this;
function log(id){
that.userid = id
}
fetch("/login", {
method: "POST",
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8'
},
body: JSON.stringify(this.data)
}).then(response => {
return response.json();
})
.then(json =>log(json.userid))
/both show undefined
console.log(that.userid, this.userid)
}
You are checking the data outside of the then scope. It doesn't exist there, so you will have to call setState with the retrieved data inside the .then().
change
.then(json =>log(json.userid))
to
.then(json => {
that.setState({userid: json.userid})
})
then, after the component updated, the state with userid is available
Update: alternatively, you can use async await and build it like this:
import React from 'react';
class MyComponent extends React.Component {
state = {
userId: null
}
useFetch = async e => {
const raw = await fetch("/login", {
method: "POST",
headers: {
'Accept': 'application/json, application/xml, text/plain, text/html, *.*',
'Content-Type': 'application/json'
},
body: JSON.stringify(this.data)
});
const json = await raw.json();
this.setState({
userId:json
}, () => console.log(this.state))
}
render() {
if (this.state.userId === null)
this.useFetch();
return (
<div>Loading some data</div>
)
}
}
export default MyComponent;
tested and working component.

Receive JSON content of Fetch API Post call

I am new to React and I have a chat UI in which I am trying to test an API call from a service.
Please assume that the call itself have the correct parameters, and even if not I want to see the error JSON response and I am just getting a blank message in the chat as a response to the user message.
The call working through Postman app in chrome but when trying to assign the call result to var in react it doesn't present the JSON response value when trying to post the message through the UI chat.
This is the function, the user message transfered to this function and then an answer should appear right after via the fetched API request:
submitMessage(e) {
e.preventDefault();
var s = fetch('https://***', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': '****',
},
body: JSON.stringify({ inputText: 'hi' })
});
this.setState({
chats: this.state.chats.concat([
{
username: "newUser",
content: <p>{ReactDOM.findDOMNode(this.refs.msg).value}</p>
},
{
username: "responsePlace",
content: s
}
])
});
}
fetch is a javascript Promise therefore it needs to be resolved using then
fetch(...)
.then(response => response.json()) // resolves json content of the response
.then(data => console.log(data)) // your actual data as a javascript object
.catch(ex => console.log(ex)) // exception handler in case anything goes wrong in the fetch
More on fetch api: fetch api examples
More on Promises: Promises

Update state values from a different file in react native

I am keeping all my functions in one file, and calling those functions in activities where needed in my react native project. Now in one of my functions which has a fetch api, I am fetching data from my online server and printing the response after a successful query.
Now I want to be able to update state value with the response from the fetch method in the then.
App.js
...
import {registerUsers} from './src/utils/api.js'
export class App extends Component{
state = {
isLoggedIn:false,
isLoading:false,
isAppready:false
}
_Register = (email,password,fullName) =>{
this.setState({isLoading:true})
//calling the register user function here
registerUsers(email,password,fullName)
}
...
The api file
import React from 'react'
import { Alert } from 'react-native';
export function registerUsers(email, password, fullName) {
fetch('http://00.00.00.00/reg/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
userEmail: email,
userPassword: password,
userFullName: fullName
})
}).then((response) => response.json())
.then((responseJson) => {
//setState({ isLoggedIn: true, isLoading: false })
// Showing response message coming from server after inserting records.
Alert.alert(responseJson);
}).catch((error) => {
// this.setState({ isLoggedIn: true, isLoading: false })
console.error(error);
});
}
I would now want to update the state values thus isLoggedIn: true and isLoading:false after the fetch method has been processed. The problem now is that I can't figure it out where to update the state values since I am calling the registerUsers function from a different file.
I would be grateful if someone could share an idea as to how to figure this out. Thanks
registerUsers should return the promise. That way, you can handle the response directly inside your component:
API:
export function registerUsers(email, password, fullName) {
return fetch('http://00.00.00.00/reg/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
userEmail: email,
userPassword: password,
userFullName: fullName
})
}).then( response => response.json());
}
Component:
import {registerUsers} from './src/utils/api.js'
export class App extends Component{
state = {
isLoggedIn:false,
isLoading:false,
isAppready:false
}
_Register = (email,password,fullName) =>{
this.setState({isLoading:true})
//calling the register user function here
registerUsers(email, password, fullName)
.then( responseJson => {
this.setState({
isLoggedIn: true,
isLoading: false,
data: responseJson
});
}).catch( error => {
this.setState({ isLoggedIn: false, isLoading: false });
});
}

How to make a rest post call from ReactJS code?

I am new to ReactJS and UI and I wanted to know how to make a simple REST based POST call from ReactJS code.
If there is any example present it would be really helpful.
Straight from the React Native docs:
fetch('https://mywebsite.example/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
(This is posting JSON, but you could also do, for example, multipart-form.)
Also see docs for ReactJS AJAX FAQs if not using React Native.
React doesn't really have an opinion about how you make REST calls. Basically you can choose whatever kind of AJAX library you like for this task.
The easiest way with plain old JavaScript is probably something like this:
var request = new XMLHttpRequest();
request.open('POST', '/my/url', true);
request.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
request.send(data);
In modern browsers you can also use fetch.
If you have more components that make REST calls it might make sense to put this kind of logic in a class that can be used across the components. E.g. RESTClient.post(…)
Another recently popular packages is : axios
Install : npm install axios --save
Simple Promise based requests
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
you can install superagent
npm install superagent --save
then for make post call to server
import request from "../../node_modules/superagent/superagent";
request
.post('http://localhost/userLogin')
.set('Content-Type', 'application/x-www-form-urlencoded')
.send({ username: "username", password: "password" })
.end(function(err, res){
console.log(res.text);
});
As of 2018 and beyond, you have a more modern option which is to incorporate async/await in your ReactJS application. A promise-based HTTP client library such as axios can be used. The sample code is given below:
import axios from 'axios';
...
class Login extends Component {
constructor(props, context) {
super(props, context);
this.onLogin = this.onLogin.bind(this);
...
}
async onLogin() {
const { email, password } = this.state;
try {
const response = await axios.post('/login', { email, password });
console.log(response);
} catch (err) {
...
}
}
...
}
I think this way also a normal way. But sorry, I can't describe in English ((
submitHandler = e => {
e.preventDefault()
console.log(this.state)
fetch('http://localhost:5000/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
}
https://googlechrome.github.io/samples/fetch-api/fetch-post.html
fetch('url/questions',{
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(this.state)
}).then(response => {
console.log(response)
})
.catch(error =>{
console.log(error)
})
Here is a the list of ajax libraries comparison based on the features and support.
I prefer to use fetch for only client side development or isomorphic-fetch for using in both client side and server side development.
For more information on isomorphic-fetch vs fetch
Here is a util function modified (another post on stack) for get and post both. Make Util.js file.
let cachedData = null;
let cachedPostData = null;
const postServiceData = (url, params) => {
console.log('cache status' + cachedPostData );
if (cachedPostData === null) {
console.log('post-data: requesting data');
return fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(params)
})
.then(response => {
cachedPostData = response.json();
return cachedPostData;
});
} else {
console.log('post-data: returning cachedPostData data');
return Promise.resolve(cachedPostData);
}
}
const getServiceData = (url) => {
console.log('cache status' + cachedData );
if (cachedData === null) {
console.log('get-data: requesting data');
return fetch(url, {})
.then(response => {
cachedData = response.json();
return cachedData;
});
} else {
console.log('get-data: returning cached data');
return Promise.resolve(cachedData);
}
};
export { getServiceData, postServiceData };
Usage like below in another component
import { getServiceData, postServiceData } from './../Utils/Util';
constructor(props) {
super(props)
this.state = {
datastore : []
}
}
componentDidMount = () => {
let posturl = 'yoururl';
let getdataString = { name: "xys", date:"today"};
postServiceData(posturl, getdataString)
.then(items => {
this.setState({ datastore: items })
console.log(items);
});
}
Here is the simple method to define and call post APIs in reactjs. Install axios using command npm install axios and call post req method wherever you want, it will return array that contains 100 elements.
// Define post_req() Method in authAction.js
import axios from 'axios';
const post_req = (data) => {
return new Promise((resolve, reject) => {
const url = 'https://jsonplaceholder.typicode.com/posts'
const header = {
"Access-Control-Allow-Origin": "*",
"Content-Type: application/json"
}
axios({
method: 'post',
url: url,
data: data,
headers: header
});
.then((res)=>{resolve(res);})
.catch((err)=>{reject(err);})
})
}
// Calling post_req() Method in react component
import React, { Component } from 'react';
import { post_req } from 'path of file authAction.js'
class MyReactComponent extends Component {
constructor(props) {
super(props);
this.state = {
myList:[]
};
}
componentDidMount() {
let data = {
.......
}
this.props.post_req(data)
.then((resp)=>{this.setState({myList:resp.data})})
.catch((err)=>{console.log('here is my err',err)})
}
render() {
return (
<div>
....
</div)
}
}
export default MyReactComponent;
import React ,{useState}from 'react';
import Axios from 'axios';
export default function Formlp()
{
const url ="";
const [state, setstate] = useState({
name:"",
iduser:""
})
function handel(e){
const newdata={...state}
newdata[e.target.id]=e.target.value
setstate(newdata);
}
function submit(e)
{
e.preventDefault();
// Axios.post(url,{name:state.name,iduser:state.iduser}).then( res=>{console.log(res)});
console.log(state)
}
return (
<div onSubmit={ (e)=> submit(e)}>
<input onChange={ (e)=>handel(e) } id="name" value={state.name} placeholder="name" type="text" >
<input onChange={ (e)=>handel(e) } id="iduser" value={state.iduser} placeholder="iduser" type="text" >
<button>submit</button>
</form>
</div>
);
}
Here is a quick example for v18+ while handling form data and creating a POST request with the data.
async function handleOrderSubmit(event){
event.preventDefault()
try{
const formData= {name: event.target.name.value, email: event.target.email.value, message: event.target.name.message}
const requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(formData)
};
const response = await fetch('https://www.example.com/form', requestOptions);
const data = await response.json();
navigate("/form-response", { state: {data: data, status: true} })
}
catch(error){
navigate("/form-response", { state: {status: false} })
}
}
Note 1: Using status on '/form-response' page, you can customise what to show user. For true, you can show a different section and for false a different one.
Note 2: If the status is successful, you can access data on the next page also and customise it according to user information.
Note 3: event.preventDefault() is important to avoid page reloading.
Here is an example: https://jsfiddle.net/69z2wepo/9888/
$.ajax({
type: 'POST',
url: '/some/url',
data: data
})
.done(function(result) {
this.clearForm();
this.setState({result:result});
}.bind(this)
.fail(function(jqXhr) {
console.log('failed to register');
});
It used jquery.ajax method but you can easily replace it with AJAX based libs like axios, superagent or fetch.

Resources