steamwebapi
Version:
Steam Web API Node.js SDK
532 lines (438 loc) • 19.7 kB
JavaScript
/**
* 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);
}
};