YouTube Data API - Resumable Uploads - Start a resumable session - Errors - upload

Running into parseError attempting to follow the "start a resumable session" YouTube Data API - Resumable Uploads documentation.
complete list of efforts ,response and code
I read on the Google APIs - "Global domain errors" page "parseError The API server cannot parse the request body."
I have watched "YouTube Developers Live: Debugging & Dealing with Errors" still know clue there
I have read "stack over flow" for similar questions, but never get answered,or answers are still un clear
the test youtube account i want to upload to has a youtube channel with videos
I tried the client PHP upload API, but found out later its not a resumable upload.
I thought resumable upoad would be a better option, so i dont frustrate users, by wasting there time,if there connection drops out....
I am runing PHP from hostgator account
I noticed how when i did not get an error, it would return the regular snippet and status data and not the "Step 2 - Save the resumable session URI" data
I am using long lived access tokens pulled from my database...in the requests, the youtube user has a channel with videos before i stored the access tokens
I do check the access tokens with tokeninfo?
I noticed changing "uploadType" to "uploadtype" would produce "message": "Media type 'application/json; charset=utf-8'
is not supported. Valid media types: [video/*, application/octet-stream]",following this error by changing content type to "application/octet-stream" would return "kind = youtube#video
object with json snippet,status" not the Step 2 - Save the resumable session URI, so i changed things back to "uploadType" and "application/json; charset=utf-8" now facing same parse error
I notice in the docs "Parameter values in the request URL must be URL-encoded." when i would urlencode() "Parameter values" it would return errors or parseError when i removed the urlencode function
Even changing "Host: www.googleapis.com" to "Host: https://www.googleapis.com" would produce "The requested URL /upload/youtube/v3/videos was not found on this server. That’s all we know."
parse error appears to be most persistent so far
I have changed urlencode() to rawurlencode() still parse error
i would add charset=utf-8;multipart/form-data;application/octet-stream to content type header, still parse error
I notice content type on string is text/plain; charset=us-ascii not sure if google server expects pure application/json
any help would be great…
Array
(
[response] => Array
(
[0] => {
"error": {
"errors": [
{
"domain": "global",
"reason": "parseError",
"message": "Parse Error"
}
],
"code": 400,
"message": "Parse Error"
}
}
)
[headers] => [
"POST \/upload\/youtube\/v3\/videos?uploadType=resumable&part=snippet,status HTTP\/1.1",
"Host: www.googleapis.com",
"Authorization: Bearer ya29.vAAY5n3SJq3uCG7z4tOhehDxYj9Z7mxFENtD5PKF_dJqFlLqwCktRHTrEJkUgY_NrJD3KMetKeBA_w",
"Content-Length: 303",
"Content-Type: application\/json; charset=utf-8",
"X-Upload-Content-Length: 20121",
"X-Upload-Content-Type: video\/*"
]
[curl_resource] => Resource id #18
[video_aray] => {
"snippet": {
"title": "test video",
"description": "testing api",
"tags": [
"any",
"thing"
],
"categoryId": 25
},
"status": {
"privacyStatus": "public",
"embeddable": true,
"license": "youtube"
}
}
[json_requestbody] => {
"snippet": {
"title": "test video",
"description": "testing api",
"tags": [
"any",
"thing"
],
"categoryId": 25
},
"status": {
"privacyStatus": "public",
"embeddable": true,
"license": "youtube"
}
}
[request_url] => https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status
[content_type_of_request] => text/plain; charset=us-ascii
[0] => text/plain; charset=us-ascii
[1] => text/plain; charset=us-ascii
)
Source
public function startResumableSession()
{
$videoResource = array( 'snippet'=>array('title'=>"test video",'description'=>"testing api",
'tags'=>array("any","thing"),'categoryId'=>25),
'status'=>array('privacyStatus'=>"public",'embeddable'=>True,'license'=>"youtube"));
$requestBody = json_encode($videoResource,JSON_PRETTY_PRINT);
$headers = array
(
"POST /upload/youtube/v3/videos?uploadType=resumable&part=snippet,status HTTP/1.1",
"Host: www.googleapis.com",
"Authorization: Bearer ya29.vAAY5n3SJq3uCG7z4tOhehDxYj9Z7mxFENtD5PKF_dJqFlLqwCktRHTrEJkUgY_NrJD3KMetKeBA_w",
"Content-Length: ".strlen($requestBody),
"Content-Type: application/json; charset=utf-8",
"X-Upload-Content-Length: 20121",
"X-Upload-Content-Type: video/*"
);
/* Parameter values in the request URL must be URL-encoded. */
$url = "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch, CURLOPT_POSTFIELDS,urlencode($requestBody));
curl_setopt($ch, CURLOPT_RETURNTRANSFER,TRUE);
$result = curl_exec($ch);
$json = json_decode($result);
/* Check request body contenttype */
$finfo = new finfo(FILEINFO_MIME);
$t1= $finfo->buffer($requestBody);
$t2 = $finfo->buffer("test");
$t3 = $finfo->buffer(utf8_encode("test"));
/* debug info */
return array( 'response'=>(array)$result,
'headers'=>json_encode($headers,JSON_PRETTY_PRINT),
'curl_resource'=>$ch,
'video_aray'=>json_encode($videoResource,JSON_PRETTY_PRINT),
'json_requestbody'=>$requestBody,
'request_url'=>$url,
'content_type_of_request'=>$t1,$t2,$t3
);
}

