currently I'm writing a GraphQL API with ApolloServer/NodeJS. I have a MySQL Database. Because I'm new at this topic, I dont have any idea how can I get data directly from my database. My api sends article information to the client (this is the only purpose of my api). The client can search a specific article via ID (every article/products has a specific ID in the database. The id which the client is typing in should be compared with the id in the database. So if the id = 1 then the api should look after the article which has the id = 1 in the DATABASE and sends the requested information about THIS article to the client. (I know that this might be better with PHP, but I have some trouble with PHP). But I don't know how I can write this into my resolver.
Here is my resolver:
const models = require('../models');
module.exports = {
Query: {
article: (parent, {id}) => {
return models.articledata.find(
(c) => c.id == id
);
}
},
Node: {
__resolveType(node) {
if(node.toObject().name){
return 'Article';
}
}
}
}
Here is my models:
let articledata = [{
id: 1,
name: 'title',
description: 'Beispiel',
imgs: 'www.test.de/img',
btnLink: 'shoplink',
headline: 'Spicy das neue Spiel',
introduction: 'Beispiel',
definition: 'Beispiel',
tutorial: 'Beispiel',
specsText: 'Beispiel',
endText: 'Beispiel',
age: 12,
duration: 30,
players: 12,
category: 'Beispiel',
designer: 'Beispiel',
language: 'Deutsch',
releaseDate: 2020,
topic: 'Beispiel',
}];
module.exports = { articledata };
And here is my index.js:
const { ApolloServer } = require('apollo-server');
const schema = require('./schema');
const resolvers = require('./resolvers');
const server = new ApolloServer({
typeDefs: schema,
resolvers,
dataSources: () => {
articleAPI: new ArticleAPI()
}
})
//The listen-method launches a web server
server.listen().then(({ url }) => {
console.log('Server ready at ${url}');
});
Of course I searched on the web, but nothing seems to work for me. I'm very glad about your help!!
Did you check out the Apollo Server documentation? There is a lot of good information of connecting data sources to your server here.
There's a section about SQL connections here. The documentation notes that Apollo does not provide dedicated SQL connections right now, but shows you how to create one by working through an example.
Related
I'm using the following code to send a notification from one device to another using FCM. Everything works fine until before return admin.messaging().sendToDevice(...). The 'Token ID: ' log displays token ID of the receiver, but when I set the variable token_id to the sendToDevice function, the notification is not called, therefore the notification is not sent. Can someone tell me what's wrong?
var firebase = require("firebase-admin");
var serviceAccount = require("./julla-tutorial.json");
console.log("enter in then Firebase Api");
const firebaseToken = [
'e0T6j1AiRjaa7IXweJniJq:APA91bHNznSHSIey08s-C-c3gchci6wepvhP1QxQyYbmZ8LySI3wnu64iW7Q23GhA6VCdc4yodZoCFOgynfAb5C8O8VE81OcSv_LL-K3ET1IKGZ_6h35n-_q5EKFtfJWlzOqZr4IvpiB',
'dNWnSqyCQbufzv1JutNEWr:APA91bFcI9FDyRxHRBEcdw4791X0e-V0k1FjXcSstUA67l94hSojMRCd6LWr2b57azNEt3z_XLwLljMX4u2mc9cZDrAVm55Mw9CHGyue-09KofWnnHNR9XWBibc4T76xOV_DWX7T2RvW',
'cq65rtuaTCKGk5lHk7UabN:APA91bFR3kAArg6lhuBq7ktNuBk7Z9MXXk3PskqhYa8CgNaEl6MX4TQ5lo35d6XhnCQ4fEkCkyZ_j08evxE9Y4oVCRTEdqsrkccCVTE8Di47lfmDR3i1NdoL3re9oLw6F_uNsnvRoQcq'
]
firebase.initializeApp({
credential: firebase.credential.cert(serviceAccount)
})
const payload = {
notification: {
title: 'Demo 2345',
body: 'dfghj',
sound: 'default',
color: 'yellow',
android_channel_id: 'default',
channel_id: 'default'
},
data: { id: 'broadcast', channelId: 'default' }
}
const options = {
priority: 'high',
timeToLive: 60 * 60 * 24, // 1 day
};
console.log('------payload---',payload);
console.log('-----TOKEN_Array----',firebaseToken);
console.log('-------options-----',options);
firebase.messaging().sendToDevice(firebaseToken, payload, options).then(function (response) {
console.log('--------response',response);
}) .catch(function (error) {
console.log('-------rejet',reject);
});
It looks like you did not change the code from this tutorial:
https://medium.com/#jullainc/firebase-push-notifications-to-mobile-devices-using-nodejs-7d514e10dd4
you will need to change the 2nd line of code:
var serviceAccount = require("./julla-tutorial.json");
to actually point to your own firebase-push-admin.json file which holds your private keys registering your backend app with the firebase cloud messaging api. you can download this file from the firebase console as mentioned in the above article.
I recommend hiding this file from your git history by adding it to .gitignore so you dont accidentally push your private keys to a public repo.
I will link you another resource in addition to above link which helped me implement firebase push notifications in a nodeJS backend app.
https://izaanjahangir.medium.com/setting-schedule-push-notification-using-node-js-and-mongodb-95f73c00fc2e
https://github.com/izaanjahangir/schedule-push-notification-nodejs
Further I will also link you another repo where I am currently working on a fully functional firebase push notification implementation. Maybe it helps to actually see some example code.
https://gitlab.com/fiehra/plants-backend
I would like to host around 300 photo on Google drive and be able to fetch every photo on my react project, but I don't know how to start like should I need a back-end like node.js? I've seen this video (https://www.youtube.com/watch?v=iajv8y-6n3Q), but he displays only 1 photo.
I wanna display all my images from Google drive on the React and put it on a array like this following JSON
const photos = [
{
src: 'https://source.unsplash.com/2ShvY8Lf6l0/800x599',
width: 4,
height: 3,
year: '2021',
event: 'Hiking',
},
{
src: 'https://source.unsplash.com/Dm-qxdynoEc/800x799',
width: 1,
height: 1,
year: '2021',
event: 'J-On',
},
{
src: 'https://source.unsplash.com/qDkso9nvCg0/600x799',
width: 3,
height: 4,
year: '2021',
event: 'Language Exchange',
},
and so on...
You can achieve your goal in two ways:
Get the files link by manually copying the link from google drive
Fetch the data by using Next.js app and googleapis.
1. Get the files link by manually copying the link from google drive:
Open the file on google drive
Right click at the image file
Click Get Link and a pop up will open
At General Access select Anyone with the link and make sure the role is Viewer
Click Copy Link and done.
Then paste it at any text editor, and you will get the link like this:
https://drive.google.com/file/d/1WS45ByTh_e8QNJTeFMGI8TYpE4OYS2U4/view?usp=sharing
Remove the file/d and replace it with uc?export=view&id= and remove the /view?usp=sharing completely and you will get something like:
https://drive.google.com/uc?export=view&id=1WS45ByTh_e8QNJTeFMGI8TYpE4OYS2U4
And put the image information in an array:
const images = [
{
name: "Doctor Strange in the Multiverse of Madness",
src: "https://drive.google.com/uc?export=view&id=1WS45ByTh_e8QNJTeFMGI8TYpE4OYS2U4"
}
]
Please do the same with the other files, and your images constant finally looks like this:
const images = [
{
name: "Doctor Strange in the Multiverse of Madness",
src:
"https://drive.google.com/uc?export=view&id=1WS45ByTh_e8QNJTeFMGI8TYpE4OYS2U4",
},
{
name: "Minions: The Rise of Gru",
src:
"https://drive.google.com/uc?export=view&id=1eUvlVjwp2brHnyD-cWN0x-10tuS_wXfU",
},
...
,
{
name: "Fantastic Beasts: The Secrets of Dumbledore",
src:
"https://drive.google.com/uc?export=view&id=1vU64yCMdu_ns4xPP-VMYoiJPKNietxRc",
},
];
Now, it is time to render the images in our React Application by using javascript's map method:
export default function App() {
return (
<div>
<div>My Google Drive Images</div>
<ul>
{images.map((image, index) => {
return (
<li key={index}>
<h1>{image.name}</h1>
<img src={image.src} alt={image.name} />
</li>
);
})}
</ul>
</div>
);
}
2. Fetch the data by using Next.js app and googleapis.
In case we have many photos, it is better to use data fetching. Here we use Next.js app and googleapis library.
There are 3 pieces of information that we need to provide in order to be able to fetch data from https://www.googleapis.com/drive/v2 server which are:
CLIENT_ID
CLIENT_SECRET
REFRESH_TOKEN
For CLIENT_ID & CLIENT_SECRET are OAuth 2.0 Client information that can be obtained from Google Developers Console. You can read the details here. And for the REFRESH_TOKEN can be obtained from OAuth 2.0 Playground and the steps are as follows:
Go to https://developers.google.com/oauthplayground
Click the OAuth 2.0 Configuration button
Click Use your own OAuth credentials checkbox
Fill the Client ID & Client Secret input with the OAuth 2.0 CLIENT_ID & CLIENT_SECRET that we get from Google Developers Console.
Close the configuration popup by clicking the close link button.
Find and click the Drive API v3 at Step 1 Select & authorizes APIs.
Select https://www.googleapis.com/auth/drive to enable the Authorize APIs button.
Next we need to select which information that can be accessed by using the token that will be created by clicking the Authorize APIs button.
Then we will be directed to the Sign in with google page. Select the account that we used to generate the CLIENT_ID & CLIENT_SECRET.
If the Google hasn’t verified this app page appears, just click Advance and click Go to ...(unsafe) and select the access types that will be granted to our Next.js app then click Continue and you will be redirected to OAuth 2.0 Playground again.
Find the Exchange authorization code for tokens button at Step 2 Exchange authorization code for tokens, and click it to get the Refresh token and Access token
To make sure that we have generated the tokens correctly, go to https://www.googleapis.com/drive/v2/files?access_token={ACCESS_TOKEN} in your browser. Our configuration is successful if there is a raw JSON page that shows our drive items.
Now, we are ready for coding. We will use our NextJs API to communicate with googleapis server and serve the data to be consumed by our app.
Open your Nextjs app, create a /pages/api/drive-files.ts file, and import googleapis library (here we use Typescript).
import type { NextApiRequest, NextApiResponse } from "next";
import { google } from "googleapis";
...
Create types:
type DriveFile = {
kind: string;
id: string;
name: string;
mimeType: "image/jpeg";
};
type Data = {
files: DriveFile[];
};
Add the Data type at the NextApiResponse and the handler will look like this:
export default async function handler(
_req: NextApiRequest,
res: NextApiResponse<Data>
) {
...
}
Next, create oauth2Client that use CLIENT_ID and CLIENT_SECRET credentials and we use https://developers.google.com/oauthplayground as the redirect uri, setCredentials using REFRESH_TOKEN, and return the google.drive response as JSON;
# /pages/api/drive-files.ts
import type { NextApiRequest, NextApiResponse } from "next";
import { google } from "googleapis";
export type DriveFile = {
kind: string;
id: string;
name: string;
mimeType: "image/jpeg";
};
export type Data = {
files: DriveFile[];
};
const CLIENT_ID =
"777777777777-xxxxddhsl77d7o77777xxxx0v777xx7.apps.googleusercontent.com";
const CLIENT_SECRET = "XXXXXX-777XXXX_-7-hexxxxheAzW_7mr_7_";
const REDIRECT_URI = "https://developers.google.com/oauthplayground";
export default async function handler(
_req: NextApiRequest,
res: NextApiResponse<Data>
) {
const oauth2Client = new google.auth.OAuth2(
CLIENT_ID,
CLIENT_SECRET,
REDIRECT_URI
);
oauth2Client.setCredentials({
refresh_token:
"1//04tORk-dUiDiJCgYIARAAGAQSNwF-L9Ir1hzh14oOk6gQWMOafDZGvLuka578PwwmZB3UMbB2a0VdcjAbRjtelFoDU92ob_Ws50I",
});
const drive = google.drive({
version: "v3",
auth: oauth2Client,
params: {
q: `mimeType = 'image/jpeg'`,
},
});
const response = await drive.files.list();
res.status(200).json({ files: response.data.files as DriveFile[] });
}
And when you access http://localhost:3000/api/drive-files from the browser, you will get:
{
"files":[
{
kind: 'drive#file',
id: '1eUvlVjwp2brHnyD-cWN0x-10tuS_wXfU',
name: 'Minions: The Rise of Gru.jpg',
mimeType: 'image/jpeg'
},
{
kind: 'drive#file',
id: '1vU64yCMdu_ns4xPP-VMYoiJPKNietxRc',
name: 'Fantastic Beasts: The Secr.jpg',
mimeType: 'image/jpeg'
},
{
kind: 'drive#file',
id: '1WS45ByTh_e8QNJTeFMGI8TYpE4OYS2U4',
name: 'Doctor Strange in the M.jpg',
mimeType: 'image/jpeg'
}
]
}
Since we will use NextJs Image component, don't forget to add domain drive.google.com at next.config.js:
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
images: {
domains: ["drive.google.com"],
},
};
module.exports = nextConfig;
Finally, you can render the images as follows:
import { useEffect, useState } from "react";
import type { NextPage } from "next";
import axios from "axios";
import { DriveFile } from "./api/drive-files";
import Image from "next/image";
const DriveFiles: NextPage = () => {
const [files, setFiles] = useState<DriveFile[]>();
useEffect(() => {
axios
.get("/api/drive-files")
.then((res) => {
setFiles(res.data.files);
})
.catch((err) => {
console.log(err);
});
}, []);
useEffect(() => {
console.log(files);
}, [files]);
return (
<>
<h1>Google Drive Files</h1>
{files &&
files.map((file, i) => {
return (
<div key={i}>
<p>{file.name}</p>
<Image
width={200}
height={300}
src={`https://drive.google.com/uc?export=view&id=${file.id}`}
alt={file.name}
/>
</div>
);
})}
</>
);
};
export default DriveFiles;
I have two server-side applications editing the same database.
One server is a feathersjs app and another is a simple nodejs app. A frontend app connects to the feathersjs app via feathersjs client.
How, when the nodejs app edits the database, can I update clients connected to the feathersjs app? As currently any changes made outside the featherjs app aren't reflected on the feathersjs clients.
Can I trigger the patched event somehow and force the clients to pull down the updated data?
if you are using mongodb with WiredTiger storageEngine you can use the collection.watch() function and add a monitor in your feathers app something like this
//src/services/monitor.js
module.exports = function(app){
//get mongo client
const mongoClient = app.get('mongoClient');
//connect db
mongoClient.then(db => {
//collection to watch
const collection = db.collection('your_collection_name')
//watch collection
const changeStream = collection.watch({ fullDocument: 'updateLookup' });
//on some data changed
changeStream.on('change', data => {
console.log ( 'something is changed in your collection' , data )
//your service.emit
});
})
}
Then I added this simple monitor in the /src/services/index.js (maybe not the right way but it works)
//src/services/index.js
...
const monitor = require('./monitor.js');
module.exports = function (app) {
...
app.configure(monitor);
...
};
Data returned on every change on the collection
{ _id:
{ _data:
'825C7F03230000001C29295A100490DEF2C65812410FABF0DE46F9C89D7246645F696400645C1AC097B189CBD5D4A24D330004' },
operationType: 'replace',
clusterTime:
Timestamp { _bsontype: 'Timestamp', low_: 28, high_: 1551827747 },
fullDocument:
{ _id: 5c1ac097b189cbd5d4a24d33,
id: '12',
language: 'it-IT',
category: 'some data',
slug: '',
description: 'some data',
src:'',
color: 'card',
status: true,
home: true,
order_int: '3',
visual: 'card' },
ns: { db: 'mydb', coll: 'mycollection' },
documentKey: { _id: 5c1ac097b189cbd5d4a24d33 } }
More info here https://docs.mongodb.com/manual/reference/method/db.collection.watch/
As you pointed out, only changes made through the Feathers API will be reflected but on the server you can always emit the event you need via service.emit:
dbConnection.on('someDatabaseUpdate', data => {
app.service('messages').emit('patched', data);
app.service('messages').emit('updated', data);
});
Things to note here (also discussed in this issue):
There will be no user or any other information about the method call
data will not be run through any service hooks
I have an Azure Functionapp that processes some data and pushes that data into an Azure servicebus topic.
I require sessions to be enabled on my servicebus topic subscription. I cannot seem to find a way to set the session id when using the javascript functionapp API.
Here is a modified extract from my function app:
module.exports = function (context, streamInput) {
context.bindings.outputSbMsg = [];
context.bindings.logMessage = [];
function push(response) {
let message = {
body: CrowdSourceDatum.encode(response).finish()
, customProperties: {
protoType: manifest.Type
, version: manifest.Version
, id: functionId
, rootType: manifest.RootType
}
, brokerProperties: {
SessionId: "1"
}
context.bindings.outputSbMsg.push(message);
}
.......... some magic happens here.
push(crowdSourceDatum);
context.done();
}
But the sessionId does not seem to get set at all. Any idea on how its possible to enable this?
I tested sessionid on my function, I can set the session id property of a message and view it in Service Bus explorer. Here is my sample code.
var connectionString = 'servicebus_connectionstring';
var serviceBusService = azure.createServiceBusService(connectionString);
var message = {
body: '',
customProperties:
{
messagenumber: 0
},
brokerProperties:
{
SessionId: "1"
}
};
message.body= 'This is Message #101';
serviceBusService.sendTopicMessage('testtopic', message, function(error)
{
if (error)
{
console.log(error);
}
});
Here is the test result.
Please make sure you have enabled the portioning and sessions when you created the topic and the subscription.
I'm using ember cli mirage to write some acceptance tests for my Ember app. I succeeded to mock server response for login but I'm not happy how I did it. Ember cli mirage have shorthands for route handlers and I would like to use them but everything I try throws me an error(except this solution). Can someone help me to refactor this response?
this.post('/login', ({ users, resources })=> {
let user = users.first();
if(!Ember.isEmpty(resources.first())){
return {
data: {
type: 'user',
id: user.id,
attributes: user,
relationships: {
resources: {
data: [
{ id: resources.first().id, type: 'resource' }
]
}
}
},
};
} else {
return {
data: {
type: 'user',
id: user.id,
attributes: user
}
};
}
});
I have both user and resource model and factory defined, with relationships between them in user and resource model(it's many to many relationship). Here's how I create user in tests
test('User can login', function(assert){
let resources = server.createList('resource', 2),
user = server.create('user', {resources: resources});
loginUser(user.email);
andThen(()=>{
assert.ok(find('a:contains("Logout")'));
assert.equal('resource.content', currentPath());
});
});
If it's many-to-many, you should explicitly create a join record, as direct m2m relationship support does not yet exist.
// mirage/models/user.js
import { Model, hasMany } from 'ember-cli-mirage';
export default Model.extend({
userResources: hasMany()
});
// mirage/models/resource.js
import { Model, hasMany } from 'ember-cli-mirage';
export default Model.extend({
userResources: hasMany()
});
// mirage/models/user-resource.js
import { Model, belongsTo } from 'ember-cli-mirage';
export default Model.extend({
user: belongsTo(),
resource: belongsTo()
});
test('User can login', function(assert){
let user = server.create('user');
let resources = server.createList('resource', 2),
// create the join records
resources.forEach(resource => {
server.create('user-resource', { user, resource });
});
loginUser(user.email);
andThen(() => {
assert.ok(find('a:contains("Logout")'));
assert.equal('resource.content', currentPath());
});
});
If you need to mock an endpoint that exposes the m2m directly it will take a bit more work. But in general I find that if your Ember app exposes CRUD operations on the relationship, it's good to expose the join record, too. Makes things simpler.
That being said, Mirage will eventually support m2m relationships.