UNPKG

steamwebapi

Version:
532 lines (438 loc) 19.7 kB
/** * steamwebapi * * Unofficial Steam Node.js SDK for interfacing with Steam's Web API * * This is free and unencumbered software released into the public domain. * * Anyone is free to copy, modify, publish, use, compile, sell, or * distribute this software, either in source code form or as a compiled * binary, for any purpose, commercial or non-commercial, and by any * means. * * In jurisdictions that recognize copyright laws, the author or authors * of this software dedicate any and all copyright interest in the * software to the public domain. We make this dedication for the benefit * of the public at large and to the detriment of our heirs and * successors. We intend this dedication to be an overt act of * relinquishment in perpetuity of all present and future rights to this * software under copyright law. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * For more information, please refer to <http://unlicense.org/> * * @author Kennedy Software Solutions Inc. * @version 0.0.4 */ /********************************************************************************************************************** Includes & letiable declaration **********************************************************************************************************************/ // Required modules let XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; // Helper modules let config = require('./config'); let util = require('./util'); let endpoints = require('./endpoints'); // Instance variables let responseFormat = 'json'; let apiKey; /** * Validate parameters * * Does light validation on the provided set of parameters to an API request * * @param parameters {object} The object containing the parameters for the request * @returns {boolean} True if all parameters are valid, else false */ function parametersValid(parameters) { // Iterate through all the provided parameters for (let property in parameters) { // Filter out prototype properties if (parameters.hasOwnProperty(property)) { // Each parameter must be a string if (typeof property !== 'string') { return false; } // Store the value of the property let value = parameters[property]; switch (property.toLowerCase()) { case 'count': case 'maxlength': case 'appid': case 'appid_playing': case 'gameid': if (!util.isNumber(value) || value < 0) { return false; } break; case 'name': if (!util.isArray(value)) { return false; } break; case 'steamids': let steamids = value.split(','); if (steamids.length > 100) { return false; } else { // Iterate through all provided IDs for (let id in steamids) { // Filter prototype properties if (steamids.hasOwnProperty(id)) { if (!util.isNumber(id) || id.length !== 17) { return false; } } } } break; case 'steamid': if (!util.isNumber(value) || value.length !== 17) { return false; } break; case 'relationship': if (config.VALID_RELATIONSHIPS.indexOf(value) < 0) { return false; } break; case 'appids_filter': if (!util.isArray(value)) { return false; } for (let appid in value) { // Filter prototype properties if (value.hasOwnProperty(appid)) { if (!util.isNumber(appid) || appid < 0) { return false; } } } // Special case handling to pass appids_filter as "input_json" parameters['input_json'] = encodeURIComponent(JSON.stringify(value)); delete parameters[property]; break; default: break; } } } return true; } /********************************************************************************************************************** API SDK module exports **********************************************************************************************************************/ /** * This module exports the API helper functions * @module SteamWebAPI */ module.exports = { /** * Set response format * * Sets the default response format for responses from the Steam Web API * * @param newFormat {string} The new preferred response format */ setFormat: function(newFormat) { // If it's valid then set it as the new default if (config.VALID_RESPONSE_FORMATS.includes(newFormat)) { responseFormat = newFormat; } }, /** * Set API Key * * Sets the API key that will be used to validate the API requests * * @param newAPIKey {string} The new API key to use * @returns {boolean} If this function successfully set the provided API key */ setAPIKey: function(newAPIKey) { // Verify the inputted api key is valid let isValidAPIKey = (typeof newAPIKey === 'string' && newAPIKey.length === 32); // If it's valid then set it as the API Key if (isValidAPIKey) { apiKey = newAPIKey; } return isValidAPIKey; }, /** * Send API request * * Send the specified request to the Steam Web API and execute the callback upon success or failure * * @param method {string} The method name on the Steam Web API * @param parameters {object} An object containing all the required parameters for the API request * @param callback {function} The function to call upon success or failure */ send: function(method, parameters, callback) { // Use XMLHttpRequest for sending requests to the API let request = new XMLHttpRequest(); // Check if attempting to send valid request method to the API if (!(endpoints.hasOwnProperty(method))) { callback({'error': config.METHOD_NOT_EXIST}) return; } // Load the specification for the method let requestSpecification = endpoints[method]; // Check if all required letiables have been provided if (!(typeof parameters === 'object')) { callback({'error': config.PARAMETERS_INVALID_FORMAT}); return; } let requirementsMet = true; let urlParameters = '?'; // If the API method requires a key, check that it has been defined if (requestSpecification.key === true) { if (!(util.isDefined(apiKey))) { callback({'error': config.API_KEY_NOT_SET}); return; } urlParameters += 'key=' + apiKey + '&'; } // Call this validation before checking if meeting requirements for special case handling // (i.e. appids_filter for GetOwnedGames must be formatted as JSON string and passed as "input_json") if (!(parametersValid(parameters))) { callback({'error': config.PARAMETERS_INVALID_VALUE}); } // Iterate through all required letiables from the specification for (let requiredParameter in requestSpecification.parameters) { // Filter out prototype properties if (requestSpecification.parameters.hasOwnProperty(requiredParameter)) { // Check if the provided params have the required letiables if (parameters.hasOwnProperty(requiredParameter)) { requestSpecification[requiredParameter] = parameters[requiredParameter]; urlParameters += requiredParameter + '=' + parameters[requiredParameter] + '&'; } else { // Check if this missing parameter is required if (requestSpecification.parameters[requiredParameter] === true) { callback({'error': config.PARAMETERS_MISSING}); return; } } } } // Remove trailing & from url parameters string urlParameters = urlParameters.substring(0, urlParameters.length - 1); // Set request details request.open('GET', config.STEAM_API_BASE_URL + requestSpecification.category + method + '/' + requestSpecification.version + urlParameters, true); // Handle request response request.onreadystatechange = function () { // Ignore incomplete requests if (!(request.readyState === 4 && request.status === 200)) { return; } try { // Handle the different preferred response types if (responseFormat === 'json') { let jsonObj = JSON.parse(request.responseText); callback(jsonObj); } else if (responseFormat === 'xml') { callback(request.responseXML); } else { callback(request.responseText); } } catch (error) { callback({'error': error}); } }; // Send the request request.send(); }, /****************************************************************************************************************** SDK interfaces ******************************************************************************************************************/ // Pre-built interfaces for the send function for the supported API endpoints /** * Get news for an app ID * * GetNewsForApp returns the latest of a game specified by its appID * * @param appid {int} AppID of the game you want the news of * @param count {int} How many news enties you want to get returned * @param maxLength {int} Maximum length of each news entry * @param callback {function} Function to handle the response */ getNewsForApp: function(appid, count, maxLength, callback) { this.send('GetNewsForApp', { 'appid': appid, 'count': count, 'maxLength': maxLength }, callback); }, /** * Get global achievement percentages for an app ID * * Returns on global achievements overview of a specific game in percentages * * @param gameid {int} AppID of the game you want the percentages of * @param callback {function} Function to handle the response */ getGlobalAchievementPercentagesForApp: function(gameid, callback) { this.send('GetGlobalAchievementPercentagesForApp', { 'gameid': gameid }, callback); }, /** * Get global stats for game * * Get the global stats for the provided achievement names * * @param gameid {int} AppID of the game you want the stats of * @param count {int} Length of the array of global stat names you will be passing * @param name {array} Name of the achievement as defined in Steamworks * @param callback {function} Function to handle the response */ getGlobalStatsForGame: function(gameid, count, name, callback) { this.send('GetGlobalStatsForGame', { 'gameid': gameid, 'count': count, 'name': name }, callback); }, /** * Get player summaries * * Returns basic profile information for a list of 64-bit Steam IDs * * @param steamids {string} Comma-delimited list of 64 bit Steam IDs to return profile information for. Up to * 100 Steam IDs can be requested * @param callback {function} Function to handle the response */ getPlayerSummaries: function(steamids, callback) { this.send('GetPlayerSummaries', { 'steamids': steamids }, callback); }, /** * Get friend list * * Returns the friend list of any Steam user, provided his Steam Community profile visibility is set to "Public" * * @param steamid {string} 64 bit Steam ID to return friend list for * @param relationship {string} Relationship filter. Possibles values: all, friend * @param callback {function} Function to handle the response */ getFriendList: function(steamid, relationship, callback) { this.send('GetFriendList', { 'steamid': steamid, 'relationship': relationship }, callback); }, /** * Get player achievements * * Returns a list of achievements for this user by app id * * @param steamid {string} 64 bit Steam ID to return friend list for * @param appid {int} The ID for the game you're requesting * @param callback {function} Function to handle the response */ getPlayerAchievements: function(steamid, appid, callback) { this.send('GetPlayerAchievements', { 'steamid': steamid, 'appid': appid }, callback); }, /** * Get user stats for game * * Returns a list of achievements for this user by app id * * @param steamid {string} 64 bit Steam ID to return friend list for * @param appid {int} The ID for the game you're requesting * @param callback {function} Function to handle the response */ getUserStatsForGame: function(steamid, appid, callback) { this.send('GetUserStatsForGame', { 'steamid': steamid, 'appid': appid }, callback); }, /** * Get owned games * * GetOwnedGames returns a list of games a player owns along with some playtime information, if the profile is * publicly visible. Private, friends-only, and other privacy settings are not supported unless you are asking for * your own personal details (ie the WebAPI key you are using is linked to the steamid you are requesting). * * @param steamid {string} The SteamID of the account * @param include_appinfo {string} Include game name and logo information in the output. The * default is to return appids only * @param include_played_free_games {boolean} By default, free games like Team Fortress 2 are excluded (as * technically everyone owns them). If include_played_free_games is * set, they will be returned if the player has played them at some * point. This is the same behavior as the games list on the Steam * Community * @param appids_filter {array} You can optionally filter the list to a set of appids. Note that * these cannot be passed as a URL parameter, instead you must use * the JSON format described in * Steam_Web_API#Calling_Service_interfaces. The expected input is * an array of integers (in JSON: "appids_filter: [ 440, 500, 550 ] * " ) * @param callback {function} Function to handle the response */ getOwnedGames: function(steamid, include_appinfo, include_played_free_games, appids_filter, callback) { let parameters = { 'steamid': steamid }; // Optional parameters if (util.isDefined(include_appinfo)) { parameters.include_appinfo = include_appinfo; } if (util.isDefined(include_played_free_games) && util.isDefined(include_played_free_games.length) && include_played_free_games.length > 0) { parameters.include_played_free_games = include_played_free_games; } if (util.isDefined(appids_filter)) { parameters.appids_filter = appids_filter; } this.send('GetOwnedGames', parameters, callback); }, /** * Get recently played games * * GetRecentlyPlayedGames returns a list of games a player has played in the last two weeks, if the profile is * publicly visible. Private, friends-only, and other privacy settings are not supported unless you are asking for * your own personal details (ie the WebAPI key you are using is linked to the steamid you are requesting). * * @param steamid {string} The SteamID of the account * @param count {int} Optionally limit to a certain number of games (the number of games a person has * played in the last 2 weeks is typically very small) * @param callback {function} Function to handle the response */ getRecentlyPlayedGames: function(steamid, count, callback) { let parameters = { 'steamid': steamid }; // Optional parameters if (util.isDefined(count)) { parameters.count = count; } this.send('GetRecentlyPlayedGames', parameters, callback); }, /** * Is playing shared game * * IsPlayingSharedGame returns the original owner's SteamID if a borrowing account is currently playing this game. * If the game is not borrowed or the borrower currently doesn't play this game, the result is always 0. * * @param steamid {string} The SteamID of the account playing * @param appid_playing {int} The AppID of the game currently playing * @param callback {function} Function to handle the response */ isPlayingSharedGame: function(steamid, appid_playing, callback) { this.send('GetUserStatsForGame', { 'steamid': steamid, 'appid_playing': appid_playing }, callback); } };