Easy answer is - you do it wrong.
You are NOT supposed to add "POST", "Host:" and "Content-Length:" into $headers because that is generated by curl (CURLOPT_URL and CURLOPT_POSTFIELDS).
YouTube API works correctly. It is not their fault.

Related

Could not get a expected Response through a POST request

I am working this API https://developer-eu.elavon.com/docs/opayo/spec/api-reference-0#operation/createCi.
I faced an issue, when creating card-identifier. I could not get an expected response.
The test API is https://pi-test.sagepay.com/api/v1/card-identifiers
To create a Card Identifier, We need a merchantKey to use as a bearerToken and request body is
{ "cardholderName": "Spongebob Squarepants", "cardNumber": "4929000000006", "expiryDate": "0223", "securityCode": "123" }
To create merchantKey use this https://reqbin.com/pzag38mw
To create Card Identifieruse this https://reqbin.com/zkhuuecs
And I added My postamn request here.
My postman http request for create Card Identifier.
curl --location --request POST 'https://pi-test.sagepay.com/api/v1/card-identifiers' \
--header 'Authorization: Bearer E0780245-2701-4748-924A-A1D5A904EB62' \
--header 'Content-Type: application/json' \
--header 'Cookie: AWSALB=o44OLd5fFLrFUD4meQBU0sxMs64iiql4YlDlppQILCFio+6pOo16e+tLu7SaI+F8sDS8CgSrRTwOcMo//ODTGcJGgNSTHPHxrP5hs87mkM1I1Xos3F0hDEoTD4dV; AWSALBCORS=o44OLd5fFLrFUD4meQBU0sxMs64iiql4YlDlppQILCFio+6pOo16e+tLu7SaI+F8sDS8CgSrRTwOcMo//ODTGcJGgNSTHPHxrP5hs87mkM1I1Xos3F0hDEoTD4dV' \
--data-raw '{
"cardholderName": "Spongebob Squarepants",
"cardNumber": "4929000000006",
"expiryDate": "0223",
"securityCode": "123"
}'
I got this Response
{
"errors": [
{
"description": "Missing mandatory field",
"property": "cardDetails.cardNumber",
"clientMessage": "The card number is required",
"code": 1003
},
{
"description": "Missing mandatory field",
"property": "cardDetails.cardholderName",
"clientMessage": "The cardholder name is required",
"code": 1003
},
{
"description": "Contains invalid value",
"property": "cardDetails.expiryDate",
"clientMessage": "The expiry date is invalid",
"code": 1009
},
{
"description": "Missing mandatory field",
"property": "cardDetails.expiryDate",
"clientMessage": "The expiry date is required",
"code": 1003
}
]
}
But The response sholud be somthing like this:
{
"cardIdentifier": "C6F92981-8C2D-457A-AA1E-16EBCD6D3AC6",
"expiry": "2015-08-11T10:45:16.285Z",
"cardType": "Visa"
}
What is the mistake I did when I sent a post request
Check the method of posting you are using in postman. If you are unsure edit to add a screenshot. Check if you have selected:
As if you use another method it may not read it
So once you have set that instead of sending you data as:
{
"cardholderName": "Spongebob Squarepants",
"cardNumber": "4929000000006",
"expiryDate": "0223",
"securityCode": "123"
}
You should send it as:
{ "cardDetails":
{
"cardholderName": "Spongebob Squarepants",
"cardNumber": "4929000000006",
"expiryDate": "0223",
"securityCode": "123"
}
}
This is because it is asking the data from under cardDetails
Please tick this if it fixed your problem so I know

