How to make my react app dynamic when fetching api? - mysql

In my react app, im using Im using MySql and NodeJS. When im fetching api, the code looks something like this
axios.post('http://localhost:5000/api/product-from-search', obj)
.then(function (response) {
state.setState({ searchInputResult: response.data })
})
.catch(function (error) {
console.log(error);
})
}
how can i make it dynamic so that i only need to write
axios.post('/api/product-from-search', obj)

You can define your baseURL outside your component and use template literals in your function call.
const baseURL = "http://localhost:5000"
~~~
axios.post(`${baseURL}/api/product-from-search`, obj)

excuse me if I'm not understanding your question correctly.
I think you are asking how to set your baseURL for Axios, so you can type all your routes as relative instead of absolute ('/api/...' instead of 'http://address:port/api/...')?
You should not need to write the http://localhost:5000 part of the path. Axios should work fine with just just the relative '/api/...'.
If that's NOT the case, I think you might have a CORS issue. (https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
If you've used create-react-app, then in the package.json (of your react app) add the following line just before the closing curly brace:
"proxy": "http://localhost:5000"
EDIT: Don't forget to restart your server after doing this!
If it's a CORS problem, the request is failing because your server is at a different origin (in this case, different port) than your front end, which the browser will block for security reasons.
Of course, you can use AXIOS configuration to set a baseURL so that you don't have to include it in every route as described here: (https://github.com/axios/axios)
const instance = axios.create({
baseURL: 'https://some-domain.com/api/',
timeout: 1000,
headers: {'X-Custom-Header': 'foobar'}
});
But I don't think that's your actual issue. Try the proxy in your package.json first.
Cheers!

You can create a separate 'helper.js' file where you can define a function to configure axios post request as per the requirements.
import React from 'react';
let baseUrl = "http://localhost:5000";
export function post(apiEndpoint, payload){
return axios.post(baseUrl+apiEndpoint, payload,
options = { headers: {
'Authorization': 'Your token goes here',
}})
.then((response)=>{
return response;
}).catch((err)=>{
console.log(err);
})
}
Now, call this named export into your file with required params.

Related

Nextjs/Vercel error: only absolute URLs are supported. Where is the '.json' in my route params coming from?

The Problem:
I'm new to Next.js (1 month) and Vercel (1 day), and between them something appears to be inserting .json in my urls on the search route, causing them to fail with error:
[GET] /_next/data/9MJcw6afNEM1L-eax6OWi/search/hand.json?term=hand
10:21:52:87
Function Status:None
Edge Status:500
Duration:292.66 ms
Init Duration: 448.12 ms
Memory Used:88 MB
ID:fra1:fra1::ldzhz-1644484912454-0a30b71b6c90
User Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.0
TypeError: Only absolute URLs are supported
at getNodeRequestOptions (/var/task/node_modules/next/dist/compiled/node-fetch/index.js:1:61917)
at /var/task/node_modules/next/dist/compiled/node-fetch/index.js:1:63448
at new Promise (<anonymous>)
at Function.fetch [as default] (/var/task/node_modules/next/dist/compiled/node-fetch/index.js:1:63382)
at fetchWithAgent (/var/task/node_modules/next/dist/server/node-polyfill-fetch.js:38:39)
at getServerSideProps (/var/task/.next/server/chunks/730.js:238:28)
at Object.renderToHTML (/var/task/node_modules/next/dist/server/render.js:566:26)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async doRender (/var/task/node_modules/next/dist/server/base-server.js:855:38)
at async /var/task/node_modules/next/dist/server/base-
server.js:950:28
2022-02-10T09:21:53.788Z 994c9544-0bbe-4a68-af83-f0e4c322151e ERROR
Error: Your `getServerSideProps` function did not return an object. Did you forget to add a `return`?
at Object.renderToHTML (/var/task/node_modules/next/dist/server/render.js:592:19)
at processTicksAndRejections (internal/process/task_queues.js:95:5)
at async doRender (/var/task/node_modules/next/dist/server/base-server.js:855:38)
at async /var/task/node_modules/next/dist/server/base-server.js:950:28
at async /var/task/node_modules/next/dist/server/response-cache.js:63:36 { page: '/search/[term]'}
RequestId: 994c9544-0bbe-4a68-af83-f0e4c322151e Error: Runtime exited with error: exit status 1
Runtime.ExitError
Though the browser says https://.../search/hand as it should.
No such thing is happening on my local server build though, and it works perfectly well.
Background/Code Snippets:
The search route is the only route that uses SSR, and is also the only route with this issue. It is a dynamic route, so it seems either next in production or vercel expects some kind of json for it -presumably pre-rendered content-, and is replacing the route URL with json.
Also I have had to use the VERCEL_URL environment variable to prepare a URL for fetch requests, so this may also be messing up the URL, but the .json in the error message makes me think otherwise, since search should not be pre-rendered.
The Page Structure For the Search Route (Index imports the component in [term] and defines its own getServerSide props to accommodate a search route without a param):
|-Search
|- [term].js
|- Index.js
The Code For [term].js:
...
export default function Search({results, currentSearch}){
...
}
export async function getServerSideProps(req) {
const { criteria, page } = req.query;
const { term } = req.params || { term: '' };
try {
const data = await fetch(`${process.env.VERCEL_URL}/api/search/${term}?criteria=${criteria || 'name'}&page=${page}`);
const searchRes = await data.json();
return {
props: {
results: searchRes.data,
currentSearch: searchRes.query
}
}
} catch (e) {
console.log(e)
}
}
Index.js is similar:
import Search from "./[term]";
export default Search;
export async function getServerSideProps(req) {
const { criteria, page } = req.query;
const { term } = req.params || { term: '' };
if(!term){
return {
props: {
results: [],
currentSearch: {}
}
}
}
try {
const data = await fetch(`${process.env.VERCEL_URL}/api/search/${term}?criteria=${criteria || 'name'}&page=${page}`);
const searchRes = await data.json();
return {
props: {
results: searchRes.data,
currentSearch: searchRes.query
}
}
} catch (e) {
console.log(e)
}
}
The API I'm trying to fetch from is confirmed to be working, so this problem is strictly regarding pages, or .json being provided to the fetch method from router params.
It would turn out that VERCEL_URL is actually an absolute URL (It does not include a protocol). I had to deploy console.log statements to find this. A little embarrassed that I missed it in the docs.
The .json was not actually in the query or params, and therefore not in the fetch request. The fetch failed because the url had no protocol.
The .json in the page url must be from Next's internal operations, and does not mean the page is being built ahead of time. Yes it is being rendered using some json, but my thinking that the json indicates a pre-rendered page(SSG/ISR) was wrong. This must mean Server Side Rendering will also make use of such json, but only at runtime, when the request is made.
The use of .json after the params slug in the GET requests for a page has no bearing on the internal flow of your app, provided it has worked correctly. If you see it in error messages, know that it is from Next and examine other parts of the code at the point of failure.
The page structure I attempted ([param].js + index.js in the same
directory) is fine, which is why my local build could work properly.
I want to delete this question because the solution is essentially one that a thorough look in the docs would have revealed, but at the same time I think the mistake itself is an easily made one and that some of the conclusions listed above(particularly the one about json being used in all next routes) could save time spent debugging for some new users of Next/Vercel.

how can I set a global function for call Apis in NUXT?

