ReactJS rxjs obervable dom ajax, get request treated as an option method - ajax

I am using 2 seperate libraries to make an http get in my reactjs application as follows
import { ajax } from 'rxjs/observable/dom/ajax';
import { Observable } from 'rxjs/Observable';
import * as actionType from '../types';
import types from '../types';
export default (action$, store) => {
return action$.ofType(types.getIssuers.requested).mergeMap(action => {
return ajax({
url: 'http://127.0.0.1:8181/api/v1/status',
responseType: 'json',
method: 'GET',
timeout: 2000
}).map(xhr => {
console.log("Issuer Epic")
const jsonBody = xhr.response;
return {
type: types.getIssuers.completed,
payload: jsonBody,
};
}).catch(error => {
return Observable.of({ type: actionType.LOAD_CUSTOMER_ERROR });
});
});
};
var request = require('request');
request('http://127.0.0.1:8181/api/v1/status', function (error, response, body) {
console.log('error:', error);
console.log('statusCode:', response && response.statusCode);
console.log('body:', body);
});
I can retrieve data without an issue if um using request library
I need to use rxjs/observable/dom/ajax as per the project requirement but it seems my HTTP GET request turned out to be an HTTP OPTION. Is there a fix for this ?

Related

how to set up redux with NextJs and allow dispatching of actions