Microsoft Graph API - Schema validation fails for PlanID when creating bucket, and update task doesn't work

First problem:
I am unable to create buckets in Microsoft Planner through the Graph API. I keep getting the following error even though I already specified the correct plan ID:
{"error": {"code": "", "message": "Schema validation has failed. Validation for field 'PlanId', on entity 'Bucket' has failed: A non-null value must be specified for this field.", "innerError": {"date": "2021-04-13T08:21:23", "request-id": "7f73320f-c273-4c8f-aedf-e4c413343d99", "client-request-id": "7f73320f-c273-4c8f-aedf-e4c413343d99"}}}
Second problem:
I am unable to update tasks in Microsoft Planner through the Graph API. I get a 200 response status code, but the actual task on Planner doesn't actually reflect the changes.
import requests_oauthlib
import config
import os
import json
MSGRAPH = requests_oauthlib.OAuth2Session(config.CLIENT_ID,
scope=config.SCOPES,
redirect_uri=config.REDIRECT_URI)
# Enable non-HTTPS redirect URI for development/testing.
os.environ['OAUTHLIB_INSECURE_TRANSPORT'] = '1'
# Allow token scope to not match requested scope. (Other auth libraries allow
# this, but Requests-OAuthlib raises exception on scope mismatch by default.)
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
os.environ['OAUTHLIB_IGNORE_SCOPE_CHANGE'] = '1'
def call_endpoint(do, **kwargs):
BASE_URL = "https://graph.microsoft.com"
RESOURCE = "v1.0/planner"
headers = {'Authorization': f'Bearer {config.ACCESS_TOKEN}'}
ENDPOINTS = {
"Create Plan": {"URL": f"{BASE_URL}/{RESOURCE}/plans", "data": {'owner': config.GROUP_ID, 'title': kwargs.get('title', "")}},
"Create Bucket": {"URL": f"{BASE_URL}/{RESOURCE}/buckets", "data": {"planId": kwargs.get("planId", ""), "name": kwargs.get("name", ""), 'orderHint': " !"}},
"Create Task": {"URL": f"{BASE_URL}/{RESOURCE}/tasks", "data": {'planId': kwargs.get('planId', ""), 'bucketId': kwargs.get('bucketId', ""), 'title': kwargs.get('title', ""), 'assignments': {}}},
"Get Plans": {"URL": f"{BASE_URL}/v1.0/groups/{config.GROUP_ID}/planner/plans", "data": {}},
"Get Buckets": {"URL": f"{BASE_URL}/v1.0/planner/plans/{kwargs.get('planId', '')}/buckets", 'data': {}},
"Get Tasks": {"URL": f"{BASE_URL}/{RESOURCE}/plans/{kwargs.get('planId', '')}/tasks", "data": {}},
"Get Task": {'URL': f"{BASE_URL}/{RESOURCE}/tasks/{kwargs.get('taskId', '')}/details", "data": {}},
"Get Bucket": {"URL": f"{BASE_URL}/{RESOURCE}/buckets/{kwargs.get('bucketId', '')}", "data": {}},
"Update Task": {'URL': f"{BASE_URL}/{RESOURCE}/tasks/{kwargs.get('taskId', '')}/details", "data": {'title': kwargs.get('title', ''), 'description': kwargs.get('description', ''), 'previewType': 'description'}},
}
endpoint = ENDPOINTS[do]['URL']
data = ENDPOINTS[do]['data']
print(f'{do} at {endpoint} with {data}')
if 'Create' in do:
response = MSGRAPH.post(endpoint, headers=headers, data=data).json()
elif 'Get' in do:
response = MSGRAPH.get(endpoint, headers=headers).json()
elif 'Update' in do:
response = MSGRAPH.get(ENDPOINTS['Get Task']['URL'], headers=headers, data=ENDPOINTS['Get Task']['data']).json()
print(response)
eTag = response['#odata.etag']
headers['If-Match'] = eTag
headers['Prefer'] = "return=representation"
response = MSGRAPH.patch(endpoint, headers=headers, data=data)
print(response)
response = MSGRAPH.get(ENDPOINTS['Get Task']['URL'], headers=headers, data=ENDPOINTS['Get Task']['data']).json()
if 'error' not in response:
print(f"Successful API call: {do}")
else:
print(f"API call {do} failed due to {response['error']}")
return response
response = call_endpoint("Create Bucket", name='wtf', planId='qHfOXBxd5UGoPCaiNOKWBskAE2rj')
response = call_endpoint("Update Task", taskId='IEUy7GJAd0WNTcfLhqXbKMkAIvYH', title="title created by API", description="description created by API")
Any suggestions would be deeply appreciated.
Just to isolate the issue we tried the same API call and its working with Microsoft Graph Explorer.
You found that you need to json.dumps(data) and add the "Content-Type": "application/json" into the header for it work.

