-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[docs] Add usage info to the README #800
Comments
Hello Dannie, thanks for your interest in the project!
Make sure you're writing a script for the browser and not for the server, as NodeJS API packages provided by google are shipped with types included, see https://github.com/Maxim-Mazurok/google-api-typings-generator#javascript-vs-nodejs-clients
They are available: https://www.npmjs.com/package/@types/gapi.client.youtube-v3 I can totally see how it may be confusing, I'll try to add a note about usage in the README, thanks for bringing that up! |
Hi Maxim, thanks for the reply! It seems that after looking I do actually have access to
As per
made me believe that I needed to build them myself. I can now see that what's being intended here is for the reader to understand that the contents of the referenced file is created via the typings generator project, NOT that I'm supposed to generate them. I'm building a browser plugin, so I do believe that I'm using the right project. Perhaps I'm just better off using |
For reference, this is the code I'm trying to apply these types to: // helpers/api.ts
import settings from "../config/settings";
// gapi.client.youtube.videos.list
export async function getVideoMetadata(id: string) {
const url = new URL(`${settings.YT_API_BASE_URL}/videos`);
url.searchParams.append("id", id);
url.searchParams.append("part", "snippet");
url.searchParams.append("part", "contentDetails");
url.searchParams.append("key", settings.YT_API_KEY);
const response = await fetch(url.toString());
return await response.json();
}
export async function getCommentThreads(id: string) {
const url = new URL(`${settings.YT_API_BASE_URL}/commentThreads`);
url.searchParams.append("videoId", id);
url.searchParams.append("part", "snippet");
url.searchParams.append("order", "relevance");
// Activate this if we find videos where the original 20 don't cover it
// url.searchParams.append("maxResults", 100);
url.searchParams.append("key", settings.YT_API_KEY);
const response = await fetch(url.toString());
return await response.json();
} |
Ah, I see what you mean, I'll try to clarify that as well. Regarding your usage, I do recommend using gapi for that. That way you won't depend much on the internal naming of interfaces and only use the public API, getting all the auto-complete goodies, argument types validation, etc. Also, you'll avoid forcefully casting responses using Please refer to the docs on how to use YouTube Data API with gapi. Here's a sample JS code from there: <script src="https://apis.google.com/js/api.js"></script>
<script>
/**
* Sample JavaScript code for youtube.videos.list
* See instructions for running APIs Explorer code samples locally:
* https://developers.google.com/explorer-help/code-samples#javascript
*/
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/youtube.readonly"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey("YOUR_API_KEY");
return gapi.client.load("https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
function execute() {
return gapi.client.youtube.videos.list({
"part": [
"snippet,contentDetails,statistics"
],
"id": [
"Ks-_Mh1QhMc"
]
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
gapi.load("client:auth2", function() {
gapi.auth2.init({client_id: "YOUR_CLIENT_ID"});
});
</script>
<button onclick="authenticate().then(loadClient)">authorize and load</button>
<button onclick="execute()">execute</button> |
I think it's just an unfortunate case of me not being that aware of how type definitions are included as dependencies :) Your reasoning makes lots of sense. Thanks for the input. I'll consider switching to Thanks again for all of the help! |
Hi again! I've revisited this trying to make Since figuring this out, what I've currently been trying to do is to refactor the types I found for this library in order to make it work for my use case, under a local Something I'm struggling with is that I found, for instance, a interface Video {
/** Age restriction details related to a video. This data can only be retrieved by the video owner. */
ageGating?: VideoAgeGating;
/** The contentDetails object contains information about the video content, including the length of the video and its aspect ratio. */
contentDetails?: VideoContentDetails;
/** Etag of this resource. */
etag?: string;
/**
* The fileDetails object encapsulates information about the video file that was uploaded to YouTube, including the file's resolution, duration, audio and video codecs, stream
* bitrates, and more. This data can only be retrieved by the video owner.
*/
fileDetails?: VideoFileDetails;
/** The ID that YouTube uses to uniquely identify the video. */
id?: string;
/** Identifies what kind of resource this is. Value: the fixed string "youtube#video". */
kind?: string;
/**
* The liveStreamingDetails object contains metadata about a live video broadcast. The object will only be present in a video resource if the video is an upcoming, live, or completed
* live broadcast.
*/
liveStreamingDetails?: VideoLiveStreamingDetails;
/** The localizations object contains localized versions of the basic details about the video, such as its title and description. */
localizations?: { [P in string]: VideoLocalization };
/** The monetizationDetails object encapsulates information about the monetization status of the video. */
monetizationDetails?: VideoMonetizationDetails;
/** The player object contains information that you would use to play the video in an embedded player. */
player?: VideoPlayer;
/**
* The processingDetails object encapsulates information about YouTube's progress in processing the uploaded video file. The properties in the object identify the current processing
* status and an estimate of the time remaining until YouTube finishes processing the video. This part also indicates whether different types of data or content, such as file details
* or thumbnail images, are available for the video. The processingProgress object is designed to be polled so that the video uploaded can track the progress that YouTube has made in
* processing the uploaded video file. This data can only be retrieved by the video owner.
*/
processingDetails?: VideoProcessingDetails;
/**
* The projectDetails object contains information about the project specific video metadata. b/157517979: This part was never populated after it was added. However, it sees non-zero
* traffic because there is generated client code in the wild that refers to it [1]. We keep this field and do NOT remove it because otherwise V3 would return an error when this part
* gets requested [2]. [1]
* https://developers.google.com/resources/api-libraries/documentation/youtube/v3/csharp/latest/classGoogle_1_1Apis_1_1YouTube_1_1v3_1_1Data_1_1VideoProjectDetails.html [2]
* http://google3/video/youtube/src/python/servers/data_api/common.py?l=1565-1569&rcl=344141677
*/
projectDetails?: any;
/** The recordingDetails object encapsulates information about the location, date and address where the video was recorded. */
recordingDetails?: VideoRecordingDetails;
/** The snippet object contains basic details about the video, such as its title, description, and category. */
snippet?: VideoSnippet;
/** The statistics object contains statistics about the video. */
statistics?: VideoStatistics;
/** The status object contains information about the video's uploading, processing, and privacy statuses. */
status?: VideoStatus;
/**
* The suggestions object encapsulates suggestions that identify opportunities to improve the video quality or the metadata for the uploaded video. This data can only be retrieved by
* the video owner.
*/
suggestions?: VideoSuggestions;
/** The topicDetails object encapsulates information about Freebase topics associated with the video. */
topicDetails?: VideoTopicDetails;
} What surprises me is that every field is possibly This might be a separate issue, but do you have any further guidance on how to approach defining types for my scenario? I'm not a fan of what I'm currently planning to do, but I'm not sure what else I can do except create these types myself? Much thanks in advance again. |
They say "Instead of remote code, we recommend the use of remote configuration files", so you could include
Yeah, I feel your pain. I'm pretty sure that videos from /*...*/
"videos": {
"methods": {
"insert": {
"response": {
"$ref": "Video"
},
"request": {
"$ref": "Video"
},
"id": "youtube.videos.insert"
/*...*/ As you can see, it accepts the same In order for a parameter to be non-undefined it has to have /*...*/
"rate": {
"path": "youtube/v3/videos/rate",
"parameters": {
"id": {
"required": true,
"type": "string",
"location": "query"
},
"rating": {
"required": true,
"type": "string",
/*...*/
However if we take a look at the `id` from `Video`, we'll notice `"annotations"`:
```json5
/*...*/
"id": {
"type": "string",
"description": "The ID that YouTube uses to uniquely identify the video.",
"annotations": {
"required": ["youtube.videos.update"]
}
},
/*...*/ We could probably get some use of it, but it'll probably require creating a separate interface for that method... Or using something like
I see 3 possible approaches for you:
Hope it helps! |
Thanks a lot @Maxim-Mazurok! you're doing gods work in helping me understand this jungle. I'm not a fan of creating a fork of Regarding your three proposals:
interface VideoListResponse {
items?: Video[];
} All of the following fields of interface Video {
id?: string;
contentDetails?: VideoContentDetails;
snippet?: VideoSnippet;
} which goes deeper into: interface VideoContentDetails {
duration?: string;
} and: interface VideoSnippet {
description?: string;
} None of the fields above will probably ever be I suppose I can extend these interfaces with How do I access the interfaces when extending though? gapi.client.youtube.VideoListResponse // Property 'VideoListResponse' does not exist on type 'typeof youtube'. One last thing is that I noticed that when I fetch Comment Threads for a video that has its comment section disabled, I get a response such like: {
"error": {
"code": 403,
"message": "The video identified by the <code><a href=\"/youtube/v3/docs/commentThreads/list#videoId\">videoId</a></code> parameter has disabled comments.",
"errors": [
{
"message": "The video identified by the <code><a href=\"/youtube/v3/docs/commentThreads/list#videoId\">videoId</a></code> parameter has disabled comments.",
"domain": "youtube.commentThread",
"reason": "commentsDisabled",
"location": "videoId",
"locationType": "parameter"
}
]
}
} This is not something that I could find an interface for. Is this handled by type definitions found elsewhere? |
Thanks a bunch. It does help! Regarding the non-null assertions, I can see how it does help more than just leaving it to JS with no types :) Regarding the non-accessible gapi.client.youtube.VideoListResponse; // Property 'VideoListResponse' does not exist on type 'typeof youtube'. vs const listResponse: gapi.client.youtube.VideoListResponse = {}; makes a difference. I think it's because TypeScript is looking for runtime code in the first example? Like it's looking for a value and not a type. Regarding
Thanks! I'll create my own interface in the meantime, since it's not too complex. I'll soldier on and see how it goes. Big thanks again Maxim! |
Ah, yes, exactly :)
If you do - please share it in #806 - I might include it in the Feel free to reopen if you'll have further related questions or open a new issue to make it easier for others to find exact answers without having to go through all the comments, cheers! |
I'll take all of this into account. I'll post whatever I come up with in that other thread. Thanks again @Maxim-Mazurok ! |
Hi! I'm sorry if this is written somewhere and I'm just not understanding it, but:
gapi
, but I'd still like the types for the response payload@types/gapi.client.*
, in my case*
beingyoutube-v3
is not available, I'm guessing I need to use this project to generate them somehow? I was thinking to download it as a dev dependency to my project, and then run the compile scripts documented to generate local type definitions. Since this package is not on NPM I suspect I'm thinking about this the wrong way. I was thinking that I could generate them on the fly on my CI serverOnce again, sorry for my confusion. I'm quite new to the TypeScript world so would appreciate any guidance :)
The text was updated successfully, but these errors were encountered: