I have an express server set up like so:
app.get('/', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
fetch('https://api.adzuna.com:443/v1/api/property/gb/search/1?app_id=1cd4129d&app_key=key&where=se16bx&distance=5&category=for-sale')
.then(response => response.json())
.then(data => {
res.send(data) // Prints result from `response.json()` in getRequest
})
.catch(error => console.error(error))
});
I then have a Next.js page like so:
class About extends Component {
state = {postcode: null}
handleOnSubmit = e => {
// calling the api passing the postcode
}
render() {
return(
<form>
<input name="postcode" />
<button onClick={this.handleOnSubmit}></button>
</form>
)
}
}
About.getInitialProps = async function() {
const res = await fetch('http://localhost:3001/');
const data = await res.json();
return {
results: data
}
}
the API call in the Express server has a hard coded postcode in it.
where=se16bx
How can I pass that value in a dynamic way based on what the user will put into the form?
Thanks
Yes you can create dynamic API call, for complete documentation you can see from here (Check /posts API).
In your case, you just need to add slug into your endpoint, then pass it to your fetcher function:
app.get('/:id*', (req, res) => {
res.setHeader('Access-Control-Allow-Origin', '*');
fetch(`https://api.adzuna.com:443/v1/api/property/gb/search/1?app_id=1cd4129d&app_key=key&where=${req.params.id}&distance=5&category=for-sale`)
.then(response => response.json())
.then(data => {
res.send(data) // Prints result from `response.json()` in getRequest
})
.catch(error => console.error(error))
});
Related
I am testing very basic REST api with supertest. I want to save the item id received in response body and assign it to a variable. Using this id i want to make further tests like get-item-by-id or update-item-by-id. No official documentation has covered this so a beginner friendly answer would be very helpful.
test i have written
const request = require("supertest")
let id;
describe('Products API', () => {
it('GET /products --> array of products', async () => {
return request('http://localhost:3001')
.get('/api/products')
.expect(200)
.expect('Content-Type', /json/)
.then(response => {
expect(response.body).toEqual(
expect.objectContaining({
success: true,
data: expect.any(Array)
})
)
})
})
})
Use regular JS variables
const request = require("supertest")
describe('Products API', () => {
it('GET /products --> array of products', async () => {
return request('http://localhost:3001')
.get('/api/products')
.expect(200)
.expect('Content-Type', /json/)
.then(response => {
expect(response.body).toEqual(
expect.objectContaining({
success: true,
data: expect.any(Array)
})
)
const data = response.body.data;
expect(data.length).toBeGreaterThan(0)
data.forEach(product => {
let id = product.id;
// expect data about the products
})
})
})
})
want to make further tests like get-item-by-id or update-item-by-id
You should explicitly test those endpoints, not via GET /api/products
E.g.
it('POST /products/{id} --> Updates a product', async () => {
const id = 1;
const result = request('http://localhost:3001')
.post(`/api/products/${id}`)
...
// TODO: Check the product was actually updated in the database, for example
});
More importantly, don't (or try not to) store variable state between tests.
i'm really new to Backend and was trying to fiddle around with API-Calls and Client-Server stuff.
const express = require("express");
const cors = require("cors");
const fetch = require("node-fetch");
const app = express();
app.use(cors());
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Listening on port ${port}`));
app.get("/express_backend", (req, res) => {
fetch(
"http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=XXXXXXXXXXXXXXXXXX&steamid=76561197996613749&format=json"
)
.then((response) => response.json())
.then((data) => console.log(data))
.then((data) => res.send(data));
});
so this is my server file and it properly fetches the data from the steam api output screenshot
But im struggling to get this from the server to my client.
import React, { useState, useEffect } from "react";
const App = () => {
const [data, setData] = useState(null);
useEffect(() => {
fetch("/express_backend")
.then(function (response) {
return response.json();
})
.then(function (json) {
let fetchedData = json;
setData(fetchedData);
})
.catch(function (err) {
console.log(err.message);
});
}, []);
return (
<div>
<p>{data}</p>
</div>
);
};
export default App;
I think that the "Unexpected end of JSON input" Error is related to the "response.json() line but im not really sure how to go on with this or how to fix it. Thanks in Advance!
there is a small issue on the backend server. In the below Promise chain, the second thenable is not returning anything to the third thenable, so basically you are not writing anything to the 'response' when doing res.send(data)
app.get("/express_backend", (req, res) => {
fetch(
"http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=XXXXXXXXXXXXXXXXXX&steamid=76561197996613749&format=json"
)
.then((response) => response.json())
.then((data) => console.log(data))
.then((data) => res.send(data));
});
The correct order would be to merge second and third then handlers, like so
app.get("/express_backend", (req, res) => {
fetch(
"http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=XXXXXXXXXXXXXXXXXX&steamid=76561197996613749&format=json"
)
.then((response) => response.json())
.then((data) => {
console.log(data);
res.send(data);
})
})
I'm using a react frontend and fetching data from my node server. I feel like my code looks a bit redundant, is there a better way to refactor all this?
App.js
searchStock = async (value) => {
let priceURL = `/stock/${ value }/price`
// fetch price data
fetch(priceURL)
.then(res => {
if (res.ok) {
res.json()
.then( (result) => {
this.setState({
price: result
})
})
}
else {
console.log("Something went wrong...")
}
})
}
server.js
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetch(apiURL)
.then(response => {
console.log(response.status)
if (response.ok) {
response.json().then((data) => {
res.json(data)
});
}
else {
res.sendStatus(response.status)
}
})
.catch(error => {
console.log(error);
});
})
As these two code segments live in different apps (frontend and backend) I don't think there's a pretty way of DRYing this.
Introduce library file with fetching logic
src/helper.js
exports.fetchHelper = (url) => fetch(url)
.then(response => {
if (response.ok) {
return response.json();
} else {
res.sendStatus(response.status)
}
})
.catch(console.error);
and use respectively
app.js
import { fetchHelper } from 'src/helper'; // or whatever else your bundler setup requires
searchStock = async (value) => {
const priceURL = `/stock/${ value }/price`;
await fetchHelper(priceURL).then((result) => {
this.setState({
price: result
})
})
}
server.js
const fetchHelper = require('src/helper').fetchHelper;
app.get('/stock/:symbol/price', (req, res) => {
const token = 'abcde123'
const symbol = req.params.symbol
const apiURL = `https://sandbox.iexapis.com/stable/stock/${symbol}/price?token=T${token}`
fetchHelper(apiURL).then((response) => {
res.json(data);
})
Or something similar...
I am trying to build a log for an Express API, however am having issues getting the data to log out.
I can log the original req and res objects in the finally block, but am not sure how I would access the SQL response.
const sql = require("mssql")
const config = require("../config")
router.get("/express-route", (req, res) => {
sql.connect(config.properties).then(pool => {
return pool.request()
.input('username', sql.NVarChar(32), req.params.username)
.execute('do_something_with_username')
.then(response => res.send(response) // pass this response
.catch(err => res.send(err))
.finally(() => {
console.log('response', response) // to here
sql.close()
})
})
}
How would I take the response from the first then block and pass it to the finally block to be used in another function?
A finally callback will not receive any argument, since there's no reliable means of determining if the promise was fulfilled or rejected. This use case is for precisely when you do not care about the rejection reason, or the fulfillment value, and so there's no need to provide it. (mdn)
Instead, simply use .then:
const sql = require("mssql")
const config = require("../config")
router.get("/express-route", (req, res) => {
sql.connect(config.properties).then(pool => {
return pool.request()
.input('username', sql.NVarChar(32), req.params.username)
.execute('do_something_with_username')
.then(response => {res.send(response); return response;}) // pass this response
.catch(err => res.send(err))
.then(response => {
console.log('response', response) // to here
sql.close()
})
})
}
You can, in fact, simplify things by writing your code within an async function
const sql = require("mssql")
const config = require("../config")
router.get("/express-route", (req, res) => {
sql.connect(config.properties).then(async pool => {
try {
const response = await pool.request()
.input('username', sql.NVarChar(32), req.params.username)
.execute('do_something_with_username');
// do another request
const otherResponse = await pool.request() ... ;
res.send(response);
} catch (err) {
res.send(err);
} finally {
sql.close();
}
})
}
This lets you write code in a more linear manner.
Ok, so what I am trying to do is do an axios.get() request pull specific data an id specifically, then use that id that I got to put it as a string literal so I can do my second request. I keep getting Info is not defined.
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`
)
.then(response => {
info = response.data.id;
})
.then(
axios.get(
`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`
)
)
.then(response => {
summoner = response.data;
return summoner;
});
let getSummonerId = (req, res) => {
res.status(200).send(summoner);
};
module.exports = {
getSummonerId
};
Fix your chaining:
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`
)
.then(response => {
return response.data.id;
})
.then(info => {
return axios.get(
`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`
)
})
.then(response => {
summoner = response.data;
return summoner;
});
Personally, I recommend async for tasks such as this. Makes handling things a lot easier with promises:
let fetchSummoner = async() => {
const res = await axios.get(`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`);
const info = res.data.id;
const res2 = await axios.get(`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`);
const summoner = res2.data;
return summoner;
}
In the current code you haven't added a return statement in the 2nd axios request. Failing to this will not fetch and return the 2nd url.
Please try the below code.
axios
.get(
`https://na1.api.riotgames.com/lol/summoner/v4/summoners/by-name/bloodstrive?api_key=${api}`
)
.then(response => {
return response.data.id;
})
.then(info => {
return axios.get(
`https://na1.api.riotgames.com/lol/league/v4/entries/by-summoner/${info}?api_key=${api}`
)
})
.then(response => {
summoner = response.data;
return summoner;
});