Creating Group via Microsoft Graph returns Error "An unexpected PrimitiveValue node was found when reading from the JSON reader"

Am trying to create group using my admin account via Microsoft Graph. I have implemented all the required parameters/variables but when I tried making calls to the API, it displays error below:
{
"error": {
"code": "Request_BadRequest",
"message": "An unexpected 'PrimitiveValue' node was found when reading from the JSON reader. A 'StartArray' node was expected.",
"innerError": {
"request-id": "02bfcc43-5982-4c49-8484-da9d6cc61bab",
"date": "2017-12-05T17:53:57"
}
}
}
My code:
<?php
session_start();
echo $acc= $_SESSION['access_token'];
$data_string = array("description" => "An Awesome New Group", "displayName" => "Awesome Group", "groupTypes" => "Unified", "mailEnabled" => "true", "mailNickname" => "awesomeGroup", "securityEnabled" => "fasle");
$data = json_encode($data_string);
//$data = $data_string;
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://graph.microsoft.com/v1.0/groups",
CURLOPT_HEADER => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "$data",
CURLOPT_HTTPHEADER => array(
"accept: application/json",
"authorization: Bearer $acc",
"content-type: application/json; charset=utf-8"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
print_r($response);
if ($err) {
echo "cURL Error #:" . $err;
} else {
//echo $response;
}
?>
Note that my real tenant id was replaced with admin#secx34fake.onmicrosoft.com so that its not displayed to public.
The error is telling you that the URL you're using is invalid.
This is accurate as /v1.0/admin#secx34fake.onmicrosoft.com/groups isn't a valid endpoint. Specifically it rejecting the userPrincipalName of admin#secx34fake.onmicrosoft.com. I'm not exactly sure where you were going with this but a Group is not a child of a User object. A User can be a member of a Group but they are both top-level elements within your Active Directory.
As an aside, a "segment" in the context of a URL is the elements separated by a /. You can think of a URL as a / delimited string with each column being a "segment". For example, /v1.0/me/events contains 3 segments: v1.0, me and events. The error you got is telling you one of these "segments" is either invalid or not in the proper order (i.e. /v1.0/events/me has the right segments in the wrong order).
For creating a Group, the proper URI looks like this:
POST https://graph.microsoft.com/v1.0/groups
Within the body of your POST you define the properties of the group. For example:
{
"description": "An Awesome New Group",
"displayName": "Awesome Group",
"groupTypes": ["Unified"],
"mailEnabled": true,
"mailNickname": "awesomeGroup",
"securityEnabled": false
}

Google FCM Server: 200 but no notification sent to phone

I am working via Postman to send a FCM push notification to my phone that already has the app installed. I have push notifications enabled, the app is on the background, and I have a valid (confirmed) Firebase push token.
I'm POSTing to https://fcm.googleapis.com/fcm/send with the headers (Authorization: key=APP_SERVER_KEY, Content-Type: application/json), and my body looks like:
{ "notification": {
"title": "Portugal vs. Denmark",
"text": "5 to 1"
},
"to": MY_PUSH_TOKEN
}
I'm getting the following 200 OK response with body:
{
"multicast_id": MULTICAST_ID,
"success": 1,
"failure": 0,
"canonical_ids": 0,
"results": [{
"message_id": "0:MESSAGE_ID"
}]
}
everything looks fine, but I'm not getting a notification on my phone? How can I troubleshoot this, does anyone know what I'm missing?
Found the solution!
But before I offer the solution, here is a bit more background on the situation for others who might find themselves in a similar problem. I was able to POST and send a notification to an Android device, and I was able to send a push via the Firebase console to both Android and iOS device, so the only thing didn't work was sending the push to specifically an iOS device via a POST HTTP request (quite baffling).
I found this discussion here: https://github.com/firebase/quickstart-ios/issues/21. Basically for iOS, I was missing two othere parameters in the request body. I needed to set content_available to true, and priority to high.
so it looked like this:
{
"notification": {
"title": "Portugal vs. Denmark",
"body": "5 to 1"
},
"content_available": true,
"priority": "high",
"to": MY_PUSH_TOKEN
}
I believe the github discussion said something about how those added request body parameters allows FCM to push via APNS for iOS.
Thank you for your answer and explaining your context.
In my context, it wasnt working anyways.
So i added content_available and also replaced "text" with "body"
If anyone is still fighting with that, here it's how i handle it.
Cheers man !
import request from 'request'
const KEYS = require('../hardcodekeys')
export function send (title, message, ids) {
//POST: https://fcm.googleapis.com/fcm/send
//HEADER: Content-Type: application/json
//HEADER: Authorization: key=AIzaSy*******************
let push = {
"notification" : {
"body" : "great match!",
"title" : "Portugal vs. Denmark",
"icon" : "myicon"
},
content_available: true,
to: ids
priority: 'high'
}
let options = {
method: 'POST',
url: 'https://fcm.googleapis.com/fcm/send',
headers: {
'Content-Type': 'application/json',
'Authorization' : `key=${KEYS.FCM_KEY}`
},
body: JSON.stringify(push)
}
function callback(error, response, body) {
console.log(response.statusCode)
console.log(body)
console.log(error)
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
console.log(info)
}
}
request(options, callback)
}
Alternative working solution to send push notification to iOS device using php script.
Just change value for keys 'to' from fields array and Authorization from header array as per comment
//To Execute this this from Mac Terminal type php thisFilename.php
$url = 'https://fcm.googleapis.com/fcm/send';
$fields = array (
'to' => 'fq5fI_wcXNY:APA91bGpR-qCYW01wNJ8pnp1ftfgR3DHqPk3ViXDqTYrq-p7MUhry9cPcpXEl7z4GFHGUPcTduww656Rks8cOpSZR-FjrseDX4S-eGdzGaBEqI46KWF8ZJmJpegbf3tzVZwILmnf64aU',//Replace with FIRInstanceID.instanceID().token() this you can get in Appdelegate, note this is NOT token received in didRegisterForRemoteNotificationsWithDeviceToken
'notification' => array (
"body" => "message",
"title" => "Title",
"icon" => "myicon"
)
);
$fields = json_encode ( $fields );
$headers = array (
'Authorization: key=' . "AIdfdfzaSyC_0F8sqVqOgdg3Es4trWFcrNcrLpBjG6w06w",//This is Server Key, you can get it from Firebase console -> App Setting -> Cloud Messaging Tab - Legacy server key
'Content-Type: application/json'
);
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_POST, true );
curl_setopt ( $ch, CURLOPT_HTTPHEADER, $headers );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $fields );
$result = curl_exec ( $ch );
curl_close ( $ch );
?>

