Graphql Yoga Playground with Lambda - "Server cannot be reached" - javascript

I'm in the process of setting a graphql endpoint with servlerless/ lambda and am receiving an error when trying to connect to the graphql playground that comes with graphql-yoga. When I go to my route that has the playground (/playground) it launches the playground interface however it just says:
Server cannot be reached
In the top right of the playground. It's worth noting i'm using the makeRemoteExecutableSchema utility to proxy to another graphql endpoint (which is my CMS called Prismic). I don't believe this is the issue as I have successfully connected to it with the playground when testing on a normal express server.
Here is the code in my handler.js
'use strict';
const { makeRemoteExecutableSchema } = require('graphql-tools');
const { PrismicLink } = require("apollo-link-prismic");
const { introspectSchema } = require('graphql-tools');
const { ACCESS_TOKEN, CMS_URL } = process.env;
const { GraphQLServerLambda } = require('graphql-yoga')
const lambda = async () => {
const link = PrismicLink({
uri: CMS_URL,
accessToken: ACCESS_TOKEN
});
const schema = await introspectSchema(link);
const executableSchema = makeRemoteExecutableSchema({
schema,
link,
});
return new GraphQLServerLambda({
schema: executableSchema,
context: req => ({ ...req })
});
}
exports.playground = async (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
const graphQl = await lambda();
return graphQl.playgroundHandler(event, context, callback);
};
I have followed this guide for getting it running up till here and am fairly sure i've followed similar steps for what applies to what i'm trying to do but can't seem to figure out where i've gone wrong.
Thanks,

Could you take a look at what version of the graphql-yoga package you are using?
I had a similar problem using the Apollo server in combination with Kentico Cloud Headless CMS and I found this issue:
https://github.com/prisma/graphql-yoga/issues/267

Related

Nextjs - getServerSideProps not reading query param in production

Hope you are well.
I am working on a Next.js project, we have a searchbar in the homepage whose method is located inside the file /pages/search.page.tsx and it runs through the getServerSideProps method.
We came into this bug that affects the search results pagination in production, not any issue in local development or local build.
Basically once a search query is executed the app renders the first bunch of results at: https://www.example.com/search/?s=what-you-have-searched/
So far so good.
However when we try to go ahead with the page results, it keeps rendering the first page because the 'skip' param is not read/received even if it appears in the url like so:
https://www.example.com/search/?s=what-you-have-searched&**skip=15**&type=articolo%2Cgallery%2Cvideo/
export const getServerSideProps: GetServerSideProps = async ({ query }) => {
const apolloClient = initializeApollo();
const typeNews = [TypeContent.NEWS, TypeContent.PHOTO, TypeContent.VIDEO];
const fieldValue = query?.s || "";
const skip = +query?.skip || 0;
const type = query?.type || typeNews.join(",");
const params = getParams(fieldValue, type, skip);
const { data } = await apolloClient.query({
query: GET_CONTENTS,
variables: { ...params },
});
return {
props: {
postData: {
data
},
},
};
};
As mentioned above, we do not have any issue locally running the app through
yarn dev or yarn start
the bug shows up only when in production.
Basically the 'skip' url params destructured from the object query always return 0 even if the url contains a different value.
What might be wrong?
How can i debug it in production to see what values we receive from the query object?
Thanks

How to handle API calls to get data that will be used for all requests to a node js application

I am designing a node js application which will get requests from frontends web applications and serve them data. It also uses some third party APIs that requires some token. Previously the token was stored in a config file. So Previously we had something like this.
config.js
module.exports = {
token: 'xxxxxxxxxxxx'}
CustomModule1.js
const configuration = require('./config');
let client = thirdparty1.createClient({
token: configuration.token});
function BusLogic(param){
client.relevantWork().then(
//return data
)
}
module.exports.BusLogic = BusLogic;
index.js
const customModule = require('./CustomModule1');
module.exports = function (context, req){
customModule1.BusLogic(req.param).then(res => {
//return frontEndData
})
}
Now we are storing token in a secure third party vault which requires another api call so I changed the structure to below.
config.js
let vaultFetch = (param1){
return getfromVault(param1)
}
module.exports = {
token: vaultFetch('tokenData')}
CustomModule1.js
function BusLogic(param,client){
client.relevantWork().then(
//return data
)
}
module.exports.BusLogic = BusLogic;
index.js
const customModule = require('./CustomModule1');
module.exports = function (context, req){
configuration.then(x => {
thirdparty1.createClient({
token: configuration.token}).then(client => {
customModule1.BusLogic(req.param,client).then(res => {
//return frontEndData
})
})
})
}
But as it so happens in case of multiple concurrent requests the api is taking a long time to fetch data. It may be caused because client is being created for every request. Is there a way to create client one time somehow by using a promise?

AWS-SDK DynamoDB Client: "export" in export const run = async () =>

