Youtube Data API and Google Cloud Endpoints - javascript

I'm having issues getting Google cloud endpoints working in tandem with the YouTube data API v3 in my javascript client. I think my issue is around the gapi.client.setApiKey() method setting the key for both my endpoints API and the YouTube api. When I do set the key YouTube works but my endpoints do not and I see the following error using my endpoints API:
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured. The API () is not enabled for your project. Please use the Google
Developers Console to update your configuration.",
"extendedHelp": "https://console.developers.google.com"
}
Without the key my endpoints work but youtube search does not and I get this message using the search feature:
{
"domain": "usageLimits",
"reason": "dailyLimitExceededUnreg",
"message": "Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup.",
"extendedHelp": "https://code.google.com/apis/console"
}
The code that loads the API is summarised below but essentially I have followed the endpoints python/javascript tutorial and the youtube data API tutorials!
init = function(apiRoot) {
var apisToLoad;
var callback = function(){
if(--apisToLoad == 0){
enableButtons();
}
}
apisToLoad = 2; // must match number of calls to gapi.client.load()
gapi.client.load('myAPIName', 'v1', callback, apiRoot);
gapi.client.load('youtube', 'v3', onYouTubeApiLoad);
};
// Called automatically when YouTube API interface is loaded (see line 9).
function onYouTubeApiLoad() {
//sets the api key
gapi.client.setApiKey('APIKeyForYouTubeFromDevConsole');
}

To verify only the youtube API requests with the API key remove the api.client.setApiKey method call.
In calls to the YouTube data API add a key parameter to the API request:
var request = gapi.client.youtube.search.list({
part: 'snippet',
type: 'video',
maxResults: 12,
q: searchValue,
key: 'YourAPIKeyGoesHere'
});
This means only these API calls are authorised and not the endpoints calls.

I'm not extremely familiar with the Youtube Data API. But I recognize the code you used for your Endpoints as the code that we provide. You can definitely use this code for the Endpoints API. For the Youtube Data one, I suggest looking here.
Looks like the code you need would be something like this :
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.services.youtube.YouTube;
public class myClass {
/**
* Define a global instance of a Youtube object, which will be used
* to make YouTube Data API requests.
*/
private static YouTube youtube;
public static void main(String[] args) {
List<String> scopes = Lists.newArrayList("https://www.googleapis.com/auth/youtube");
try {
// Authorize the request.
Credential credential = Auth.authorize(scopes, "invideoprogramming");
// This object is used to make YouTube Data API requests.
youtube = new YouTube.Builder(Auth.HTTP_TRANSPORT, Auth.JSON_FACTORY, credential)
.setApplicationName([YOUR APP])
.build();
}
From there you should be able to use the youtube object to make your calls, and the gapi to send stuff to your endpoint.

Related

How to pass event parameters to AWS Lambda function using API Gateway?

I have an AWS Lambda function written in python that is initiated by a Zapier trigger that I set up. As I pass some input parameters to the function in the Zapier trigger, I can access to the input parameters in my python code by using variables such as event[parameter1]. It perfectly works.
I'm trying to access the same Lambda function in Airtable Scripting environment. In order to do it, I set up an API Gateway trigger for the Lambda function, but I can't figure out how to pass input parameters in the vanilla JS environment. Below is the code that I have, which gives me "Internal Server Error".
Your help would be definitely appreciated!
const awsUrl = "https://random-id.execute-api.us-west-2.amazonaws.com/default/lambda-function";
let event = {
"queryStringParameters": {
"gdrive_folder_id": consFolderId,
"invitee_email": email
}
};
let response = await fetch(awsUrl, {
method: "POST",
body: JSON.stringify(event),
headers: {
"Content-Type": "application/json",
}
});
console.log(await response.json());
[Edited] Plus, here's the code of the Lambda function and the latest cloudwatch log after a successful execution invoked by Zapier. It's a simple code that automates Google Drive folder sharing based on 2 inputs. (Folder ID + email address) Please bear with me for the poor code quality!
from __future__ import print_function
from googleapiclient.discovery import build
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/drive']
SERVICE_ACCOUNT_FILE = 'service.json'
def lambda_handler(event, context):
"""Shows basic usage of the Drive v3 API.
Prints the names and ids of the first 10 files the user has access to.
"""
# 2-legged OAuth from Google service account
creds = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
drive_service = build('drive', 'v3', credentials=creds)
# change multiple permissions with batch requests
folder_id = event['gdrive_folder_id']
email_address = event['invitee_email']
def callback(request_id, response, exception):
if exception:
# Handle error
print(exception)
else:
print("Permission Id: {}".format(response.get('id')))
batch = drive_service.new_batch_http_request(callback=callback)
user_permission = {
'type': 'user',
'role': 'writer',
'emailAddress': email_address
}
batch.add(drive_service.permissions().create(
fileId=folder_id,
body=user_permission,
fields='id',
))
batch.execute()
I'm not a Python expert and I don't know how you've setup your API Gateway integration with Lambda but I believe your code can have two issues:
1.) Internal Server Error as a response from the API Gateway endpoint also often refers to a problem in the integration between the API Gateway and your Lambda function. In this case here I can not see where you are returning a valid response back to the API Gateway. In your example the return value of batch.execute() is probably returned, right? However, by default the API Gateway expects an object that contains a statusCode and body and optionally headers. You can have a look at the AWS Lambda handler documentation for Python and their examples. Also this documentation page might be of interest for you.
2.) In your function you are accessing the event data like event['gdrive_folder_id']. However, I can not see that you are parsing the event data somewhere. Are you using a custom integration between your API Gateway? Because in case of a proxy integration the API Gateway sends an object that has a body field and from there you'd need to read the HTTP body. See examples on this documentation page.
Here are some more thing you can check on your own:
Have you also checked what you get when you just print the event data? Also, is the batch.execute() waiting for the batch processing or does it return anything? If so, what does it return?
One note here: You haven't told us anything about the integration between your API Gateway and your Lambda function. Since you can do some mapping between the API Gateway and AWS Lambda, it could be possible that you are converting the request and response outside of the Lambda function and hence, my suggestions above are wrong. Let me know if this is true or not and we can further investigate it.

SoundCloud API 403 Search Endpoint

I am wanting to make use of the SoundCloud API so a user can search for an artist and then click their tracks to get an embed code.
I am using the SDK and the embed function works fine as follows:
SC.initialize({
client_id: 'XXXXXXX'
});
var track_url = 'https://soundcloud.com/forss/flickermood';
SC.oEmbed(track_url, { auto_play: true }).then(function(oEmbed) {
console.log('oEmbed response: ', oEmbed);
});
But when I use the search endpoint I get 403.
SC.get('/tracks', {
q: 'buskers', license: 'cc-by-sa'
}).then(function(tracks) {
console.log(tracks);
});
I noticed that SoundCloud uses a v2 api for the search on their site - is this documented anywhere?
I haven't been able to register an app and I have seen it's been closed for a while - I'm wondering what I need to do to get past this 403 and if it's because my client_id which I grabbed from my browser.
Any insight would be great - the API looks fairly extensive but void if I can't use it.

google realtime api / drive api -> get user role for realtime doc

I have a realtime app and get the collaborators with doc.getCollaborators() and this gives me an array [] doc is from the type gapi.drive.realtime.Document:
According to the API Reference there is no field like isOwner that shows me if the current collaborator is the owner of the realtime document "doc"
My Question how can I find out which role the collaborators of a doc has.
In the API documentation I find: "The Realtime API supports owner, reader and writer roles"
If I try to use gapi.client.drive.permissions.list suggested from the google drive api reference:
function retrievePermissions(fileId, callback) {
var request = gapi.client.drive.permissions.list({
'fileId': fileId
});
request.execute(function (resp) {
callback(resp.items);
});
}
retrievePermissions(self.realtimeDocId, function (resp) {
resp;
});
Then I get the following error message:
Error in Realtime load callback: TypeError: Cannot read property
'permissions' of undefined TypeError: Cannot read property
'permissions' of undefined
To use the drive API you must load it separately from the Realtime API.
window.gapi.client.load('drive', 'v3', function ()
{
// Run your code here.
});
After getting the permissions list, you can use the permissions ID for each user returned from your RealtimeDoc::getCollaborators call.
You may want to check how you've place your codes, based on the documentation, you can integrate Realtime API to the Drive platform.
Realtime documents are attached to files stored in Google Drive. Accordingly, your application should use the Drive REST API to interact with Drive files. For example, to create a new file, use the files.insert method from the Drive REST API. To retrieve a file that already exists, use the files.get method.
For more information on interacting with files in Google Drive, see Google Drive Integration.
As for code implementation you can check CodeMirror Collaboration with Google Drive Realtime Api.
Drive API:
/**
* Creates a new Realtime file.
* #param title {string} title of the newly created file.
* #param callback {Function} the callback to call after creation.
*/
rtclient.createRealtimeFile = function(title, callback) {
gapi.client.load('drive', 'v2', function() {
gapi.client.drive.files.insert({
'resource': {
mimeType: rtclient.REALTIME_MIMETYPE,
title: title
}
}).execute(callback);
});
}
For Realtime API:
// We have a file ID in the query parameters, so we will use it to load a file.
if (fileId) {
gapi.drive.realtime.load(fileId, this.onFileLoaded, this.initializeModel, handleErrors);
return;
}
Hope this info helps.

authenticating a service account to call a Google API with JavaScript client library

I want to make JSON-RPC calls from localhost (WAMP environment) to the Google FusionTables API (and a couple of other APIs) using the Google Client Library for JavaScript
Steps I have taken:
setup a project on the Google Developer Console
enabled the FusionTables API
created a service account and downloaded the JSON file.
successfully loaded the JS client library with the auth package: gapi.load('client:auth2', initAuth);
constructed the init method parameter the following 3 ways:
the downloaded JSON verbatim
the downloaded JSON modified to include the scope
just the client ID and scope
tried (and failed) to initialize the GoogleAuth instance: gapi.auth2.init(params)
function failed(reason) {
console.log(reason);
}
gapi.load('client:auth2', initAuth);
function initAuth() {
var APIkey = 'MY API KEY';
gapi.client.setApiKey(APIkey); //I understand this to be unnecessary with authorized requests, included just for good measure
var GDTSAKey = 'MY SERVICE ACCOUNT KEY';
var scopes = 'https://www.googleapis.com/auth/fusiontables';
gapi.auth2.init({
client_id: "101397488004556049686",
scope: 'https://www.googleapis.com/auth/fusiontables'
}).then(signin, failed("couldn't initiate"));
//passing the downlaoded JSON object verbatim as parameter to init didn't work either
} //initAuth()
function signin() {
gapi.auth2.getAuthInstance().signIn().then(makeAPIcall), failed("couldn't sign-in");
}
function makeAPIcall(){
gapi.client.load('fusiontables', 'v2', function(){
var tableId = '1PSI_...';
var table = gapi.client.fusiontables.table.get(tableId);
document.querySelector("#result").innerHTML = table;
});
}
based on JS client library >> Samples
the gapi.auth2.init method invokes the second callback (which I understand to be an error handler): failed("couldn't initiate"), but then, curiously, I also get `couldn't sign in' which could only have originated from within the provided success handler. What's going on? How do I get this to work?
Note: I am only willing to try the CORS/xhr, if there is no way to do it with JS client lib.
What's going on?
You are trying to use a service account with the Google JavaScript client library which does not support service accounts.
How do I get this to work?
Switch to Oauth2 authentication or if you must use a service account switch to a server sided language like PHP or python for example. Which support service account authentication.

Facebook Javascript SDK: Can't load a page's public feed [duplicate]

I'm trying to use the Facebook Graph API to get the latest status from a public page, let's say http://www.facebook.com/microsoft
According to http://developers.facebook.com/tools/explorer/?method=GET&path=microsoft%2Fstatuses - I need an access token. As the Microsoft page is 'public', is this definitely the case? Is there no way for me to access these public status' without an access token?
If this is the case, how is the correct method of creating an access token for my website? I have an App ID, however all of the examples at http://developers.facebook.com/docs/authentication/ describe handling user login. I simply want to get the latest status update on the Microsoft page and display it on my site.
This is by design. Once it was possible to fetch the latest status from a public page without access token. That was changed in order to block unidentified anonymous access to the API. You can get an access token for the application (if you don't have a Facebook application set for your website - you should create it) with the following call using graph API:
https://graph.facebook.com/oauth/access_token?
client_id=YOUR_APP_ID&client_secret=YOUR_APP_SECRET&
grant_type=client_credentials
This is called App Access Token. Then you proceed with the actual API call using the app access token from above.
hope this helps
You can use AppID and Secret key to get the public posts/feed of any page. This way you don't need to get the access-token. Call it like below.
https://graph.facebook.com/PAGE-ID/feed?access_token=APP-ID|APP-SECRET
And to get posts.
https://graph.facebook.com/PAGE-ID/posts?access_token=APP-ID|APP-SECRET
It's no more possible to use Facebook Graph API without access token for reading public page statuses, what is called Page Public Content Access in Facebook API permissions. Access token even is not enough. You have to use appsecret_proof along with the access token in order to validate that you are the legitimate user. https://developers.facebook.com/blog/post/v2/2018/12/10/verification-for-individual-developers/.
If you are individual developer, you have access to three pages of the data (limited), unless you own a business app.
You can get the posts by simply requesting the site that your browser would request and then extracting the posts from the HTML.
In NodeJS you can do it like this:
// npm i request cheerio request-promise-native
const rp = require('request-promise-native'); // requires installation of `request`
const cheerio = require('cheerio');
function GetFbPosts(pageUrl) {
const requestOptions = {
url: pageUrl,
headers: {
'User-Agent': 'Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0'
}
};
return rp.get(requestOptions).then( postsHtml => {
const $ = cheerio.load(postsHtml);
const timeLinePostEls = $('.userContent').map((i,el)=>$(el)).get();
const posts = timeLinePostEls.map(post=>{
return {
message: post.html(),
created_at: post.parents('.userContentWrapper').find('.timestampContent').html()
}
});
return posts;
});
}
GetFbPosts('https://www.facebook.com/pg/officialstackoverflow/posts/').then(posts=>{
// Log all posts
for (const post of posts) {
console.log(post.created_at, post.message);
}
});
For more information and an example of how to retrieve more than 20 posts see: https://stackoverflow.com/a/54267937/2879085
I had a similar use case for some weeks and I used this API:
https://rapidapi.com/axesso/api/axesso-facebook-data-service/
I could fetch all posts and comments in some minutes, worked quite well for me.

Categories

Resources