Http JSON POST request returns empty body response with ruby

I am playing with ruby & services, I try to retreive a json response, BUT only get an empty body response :
uri = URI("http://.../v1/queryContext")
req = Net::HTTP::Post.new(uri.path, initheader = {'content-type' => 'application/json', 'Accept' => 'application/json'})
req.body = {
"entities": [
{
"type": "Printer",
"isPattern": "false",
"id": "UM1"
}
]
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
http.request(req)
end
Requests works fine (Status 200 / Message OK) but the JSON content that returns is not there (response.body.size = 0). very strange as I can see that its produced by the server.
Response payload: '{
"contextResponses" : [
{
"contextElement" : {
"type" : "Printer",
"isPattern" : "false",
"id" : "UM1",
"attributes" : [
{
"name" : "bed",
"type" : "float",
"value" : "50"
},
{
"name" : "temperature",
"type" : "float",
"value" : "180"
}
]
},
"statusCode" : {
"code" : "200",
"reasonPhrase" : "OK"
}
}
]
}
'
Also, The following curl equivalent Works fine :
(curl http://.../v1/queryContext -s -S --header 'Content-Type: application/json' \
--header 'Accept: application/json' -d #- | python -mjson.tool) <<EOF
{
"entities": [
{
"type": "Printer",
"isPattern": "false",
"id": "UM1"
}
]
}
EOF
I have the same exact issue using gems like httpclient or unirest. Is There anything special in Ruby that has to be done to receive the awaited json contents ?
Thanks
Your code looks fine, I would suggest clearing bundle's cache (bundle clean --force) and install packages again.
Have you also tried running it on a different machine?
By the way, here's a clear example about doing a json request with the HTTP library you are using:
https://www.socialtext.net/open/very_simple_rest_in_ruby_part_3_post_to_create_a_new_workspace
It seems body of your request pretty print formatted. If you use object mapper or et. could you please check your object mapper have enabled prettyprint property or something like that? If it is enabled, remove it and try again. If you don't use object mapper, try to send a compact body instead of formatted one.
Good luck!

Resources