This question references the method examples in AWS SDK for Javascript documentation.
The examples on the page (ie. Describing a table) splits up the code into modules:
ddbClient.js (has configuration settings).
ddb_describetable.js (has code that actually runs the method).
In ddb_describetable.js, why is there an export in front of the "const params..." and the "const run = async"? Can you explain the purpose with a high level example/best practices in relation to AWS or nodejs (if examples/best practices apply)?
ddbClient.js
// Create service client module using ES6 syntax.
import { DynamoDBClient } from "#aws-sdk/client-dynamodb";
// Set the AWS Region.
const REGION = "REGION"; //e.g. "us-east-1"
// Create an Amazon DynamoDB service client object.
const ddbClient = new DynamoDBClient({ region: REGION });
export { ddbClient };
ddb_describetable.js
// Import required AWS SDK clients and commands for Node.js
import { DescribeTableCommand } from "#aws-sdk/client-dynamodb";
import { ddbClient } from "./libs/ddbClient.js";
// Set the parameters
export const params = { TableName: "TABLE_NAME" }; //TABLE_NAME
export const run = async () => {
try {
const data = await ddbClient.send(new DescribeTableCommand(params));
console.log("Success", data);
// console.log("Success", data.Table.KeySchema);
return data;
} catch (err) {
console.log("Error", err);
}
};
run();
The actual DescribeTableCommand code documentation (which doesn't show an example) doesn't imply that this structure should be used.

Node/Express: Use a function request from another file

Firstly, I'm a frontend developer so I'm sorry if I use wrong terms in my explanations.
In my company, we are actually building 1 web app and 2 API apps. So the users use the web app which talks to the first API which talks to the second API.
Here, we are in the first API, in the server.js file:
server.js
---------
var app = express();
const cats = require("./api/cats");
app.get("/animals/cats", cats.listTheCats); // listTheCats() returns an array of cats
In cats.js, we can see with listTheCats() we are sending another request to the second API:
cats.js
-------
const listTheCats = (req, res) => {
axios({
method: "get",
url: "http://second-api-url.com/animals/cats",
params: req.query,
})
.then((ans) => {
res.status(ans.data.status).json(ans.data.data);
})
.catch((err) => {
console.log(err);
res.sendStatus(503);
});
};
module.exports = listTheCats;
The code above works fine on the web app. But now, in the first api, in another file called "cuteAnimals.js" I need to call listTheCats(). So I tried to do this but it doesn't work:
cuteAnimals.js
--------------
const { listTheCats } = require("./cats");
const fetchCats = async () => {
const params = {
type: "cute",
};
const cuteCats = await axios.get(`animals/cats`, {
params,
});
// or const cuteCats = await listTheCats(params);
console.log("cuteCats", cuteCats);
};
fetchCats();
This is the error: "Request failed with status code 400"
In cuteAnimals.js, is it right to use axios from a file to another file of the same server project?
You need to export the function in order to use it in another file, you can do it simply by writing this line at the end of cats.js
module.exports = listTheCats

How to fix firebase database initialised multiple times due to React SSR initialised database and cloud function firebase initialised database?

I have updated the question as found the root cause of the issue.
As I have hosted my React SSR app which uses firebase database in the client serving by one of the cloud function named app throwing an error of Error: FIREBASE FATAL ERROR: Database initialized multiple times. Please make sure the format of the database URL matches with each database() call.. When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo?
ORIGINAL Question: Why firebase cloud function throwing an error of 'The default Firebase app does not exist.'?
So I am trying out firebase function for the first time. admin.messaging() throwing me the following error. Help me figure out why?
If I look at the console I get results till console.log('deviceToken', deviceToken);
so whats wrong in const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);?
const functions = require('firebase-functions');
const admin = require('firebase-admin');
exports.updateUnreadCount = functions.database.ref('/chats/{chatId}/{messageId}')
.onCreate(async(snap, context) => {
const appOptions = JSON.parse(process.env.FIREBASE_CONFIG);
appOptions.databaseAuthVariableOverride = context.auth;
const adminApp = admin.initializeApp(appOptions, 'app');
const { message, senderId, receiverUid } = snap.val();
console.log(message, senderId, receiverUid);
console.log('------------------------');
const deleteApp = () => adminApp.delete().catch(() => null);
try {
const db = adminApp.database();
const reciverUserRef = await db.ref(`users/${receiverUid}/contacts/${senderId}/`);
console.log('reciverUserRef', reciverUserRef);
const deviceTokenSnapshot = await reciverUserRef.child('deviceToken').once('value');
const deviceToken = await deviceTokenSnapshot.val();
console.log('deviceToken', deviceToken);
const payload = {
notification: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
}
};
const messageDone = await admin.messaging().sendToDevice(deviceToken, payload);
console.log('Successfully sent message: ', JSON.stringify(messageDone));
return deleteApp().then(() => res);
} catch (err) {
console.log('error', err);
return deleteApp().then(() => Promise.reject(err));
}
});
Update1: According to this https://firebase.google.com/docs/cloud-messaging/send-message#send_to_a_topic, admin.messaging().sendToDevice(deviceToken, payload) APIs are only available in the Admin Node.js SDK?
So switched to
const payload = {
data: {
title: 'Test Notification Title',
body: message,
sound: 'default',
badge: '1'
},
token: deviceToken
};
const messageDone = await admin.messaging().send(payload);
Which is not working either. Getting an error Error: The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services. Any lead will be helpful.
EDIT: Finally got the function working.
My index.js is exporting to functions, follwoing
exports.app = functions.https.onRequest(app); //React SSR
exports.updateChat = functions.database.ref('/chats/{chatId}/{messageId}').onCreate(updateChat);
exports.app is a react ssr function, which I am using to host my site. This uses database too. and throwing error of multiple database instance.
When I comment out one by one and deploy, works perfectly. But when I deploy together doesn't work. How do I separate these two keeping both at the same repo? Any suggestions, please?
You can initialise db outside export function.
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(appOptions, 'app')
//continue code
Update:
const admin = require('firebase-admin');
const adminApp = admin.initializeApp(options);
async function initialize(options, apps = 'app') {
try {
const defaultApp = adminApp.name
if(defaultApp) {
const adminApp1 = admin.initializeApp(apps);
}else {
const adminApp1 = admin.initializeApp(options, apps);
}
}catch(err) {
console.error(err);
}
}
Modify this snippet as per your need and try it out
It abstracts initialize of app in another function. Just call this function at appropriate place in your code.

Categories

Resources