Im trying to set up redux for my NextJS React App and I'm having some complications when dispatching this action through the indicated link. An error of 'Network Error' is displayed on LIST_FAIL. Any well available resources or advice would be appreciated. Thanks.
import axios from 'axios';
import {
//NOte that these are actions which will be dispatched or fired in the action y using dispatch()
LIST_REQUEST,
LIST_SUCCESS,
LIST_FAIL,
} from '../constants/customerConstants';
export const listCusts = () => async (dispatch, getState) => {
try {
//our first request to the backend to get the token
dispatch({
type:LIST_REQUEST,
});
const { data } = await axios.get('https://byronochara.tech/gassystem/api/v1/customers');
console.log(data);
const result = data.results;
// console.log('Results now an Array', result); //This is now an array to be looped in the list screen
dispatch({
type: LIST_SUCCESS,
payload: result,
});
} catch (error) {
dispatch({
type: LIST_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};

Write on session with Sapper and Svelte

I wrote a Sapper app with session management following the RealWorld example:
polka()
.use(bodyParser.json())
.use(session({
name: 'kidways-app',
secret: 'conduit',
resave: false,
saveUninitialized: true,
cookie: {
maxAge: 31536000
},
store: new FileStore({
path: 'data/sessions',
})
}))
.use(
compression({ threshold: 0 }),
sirv('static', { dev }),
pdfMiddleware,
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
)
.listen(PORT, err => {
if (err) console.log('error', err);
});
Then on my _layout.sevlte:
<script context="module">
export async function preload({ query }, session) {
console.log('preload', session)
return {
// ...
};
}
</script>
<script>
import { onMount, createEventDispatcher } from 'svelte';
import { Splash } from 'project-components';
import * as sapper from '#sapper/app';
import { user } from '../stores';
import client from '../feathers';
const { session } = sapper.stores();
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});
console.log($session)
</script>
<h1>{$session.token}</h1>
This work on client side rendering, but the token is still undefined on preload, making my SSR template rendering broken.
What did I missed?
When a page renders, session is populated according to the return value of the function you specified here:
sapper.middleware({
session: req => ({
token: req.session && req.session.token
})
})
So while the client may have an up-to-date token, it won't take effect on page reload unless you somehow persist the token to the server in such a way that the session middleware knows about it.
Typically you'd achieve this by having a server route, like routes/auth/token.js or something...
export function post(req, res) {
req.session.token = req.body.token;
res.writeHead(200, {
'Content-Type': 'application/json'
});
res.end();
}
...and posting the token from the client:
onMount(async () => {
try {
await client.reAuthenticate();
const auth = await client.get('authentication');
user.set(auth.user);
await fetch(`auth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ token })
});
// writing to the session store on the client means
// it's immediately available to the rest of the app,
// without needing to reload the page
$session.token = 'test';
} catch (e) {
} finally {
loaded = true;
}
});

Redux says to use Plain object in action.But dont know where to use plain object

I was searching for my answer in SO, but could not find any suitable one. So here i go with my questions...
In my redux action creator i am fetching API call from isomorphic-unfetch but I am getting the message Error: Actions must be plain objects. Use custom middleware for async actions each time.Though i defined dispatch in my action...
My action code is
const exchangeBuy = ({btc, usdt, id}, url) => {
return (dispatch) => {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify( { btc, usdt, id } )
}).then(
r => r.json()
).then(
r => dispatch({
type: 'EXCHANGE_BUY',
payload: r //here r return an object from mongoDB
})
)
}
}
Also the code that invokes this is
submitExchange(e){
e.preventDefault()
const btc = e.target.btcamount.value
const usdt = e.target.usdprice.value
this.props.exchangeBuy( //Here it is
{
btc: btc,
usdt: usdt,
id: this.props.users.id
},
this.props.apiurl )
}

redux saga ajax call - not working as expected

I have this redux saga code where everything works okay...until the promise, after that things start to go wrong
here's the relevant code
const firstApiRequest = ()=>{
return $.ajax({
url: myUrl,// ,
type:'POST',
headers: {
"Accept":"application/json",
"Content-Type":"application/json",
},
data:JSON.stringify(bodyData),
success:function(res){
console.log(res);
return res;
}
})
};
export function *startCheckout() {
try {
yield put(showLoading());
const data = yield call(firstApiRequest);//const data ends
yield put({type:FIRST_REQUEST_DONE,payload:data});
} catch (err) {
yield put(firstRequestFail(err));
}
}
export function *checkout() {
yield takeEvery(SEND_FIRST_REQUEST, startCheckout);
}
The problem is that after the return res in firstApiRequest , I wanted to use the data to send the FIRST_REQUEST_DONE action , but what happens is that the flow goes to FIRST_REQUEST_FAIL and shows error as true.
The problem is that the api response is coming back successfully and I am getting the data inside the error when the flow goes to FIRST_REQUEST_FAIL part of reducer and data shows up as error.
here's the code for reducer
where flow goes to
case 'FIRST_REQUEST_FAIL':
return {
loading: false,
error: true,
errorMessage: action.err,
};
instead of going to
case 'FIRST_REQUEST_DONE':
return {
id: action.id,
};
so, what's wrong with the code here? why does it show error even after a succesful response from server?
You shouldn't be defining the success in your api request.
$.ajax will return a promise on its own:
const firstApiRequest = () => (
$.ajax({
url: myUrl,// ,
type:'POST',
headers:{
"Accept":"application/json",
"Content-Type":"application/json",
},
data:JSON.stringify(bodyData),
}));
Also, why are you using jQuery for making the API requests? I'd suggest using axios or fetch
Here is an approach to handle API request using redux-saga:
First create a request helper
import 'whatwg-fetch';
function parseJSON(response) {
return response.json ? response.json() : response;
}
/**
* Checks if a network request came back fine, and throws an error if
not
*
* #param {object} response A response from a network request
*
* #return {object|undefined} Returns either the response, or throws an
* error
*/
function checkStatus(response, checkToken = true) {
if (response.status >= 200 && response.status < 300) {
return response;
}
return parseJSON(response).then(responseFormatted => {
const error = new Error(response.statusText);
error.response = response;
error.response.payload = responseFormatted;
throw error;
});
}
/**
* Requests a URL, returning a promise
*
* #param {string} url The URL we want to request
* #param {object} [options] The options we want to pass to "fetch"
*
* #return {object} The response data
*/
export default function request(url, options = {}) {
// Set headers
if (!options.headers) {
options.headers = Object.assign({
'Content-Type': 'application/json',
}, options.headers, {});
}
// Stringify body object
if (options && options.body) {
options.body = JSON.stringify(options.body);
}
return fetch(url, options)
.then(checkStatus)
.then(parseJSON)
}
In your saga
import { call, fork, put, takeLatest } from 'redux-saga/effects';
import request from 'utils/request';
import { submitSuccess, submitError } from './actions'; // path
to your actions.
import { SUBMIT } from './constants'; // The event you're listening
export function* submitData(action) {
try {
const response = yield call(request, 'your_url', { method: 'POST', body: action.body });
yield put(submitSuccess(response));
} catch(err) {
yield put(submitError(response.payload.message);
}
}
export function* defaultSaga() {
yield fork(takeLatest, SUBMIT, submitData);
}
export default defaultSaga;
Reducer
const initialState = fromJS({
submitSuccess: false,
submitReponse: '',
errorMessage: '',
});
function fooReducer(state = initialState, action) {
switch (action.type) {
case SUBMIT_SUCCESS:
return state
.update('submitSuccess', () => true)
.update('submitResponse', () => action.response);
case SUBMIT_ERROR:
return state.update('errorMessage', () => action.errorMessage);
//...
}
}
With this structure you should be able to catch your success and you error when you're making your request.

How to make Graphql run with CORS

I've read several articles about this, but none of them work for me.
https://github.com/graphql/express-graphql/issues/14
Here is my expressjs code:
app.use("/graphql", function (req, res, next) {
res.header('Access-Control-Allow-Origin', 'http://localhost:8080');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
if (req.method === 'OPTIONS') {
res.sendStatus(200);
} else {
next();
}
});
// apply graphql middleware
app.use('/graphql', graphqlHTTP({
schema: schema,
rootValue: rootResolver,
graphiql: true,
}))
If I do it this way, the pre-flight OPTIONS is successful, but the actual POST request fails.
I am using this function to make request to local graphql server.
function postFn(url, payload) {
return $.ajax({
method: 'POST',
url: url,
contentType: 'application/json',
xhrFields: {
withCredentials: true
},
data: payload
});
}
Here is the front-end code to trigger the POST request:
let query = `
query myqury($offset: Int, $limit: Int) {
clients(limit:$limit , offset:$offset ) {
docs{
_id
full_name
}
total
limit
offset
}
}
`
var variables = {
offset: offset,
limit: limit
}
let payload = {
query: query,
variables: variables
}
return request.post(graphQlEndpoint, payload)
The error message is:
No 'Access-Control-Allow-Origin' header is present on the requested resource
I had the same issue as you. Using the graphQL on an express server.
Try using express cors
Use it in your express code like this
const express = require( `express` );
const graphqlHTTP = require( `express-graphql` );
const cors = require( `cors` );
const app = express();
app.use( cors() );
app.use(
`/graphql`,
graphqlHTTP( {
schema: schema, // point to your schema
rootValue: rootResolver, // point to your resolver
graphiql: true
} )
);
Fetch example based on GraphQL Documentation
fetch( url, {
method : `post`,
headers: {
'Content-Type': `application/json`,
'Accept' : `application/json`
},
body: JSON.stringify( {
query: `
{
person {
name
}
}`
} )
} )
.then( response => response.json() )
.then( response => console.log( response ) );
I had the same issue when making calls using Vue client. The only way I could resolve was to disable the Cross-Origin restriction on the browser for testing purposes.
Please insert below code in your server.js file
const graphQLServer = express();
const corsOptions = {
origin(origin, callback) {
callback(null, true);
},
credentials: true
};
graphQLServer.use(cors(corsOptions));
var allowCrossDomain = function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type,token');
next();
}
graphQLServer.use(allowCrossDomain);
I think this may solve your problem

Resources