after some google searched,
I am doing this in plugins/callApi.js
import axios from 'axios';
import Vue from 'vue';
Vue.use(callApi);
export default async (apiUrl, postData, headers = {}) => {
let msg = await axios.post(https://my-api-location.com' + apiUrl,postData);
return msg.data;
};
then set in nuxt.config.js
plugins: [
'~plugins/callApi.js']
when I want to use it
const msgData = await callApi('/api/news/getNewsList', postData);
if (msgData.response === 'success') { .......
but when I start yarn dev, it hightlight "Vue.use(callApi);" part and says "callApi is not defined"
how cant I fix it? thanks a lot :)
I actually re-read your answer because I was a little confused.
So, in your callApi.js, you define what you want there, but you are calling Vue.use(callApi) in the file where you are actually defining what callApi will be.
At the moment the compiler goes to Vue.use(callApi), this variable "callApi" is not defined yet (because it will only be available after it finishes compiling this very file).
So just do the
import axios from 'axios';
import Vue from 'vue';
export default async (apiUrl, postData, headers = {}) => {
let msg = await axios.post(https://my-api-location.com' + apiUrl,postData);
return msg.data;
};
then, by setting the plugin path on the plugins property in the nuxt.config file (exactly the way you did), the very callApi file will be automatically called (try to put a console log in your callApi file, and you'll see it logging when you start your application).
An example of what you want:
https://codesandbox.io/s/nuxt-app-demovue-ssr-forked-s94rz?file=/pages/index.vue
Now in your plugin, you have to decide exactly what you want to do. you might want to expose the function or make it globally available, that's up to you!
For this last option, you might want to take a look here:
Vue/Nuxt: How to define a global method accessible to all components?
Good luck!

Why is my API requset returning only a string payload [JavaScript]

I am new to working with API and I am working on a web-extension to fetch a random quote.
Each time I refresh the page the output works fine with response.data however, I would like to use each object from the responses... and not have the entire data on the page so I can add my custom styles.
I am using Axios + pure js
and I would like to access these values
Can someone please tell me, what I am doing wrong here?
For now, all I can access is request.data
axios
.get(url)
.then(function (response) {
showTextToUser(response.data);
//NOT WORKING console.log(response['verse']);
})
.catch(function (error) {
console.log(error);
});
Here's my request using axios
This is how axios response object look like
{
config:{},
data:{ --PAYLOAD YOU SENT FROM SERVER --},
headers:{},
request:{},
status: // status code,
statusText:''
}
I think you will find the verse object in data object as response.data.verse

Make a NestJS route send in response a pretty formatted JSON

I have a NestJS route which sends back in response, a JSON not well formatted (like minified),
I want to make this JSON easier to read, like a JSON prettier or JSON formatted,
Do someone knows how to do it in NestJS ? I accept answers for other NodeJS frameworks like Express, maybe it will work in NestJS too...
Prettifying the JSON response should be the responsibility of the client, not the server. Otherwise you could be sending a lot of white space which will bloat the response size and could lead to a crash due to having a response too large. If you are using something like Postman, it should be easy to prettify it, I think Postman might do it by default. If you are looking at the response in some web browser, you could use JSON.parse() on the response and it should make the response an actual JSON which console.log() would then print in a pretty way.
You should try https://www.postman.com or https://insomnia.rest/. It can save you a lot of time when it comes to testing an API.
While you shouldn't do it in prod as mentioned above, there's number of cases where it makes a lot of sense (e.g. in dev env). You can achieve this in a bit hacky way:
Access express instance inside nest through breaking abstraction. It's not exposed on INest interface, so you'll need to cast it to any type to bypass Typescript check
Set undocumented express property "json spaces", which will set formatting for all JSON responses over the app
const app = await NestFactory.create(AppModule);
if (process.env.NODE_ENV === 'development') {
(app as any).httpAdapter.instance.set('json spaces', 2);
}
await app.listen(3000);
It works for me:
// src/main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
if (process.env.NODE_ENV !== 'production') {
app.getHttpAdapter().getInstance().set('json spaces', 2);
}
await app.listen(process.env.PORT);
}
Define return type string on your controller
Set the Content-Type: application/json response header
Use JSON.stringify to format your object with whitespace
Example controller code:
import { Controller, Get, Header } from '#nestjs/common';
#Controller('diagnostics')
export class DiagnosticsController {
#Get()
#Header('Content-Type', 'application/json')
findAll(): string {
const statusCode = 200;
const statusText = 'OK';
const info = {
self: 'NestJS Diagnostics Report',
status: {
statusCode,
statusText,
},
};
return JSON.stringify(info, null, 2);
}
}

Customize Loopback response after save

I have a loopback 2.x app, in which I have a model Conversation and a model Message, with a relationship "Conversation has many messages". I want to customize the response for POST conversations/:id/messages with a json response different than the default, say {status: 'success'}. I tried to use remote hook for the method __create__messages, but it did not work:
Conversation.afterRemote('__create__messages', function(ctx, next) {
ctx.result.data = {
success: 'yes'
};
next();
});
This still returns the default response. How can I return a custom json for a remote method? I have seen examples only for all models, or for all methods: multiple models, multiple methods
Maybe you can try a version of following code below. Also, I think you are meaning to to manipulate data before the method finishes, not after. If you wait, the response will already be created, preventing your intended goal. Let me know if this works (replace with methods that will work for your use case).
Conversation.observe('before save', function(context, next) {
var instance = context.instance || context.data;
if (!instance) return next();
// Your code here
next();
});