Im attempting to retrieve a document using the getInitialProps method from nextjs. However it is returning a Promise with a state 'pending'. Here is my code:
static async getInitialProps(context) {
const { id } = context.query;
await db
.collection('clients')
.doc('JJqyDI8a1ILqnqmp2gcO')
.get()
.then(doc => ({
data: doc.data(),
}));
console.log(data); // logs pending
return {
client: data,
};
}
I cant seem to find any examples either.
All async functions return a promise.
I don't see how you're accessing data because when you console.log it is already out of scope.
Do something like this:
static async getInitialProps(context) {
const { id } = context.query;
const data = await db
.collection('clients')
.doc('JJqyDI8a1ILqnqmp2gcO')
.get()
.then(doc => ({
...doc.data(),
}));
return {
client: data,
};
}
This should make it accessible by props.client
Related
I want to achieve something like this:
call my website url https://mywebsite/api/something
then my next.js website api will call external api
get external api data
update external api data to mongodb database one by one
then return respose it's status.
Below code is working correctly correctly. data is updating on mongodb but when I request to my api url it respond me very quickly then it updates data in database.
But I want to first update data in database and then respond me
No matter how much time its take.
Below is my code
export default async function handler(req, res) {
async function updateServer(){
return new Promise(async function(resolve, reject){
const statusArray = [];
const apiUrl = `https://example.com/api`;
const response = await fetch(apiUrl, {headers: { "Content-Type": "application/json" }});
const newsResults = await response.json();
const articles = await newsResults["articles"];
for (let i = 0; i < articles.length; i++) {
const article = articles[i];
try {
insertionData["title"] = article["title"];
insertionData["description"] = article["description"];
MongoClient.connect(mongoUri, async function (error, db) {
if (error) throw error;
const articlesCollection = db.db("database").collection("collectionname");
const customQuery = { url: article["url"] };
const customUpdate = { $set: insertionData };
const customOptions = { upsert: true };
const status = await articlesCollection.updateOne(customQuery,customUpdate,customOptions);
statusArray.push(status);
db.close();
});
} catch (error) {console.log(error);}
}
if(statusArray){
console.log("success", statusArray.length);
resolve(statusArray);
} else {
console.log("error");
reject("reject because no statusArray");
}
});
}
updateServer().then(
function(statusArray){
return res.status(200).json({ "response": "success","statusArray":statusArray }).end();
}
).catch(
function(error){
return res.status(500).json({ "response": "error", }).end();
}
);
}
How to achieve that?
Any suggestions are always welcome!
I have async function getTables() which using Google Sheet API to get google spreadsheet data. But on response it returns undefined value. this.getClient() returns OAuth2Client data. Could you check my async function, maybe it is written not properly?
async getTables(): Promise<any> {
try {
const sheets = google.sheets({
version: "v4",
auth: await this.getClient()
});
const res = await sheets.spreadsheets.values.get({
spreadsheetId: "sheetId",
range: "A1:B100"
});
return res;
} catch (err) {
throw new HttpException("The API returned an error: " + err, 500);
}
This is getClient async function which authorize client.
async getClient(): Promise<OAuth2Client> {
if (!this.oAuth2Client) {
return await this.authorize();
}
return this.oAuth2Client;
}
private async authorize() {
const credentials = {
access_token: this.auth.access_token,
refresh_token: null
};
this.oAuth2Client = new google.auth.OAuth2(this.CLIENT_ID, this.clientSecret, this.redirectUrl);
this.oAuth2Client.setCredentials(credentials);
return this.oAuth2Client;
}
It was my mistake, I just updated the version of Google API and everything is work, it returns array of data.
I have a problem building NextJs Web with NextAuth. I created my own API in pages/api and protected it with getSession from NextAuth. When I call the API using getServerSideProps or getStaticProps, getSession returns a null value, but when I call the API inside a component function, getSession returns the user data value. Can anyone help or have any tips?
pages/index.jsx
export async function getStaticProps(context) {
const projects = await fetchApi(`${process.env.BASE_URL}/projects`);
console.log(projects)
return {
props: {},
};
}
pages/api/projects
import { getSession } from 'next-auth/client';
async function handler(req, res) {
const projectService = new ProjectService();
let session;
let emailUser;
try {
session = await getSession({ req });
console.log(session); // null
emailUser = session.user.email;
if (!session) {
throw new AuthenticationError('No authenticated');
}
} catch (error) {
if (error instanceof ClientError) {
return res.status(error.statusCode).json(clientErrRes(error));
}
return res.status(500).json(serverErrRes(error));
}
...another code
}
You need to add headers in the fetch from the context. because you are fetching from server side.
const {req}=context
const {cookie} = req.headers
return fetch(`${process.env.BASE_URL}/projects`, {
headers: {
'Cookie':cookie
}
})
You can't have auth (per user) in getStaticProps because those pages are generated at compile time.
When you are calling the api from the react component (at runtime - from the browser) you are doing it on the behalf of the user so there is a session (cookie) there.
I've deployed a Lambda function, which should get list of items with a scan(params, cb) function. In console, I see something different, not the returned list, but something that lookgs like http request body or response?
Can you please explain how to get the list correctly and what do I get?
exports.handler = async (event, context, callback) => {
console.log('function started')
let params = {
TableName: "documents"
}
console.log('params get')
let respond = await db.scan(params, (err, data) => {
console.log('scan started')
if (err) console.log(err, err.stack);
else {
console.log('else started')
return data
}
})
console.log('Respons IS: ')
console.log(respond)
};
The response is a huge huge huge list of something:
You are mixing callbacks and async/await ES6 feature.
I advise you to only use the latter in this case.
Here is what it would look like :
const aws = require('aws-sdk');
const db = new aws.DynamoDB.DocumentClient();
exports.handler = async (event, context) => {
console.log('function started');
const params = {
TableName: "documents"
};
console.log('params get');
const respond = await db.scan(params).promise();
console.log('Respons IS: ');
console.log(respond);
return ...
};
I'm utilising the following API for a World Cup Laravel app - http://api.football-data.org/docs/v1/index.html#_fixture
This information brings me back today's fixture's as I'm using this code (config just holds my API key):
const todaysMatches = new Vue({
el: '#todaysMatches',
data: {
todaysMatches: [],
flags: []
},
methods: {
loadData: function () {
axios.get("http://api.football-data.org/v1/competitions/467/fixtures/?timeFrame=p1", config)
.then(response => {this.todaysMatches = response.data});
}
},
mounted: function () {
this.loadData();
}
});
This brings back the following data sctructure:
Inside each fixture you get an array of _links which you can see in the below screenshot:
Now, what I would like to do is query both the awayTeam api and the homeTeam api because they each have an endpoint of crestUrl which returns the country's flag.
You can see that inside my data I've set an array prop called flags so I was thinking of running additional calls inside my loadData method and populate that array for each fixture, but I don't think that's a clean way of doing it.
Can anyone suggest the best way to approach this?
I have used async/await pattern to achieve your requirement as below:
loadData: async function() {
const response = await axios.get(
"http://api.football-data.org/v1/competitions/467/fixtures/?timeFrame=p1",
config
);
this.todaysMatches = response.data;
let arr = this.todaysMatches.fixtures.map(fixture => {
const _links = fixture._links;
return [
axios.get(_links.awayTeam.href, config),
axios.get(_links.homeTeam.href, config)
];
});
arr.forEach(async item => {
const away = await item[0];
const home = await item[1];
this.flags.push({
awayFlag: away.data.crestUrl,
homeFlag: home.data.crestUrl
});
});
}
Explaination:
After fetching todaysMatches a new array arr is created which consists of promises returned by get request to the team's url [[getAwayTeamInfo, getHomeTeamInfo], [getAwayTeamInfo, getHomeTeamInfo], [getAwayTeamInfo, getHomeTeamInfo],...]
We loop through this and await on the promise to get the crestUrl
This crestUrl is pushed into flags array as an object
{
awayFlag: away.data.crestUrl,
homeFlag: home.data.crestUrl
}
Update
Adding the flag urls directly to the this.todaysMatches.fixtures array
loadData: async function() {
const response = await axios.get(
"http://api.football-data.org/v1/competitions/467/fixtures/?timeFrame=p1",
config
);
this.todaysMatches = response.data;
const fixtures = this.todaysMatches.fixtures;
let arr = fixtures.map(fixture => {
const _links = fixture._links;
return [
axios.get(_links.awayTeam.href, config),
axios.get(_links.homeTeam.href, config)
];
});
arr.forEach(async (item, index) => {
const away = await item[0];
const home = await item[1];
this.$set(fixtures, index, {
...fixtures[index],
awayFlag: away.data.crestUrl,
homeFlag: home.data.crestUrl
});
});
}