How to fetch data in ReactJS from NodeJS API for Influxdb? - node.js

I am using InfluxDB as database, I used influxdb-nodejs library module to create API to write data and Query data from Influxdb.
The Queryfunction.js API code is as follows:
module.exports = {
queryfunc: function() {
const Influx = require('influxdb-nodejs');
const client = new Influx('http://127.0.0.1:8086/mydb');
client.query('http')
.where('type', '2')
.then(console.info)
.catch(console.error);
}
}
I use a script.js file to call queryfunc() in Queryfunction.js API:
const myModule = require('./Queryfunction');
let val = myModule.queryfunc();
I use command node script to run the script file.
The result is an array
C:\Users\Admin\Desktop\reactApp\API>node script
{ results: [ { statement_id: 0, series: [Array] } ] }
I am using ReactJS to create front end UI components. How to fetch the resultant array data in ReactJS?

You're either need to write to a json file or you'll need to have an express wrapper around your db calls.
const express = require('express')
const app = express();
app.get('/api', (req, res, next) => {
const Influx = require('influxdb-nodejs');
const client = new Influx('http://127.0.0.1:8086/mydb');
client.query('http')
.where('type', '2')
.then(data => res.json(data)
.catch(err => next(err)); // error middleware to handle
}
app.listen('3000', () => console.log('running on http://localhost:3000'))
Within react you do a fetch:
Class App extends React.Component {
componentDidMount() {
fetch('http://localhost:3000')
.then(res => res.json())
.then(data => this.setState( {data} ) )
render() {
....
}
}

Related

How to override url for RTK query

I'm writing pact integration tests which require to perform actual call to specific mock server during running tests.
I found that I cannot find a way to change RTK query baseUrl after initialisation of api.
it('works with rtk', async () => {
// ... setup pact expectations
const reducer = {
[rtkApi.reducerPath]: rtkApi.reducer,
};
// proxy call to configureStore()
const { store } = setupStoreAndPersistor({
enableLog: true,
rootReducer: reducer,
isProduction: false,
});
// eslint-disable-next-line #typescript-eslint/no-explicit-any
const dispatch = store.dispatch as any;
dispatch(rtkApi.endpoints.GetModules.initiate();
// sleep for 1 second
await new Promise((resolve) => setTimeout(resolve, 1000));
const data = store.getState().api;
expect(data.queries['GetModules(undefined)']).toEqual({modules: []});
});
Base api
import { createApi } from '#reduxjs/toolkit/query/react';
import { graphqlRequestBaseQuery } from '#rtk-query/graphql-request-base-query';
import { GraphQLClient } from 'graphql-request';
export const client = new GraphQLClient('http://localhost:12355/graphql');
export const api = createApi({
baseQuery: graphqlRequestBaseQuery({ client }),
endpoints: () => ({}),
});
query is very basic
query GetModules {
modules {
name
}
}
I tried digging into customizing baseQuery but were not able to get it working.

Nodejs not sending data in Reactjs functional component

When you call it in http://localhost:9000/testApi, it works fine.
testAPI.js
const express = require('express');
var router = express.Router();
router.get("/",function(req,res){
res.send("API is working fine");
});
module.exports = router;
But Calling in ReactJS functional component leads to nothing
import React, {useState, useEffect} from 'react';
import TopicCard from './TopicCard.js'
import './HomePage.css'
function HomePage() {
const [apiResponse,setApiResponse] = useState('Loading..')
const url = "http://localhost:9000/"
useEffect(() => {
fetch(url).then(res => setApiResponse(res.data))
}, [])
return (
<>
<h1>Choose a topic to learn {apiResponse}</h1>
</>
);
Console.log gives this
PromiseĀ {}[[Prototype]]: Promise [[PromiseState]]: "rejected"
[[PromiseResult]]: SyntaxError: Unexpected token A in JSON at position
0
While the Class Component is working perfectly fine
import React, {Component} from 'react'
class Test extends Component {
constructor(props) {
super(props);
this.state = { apiResponse: "" };
}
callAPI() {
fetch("http://localhost:9000/testAPI")
.then(res => res.text())
.then(res => this.setState({ apiResponse: res }));
}
componentWillMount() {
this.callAPI();
}
render()
{
return (
<div>
<p className="App-intro">;{this.state.apiResponse}</p>
</div>
);
}
}
export default Test
No differences are between functional and class-based components.
The Problem
You forgot to parse your response as a text in the fetch method.
The Solution
parse your data as a text and then store it on your state variable
useEffect(() => {
fetch(URL)
.then(res => res.text())
.then(res => setApiResponse(res))
.catch(err => console.warn(err))
}, [])
Note: don't forget to use catch method for your asynchronous fetch API.
Explanation
When your data (API call response) is in standard JSON format, you need to parse them with .json() method, and usually, a data property holds the whole response, but in your case (with a text as a response) it's not useful.
Are you confusing routes / end points with file names? testAPI.js is your file name. It's not your endpoint.
You call:
const url = "http://localhost:9000/testAPI"
useEffect(() => {
fetch(url).then(res => setApiResponse(res.data))
}, [])
But your endpoint is - a forward slash '/' i.e. the root (not ROUTE) :
router.get("/",function(req,res){
res.send("API is working fine");
});
Try changing to this:
const url = "http://localhost:9000/"
useEffect(() => {
fetch(url).then(res => setApiResponse(res.data))
}, [])
If you want to fetch const url = "http://localhost:9000/testAPI" from react then change the endpoint to:
const url = "http://localhost:9000/testAPI" else server won't know of it.

Unable to save data in gatsby graphql layer while creating source plugin

I am trying to fetch all the videos of a youtube channel grouped by playlist. So first i am fetching all the playlists and then again fetching the corresponding videos.
const fetch = require("node-fetch")
const queryString = require("query-string")
module.exports.sourceNodes = async (
{ actions, createNodeId, createContentDigest },
configOptions
) => {
const { createNode } = actions
// Gatsby adds a configOption that's not needed for this plugin, delete it
delete configOptions.plugins
// plugin code goes here...
console.log("Testing my plugin", configOptions)
// Convert the options object into a query string
const apiOptions = queryString.stringify(configOptions)
const apiUrl = `https://www.googleapis.com/youtube/v3/playlists?${apiOptions}`
// Helper function that processes a content to match Gatsby's node structure
const processContent = content => {
const nodeId = createNodeId(`youtube--${content.id}`)
const nodeContent = JSON.stringify(content)
const nodeData = Object.assign({}, content, {
id: nodeId,
parent: null,
children: [],
internal: {
type: `tubeVideo`,
content: nodeContent,
contentDigest: createContentDigest(content)
}
})
return nodeData
}
return fetch(apiUrl)
.then(res => res.json())
.then(data => {
data.items.forEach(item => {
console.log("item", item.id)
//fetch videos of the playlist
let playlistApiOption = queryString.stringify({
part: "snippet,contentDetails",
key: "AIzaSyDPdlc3ctJ7yodRZE_GfbngNBEYbdcyys8",
playlistId: item.id,
fields: "items(id,snippet(title,description,thumbnails),contentDetails)"
})
let playlistApiUrl = `https://www.googleapis.com/youtube/v3/playlistItems?${playlistApiOption}`
fetch(playlistApiUrl)
.then(res => res.json())
.then(data => {
data.items.forEach(video => {
console.log("videos", video)
// Process the video data to match the structure of a Gatsby node
const nodeData = processContent(video)
// console.log(nodeData)
// Use Gatsby's createNode helper to create a node from the node data
createNode(nodeData)
})
})
})
})
}
Here Nodes are getting created for individual videos. But can't query this nodes from graphql store. ie. datas are not getting saved in graphql store
edit: Wait, I just realize it's inside a loop. Your sourceNodes is not waiting for the fetch inside your loop to resolve. In this case, you'd have to use something like Promise.all to resolve each item in the loop. Code's updated to reflect that.
return fetch(apiUrl)
.then(res => res.json())
.then(data => {
return Promise.all(
data.items.map(item => {
/* etc. */
return fetch(playlistApiUrl)
.then(res => res.json())
.then(data => {
data.items.forEach(video => {
/* etc. */
createNode(nodeData)
})
})
)
})
})
Check out async/await syntax, it might make finding these type of issue easier.

Using socket.io with React and Google App Engine

I've created a Node(express)/React app that uses socket.io and Redux's store as follows:
import io from "socket.io-client";
import * as types from "../actions/types";
import { cancelReview, startReview } from "./actions";
const socket = io("http://localhost:8080", {
transports: ["websocket"]
});
export const init = store => {
socket.on("connect", () => {
console.log("websocket connection successful...");
socket.on("cancelReview", (id, name) => {
cancelReview(store, id, name);
});
socket.on("startReview", (id, name) => {
startReview(store, id, name);
});
});
};
This function is then called from store.js as follows:
import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension/developmentOnly";
import thunk from "redux-thunk";
import rootReducer from "./reducers";
import { init } from "./socket/socket";
// Initial state
const initialState = {};
// Middleware
const middleware = [thunk];
const store = createStore(
rootReducer,
initialState,
composeWithDevTools(applyMiddleware(...middleware))
);
init(store);
export default store;
Everything works fine on my local machine, but I'm now realizing after doing some research that this will not work on Google's app engine because instead of http://localhost:8080 I need to get the actual IP address from Google's metadata server and pass in EXTERNAL_IP + ":65080". So I'm able to get the external IP in my express app as follows:
const METADATA_NETWORK_INTERFACE_URL =
"http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip";
function getExternalIp(cb) {
const request = axios.create({
baseURL: METADATA_NETWORK_INTERFACE_URL,
headers: { "Metadata-Flavor": "Google" }
});
request
.get("/", (req, res) => {
return cb(res.data);
})
.catch(err => {
console.log("Error while talking to metadata server, assuming localhost");
return cb("localhost");
});
}
However, if I pass this value into my render function as seen below, React creates a prop to pass into components (as far as I understand from the info I could find):
app.get("*", (req, res) => {
getExternalIp(extIp => {
res.render(path.resolve(__dirname, "client", "build", "index.html"), {
externalIp: extIp
});
});
I am not able to access this value via the window global. So my question is, how do I access this external IP from my store initialization, since it is not an actual React component?
Thanks in advance.

socket io on sails js as API and node+react as Frontend

I have an API build using sailsjs and a react redux attach to a nodejs backend, and i am trying to implement socket.io for a realtime communication, how does this work?
is it
socket.io client on the react side that connects to a socket.io server on its nodejs backend that connects to a socket.io server on the API
socket.io client on the react side and on its nodejs backend that connects to a socket.io server on the API
i have tried looking around for some answers, but none seems to meet my requirements.
to try things out, i put the hello endpoint on my API, using the sailsjs realtime documentation, but when i do a sails lift i got this error Could not fetch session, since connecting socket has no cookie (is this a cross-origin socket?) i figure that i need to pass an auth code inside the request headers Authorization property.
Assuming i went for my #1 question, and by using redux-socket.io,
In my redux middleware i created a socketMiddleware
import createSocketIoMiddleware from 'redux-socket.io'
import io from 'socket.io-client'
import config from '../../../config'
const socket = io(config.host)
export default function socketMiddleware() {
return createSocketIoMiddleware(
socket,
() => next => (action) => {
const { nextAction, shuttle, ...rest } = action
if (!shuttle) {
return next(action)
}
const { socket_url: shuttleUrl = '' } = config
const apiParams = {
data: shuttle,
shuttleUrl,
}
const nextParams = {
...rest,
promise: api => api.post(apiParams),
nextAction,
}
return next(nextParams)
},
)
}
and in my redux store
import { createStore, applyMiddleware, compose } from 'redux'
import createSocketIoMiddleware from 'redux-socket.io'
...
import rootReducers from '../reducer'
import socketMiddleware from '../middleware/socketMiddleware'
import promiseMiddleware from '../middleware/promiseMiddleware'
...
import config from '../../../config'
export default function configStore(initialState) {
const socket = socketMiddleware()
...
const promise = promiseMiddleware(new ApiCall())
const middleware = [
applyMiddleware(socket),
...
applyMiddleware(promise),
]
if (config.env !== 'production') {
middleware.push(DevTools.instrument())
}
const createStoreWithMiddleware = compose(...middleware)
const store = createStoreWithMiddleware(createStore)(rootReducers, initialState)
...
return store
}
in my promiseMiddleware
export default function promiseMiddleware(api) {
return () => next => (action) => {
const { nextAction, promise, type, ...rest } = action
if (!promise) {
return next(action)
}
const [REQUEST, SUCCESS, FAILURE] = type
next({ ...rest, type: REQUEST })
function success(res) {
next({ ...rest, payload: res, type: SUCCESS })
if (nextAction) {
nextAction(res)
}
}
function error(err) {
next({ ...rest, payload: err, type: FAILURE })
if (nextAction) {
nextAction({}, err)
}
}
return promise(api)
.then(success, error)
.catch((err) => {
console.error('ERROR ON THE MIDDLEWARE: ', REQUEST, err) // eslint-disable-line no-console
next({ ...rest, payload: err, type: FAILURE })
})
}
}
my ApiCall
/* eslint-disable camelcase */
import superagent from 'superagent'
...
const methods = ['get', 'post', 'put', 'patch', 'del']
export default class ApiCall {
constructor() {
methods.forEach(method =>
this[method] = ({ params, data, shuttleUrl, savePath, mediaType, files } = {}) =>
new Promise((resolve, reject) => {
const request = superagent[method](shuttleUrl)
if (params) {
request.query(params)
}
...
if (data) {
request.send(data)
}
request.end((err, { body } = {}) => err ? reject(body || err) : resolve(body))
},
))
}
}
All this relation between the middlewares and the store works well on regular http api call. My question is, am i on the right path? if i am, then what should i write on this reactjs server part to communicate with the api socket? should i also use socket.io-client?
You need to add sails.io.js at your node server. Sails socket behavior it's quite tricky. Since, it's not using on method to listen the event.
Create sails endpoint which handle socket request. The documentation is here. The documentation is such a pain in the ass, but please bear with it.
On your node server. You can use it like
import socketIOClient from 'socket.io-client'
import sailsIOClient from 'sails.io.js'
const ioClient = sailsIOClient(socketIOClient)
ioClient.sails.url = "YOUR SOCKET SERVER URL"
ioClient.socket.get("SAILS ENDPOINT WHICH HANDLE SOCKET", function(data) {
console.log('Socket Data', data);
})

Resources