Git Product home page Git Product logo

blizzapi's Introduction

BlizzAPI logo

BlizzAPI

npm (latest) Build status codecov

Flexible and feature-rich JavaScript / TypeScript library for easy access to Blizzard Battle.net APIs.

Install

npm install blizzapi

Quick start

const { BlizzAPI } = require("blizzapi");

/**
 * Or using TypeScript:
 * import { BlizzAPI } from 'blizzapi';
 */

const api = new BlizzAPI({
  region: "us",
  clientId: "client id",
  clientSecret: "client secret",
});

const data = await api.query("/path/to/endpoint");

console.log(data);

Manual build

git clone https://github.com/blizzapi/blizzapi.git
cd blizzapi
npm install
npm run build

Documentation & examples

Contributions

Contributions of any kind are welcome.

You can contribute to BlizzAPI by:

  • submiting a bug report or a feature suggestion
  • improving documentation either within the project itself or in the doc site repository
  • submitting pull requests

Before contributing be sure to read Contributing Guidelines and Code of Conduct.

Contributors

To all who contribute code, improve documentation, submit issues or feature requests - thank you for making BlizzAPI even better!

We maintain an AUTHORS file where we keep a list of all project contributors. Please consider adding your name there with your next PR.

License

Licensed under MIT License. See LICENSE for more information.

Legal

This project is not authored, affiliated or endorsed in any way by Blizzard Entertainment.

Battle.net and Blizzard Entertainment are trademarks or registered trademarks of Blizzard Entertainment, Inc. in the U.S. and/or other countries.

blizzapi's People

Contributors

alexzedim avatar dependabot[bot] avatar greenkeeper[bot] avatar lwojcik avatar snyk-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

blizzapi's Issues

'Axios is not defined' on BlizzApi().query

When trying to use a new instance of the BlizzApi object, once I fire my method I get a return of 'axios is not defined'

Quick snippet of usage:

const api = new BlizzAPI({
            region: requestBody.region,
            clientId: this._apiAuthTokens.clientId,
            clientSecret: this._apiAuthTokens.clientSecret
        })

const data = await api.query(...) // api url - axios not defined here.

For context, I'm using the wrapper in a NextJS TypeScript project where I'm already making sure to check for SSR by using the effect hook. I've checked peer-dependencies and the blizzapi package.json includes axios ^0.21.2. Axios also exists within the node_modules of blizzapi.

Are there type definitions I'd need to install still or is the wrapper not suited for use within a typescript project (which I doubt)?

Requesting a different region?

Hey, is it currently possible to change the region for different queries from the one you initialized the BlizzAPI instance with? This behaviour is fine for static data, but for example if I wanted to get WoW auction house or token prices for different regions I'd have to initialize a new client everytime I request a different region. US access tokens work for EU/KR... etc. as well, so I think this should be possible to do (maybe it is already, couldn't find anything in the code though).

If not, I'd maybe propose either a region parameter on the query function that overrides the BlizzAPI instance region if set, or have a .setRegion() function on the BlizzAPI class.

Action required: Greenkeeper could not be activated 🚨

🚨 You need to enable Continuous Integration on Greenkeeper branches of this repository. 🚨

To enable Greenkeeper, you need to make sure that a commit status is reported on all branches. This is required by Greenkeeper because it uses your CI build statuses to figure out when to notify you about breaking changes.

Since we didn’t receive a CI status on the greenkeeper/initial branch, it’s possible that you don’t have CI set up yet. We recommend using Travis CI, but Greenkeeper will work with every other CI service as well.

If you have already set up a CI for this repository, you might need to check how it’s configured. Make sure it is set to run on all new branches. If you don’t want it to run on absolutely every branch, you can whitelist branches starting with greenkeeper/.

Once you have installed and configured CI on this repository correctly, you’ll need to re-trigger Greenkeeper’s initial pull request. To do this, please click the 'fix repo' button on account.greenkeeper.io.

getting access_token expiration data

blizz api returns a response similar to:

Example CURL request
curl -u {client_id}:{client_secret} -d grant_type=client_credentials https://oauth.battle.net/token
Expected response
{"access_token": "USVb1nGO9kwQlhNRRnI4iWVy2UV5j7M6h7", "token_type": "bearer", "expires_in": 86399, "scope": "example.scope"}

blizz api (https://blizzapi.lukem.net/docs/usage/getting-access-token.html) getAccessToken() just returns the token but I also need the expires_in data to store and use in my internal authentication mechanisms.

How can I get the expires_in?

does BlizzAPI.validateAccessToken() return the data?

Cyrillic letters are not applicable for query method as arguments

Hi!

I just installed your library instead of Blizzard.js that is seems no longer maintenanced. So it works fine, until you try to request anything via query method with arguments that consist cyrillic letters. Even if I use encodeURI method.

You could try it yourself, with the code like this:

        const api = new BlizzAPI({
            region: 'eu',
            clientId: blizzardKeys._id,
            clientSecret: blizzardKeys.secret
        });
        let uri = encodeURI(`/wow/character/${arg_realm}/${arg_name}`);
        const data = await api.query(uri);
        console.log(data);

where realm is гордунни, and name equals инициатива or anything like this.

And I also checked the docs for query method, and haven't found anything that helps me to understand how to request a specific fields for character or any other endpoint that supports it.

Replace relative imports with absolute imports

timeout fix

I have found a little blind spot in the query.ts code, relevant to the timeout param.

For somehow, the timeout param was ignored by some queries. So even, if it was predetermined, it gives an error with the default timeout.

  let market = await api.query(`/data/wow/connected-realm/${_id.connected_realm_id}/auctions`, {
    timeout: 30000,
    params: { locale: 'en_GB' },
    headers: {
      'Battlenet-Namespace': 'dynamic-eu',
      'If-Modified-Since': _id.timestamp
    }
  }).catch(error => {
    console.info(`E,${_id.connected_realm_id}:${error}`);
    return void 0;
  });

timeout10s

So, I have made a PR, and this time, all Travis and Codecov checks are green-lighting, so as I guess, it won't a problem to add it.

onAccessTokenExpired() not called if access token is expired

https://blizzapi.lukem.net/docs/usage/custom-access-token.html#parameters says that if we enable validateAccessTokenOnEachQuery,
the blizzapi should be calling

onAccessTokenExpired: () => { /* do something */ },

but from my tests, even if i see expired token in api response

{ error: 'access_token_invalid' }

the onAccessTokenExpired event is not called.

      this.api_clients[region.code] = new BlizzAPI({
        region: region.code as RegionName,
        accessToken: access_token,
        validateAccessTokenOnEachQuery: true,
        refreshExpiredAccessToken: false,
        onAccessTokenExpired: () => {
          console.dir("onAccessTokenExpired");
        },
      });

any ideas?

Error: Request failed with status code 404

Hello. I got from BlizzardAPI error 404. Not all time.

Example response object:

{
  config: {
    url: 'https://us.api.blizzard.com/data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU',
    method: 'get',
    headers: {
      Accept: 'application/json, text/plain, */*',
      Authorization: 'Bearer US44blOychwNcckTfGk02C99lY9eHUNBcm',
      'User-Agent': 'axios/0.21.1'
    },
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 10000,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    validateStatus: [Function: validateStatus],
    data: undefined
  },
  request: ClientRequest {
    _events: [Object: null prototype] {
      socket: [Function],
      abort: [Function],
      aborted: [Function],
      connect: [Function],
      error: [Function],
      timeout: [Function],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 7,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    useChunkedEncodingByDefault: false,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: 0,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    socket: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: true,
      _SNICallback: null,
      servername: 'us.api.blizzard.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'us.api.blizzard.com',
      _readableState: [ReadableState],
      readable: true,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: false,
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular],
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(asyncId)]: 54,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    connection: TLSSocket {
      _tlsOptions: [Object],
      _secureEstablished: true,
      _securePending: false,
      _newSessionPending: false,
      _controlReleased: true,
      secureConnecting: true,
      _SNICallback: null,
      servername: 'us.api.blizzard.com',
      alpnProtocol: false,
      authorized: true,
      authorizationError: null,
      encrypted: true,
      _events: [Object: null prototype],
      _eventsCount: 10,
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: 'us.api.blizzard.com',
      _readableState: [ReadableState],
      readable: true,
      _maxListeners: undefined,
      _writableState: [WritableState],
      writable: false,
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: undefined,
      _server: null,
      ssl: [TLSWrap],
      _requestCert: true,
      _rejectUnauthorized: true,
      parser: null,
      _httpMessage: [Circular],
      [Symbol(res)]: [TLSWrap],
      [Symbol(verified)]: true,
      [Symbol(pendingSession)]: null,
      [Symbol(asyncId)]: 54,
      [Symbol(kHandle)]: [TLSWrap],
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 0,
      [Symbol(kBytesWritten)]: 0,
      [Symbol(connect-options)]: [Object]
    },
    _header: 'GET /data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Authorization: Bearer US44blOychwNcckTfGk02C99lY9eHUNBcm\r\n' +
      'User-Agent: axios/0.21.1\r\n' +
      'Host: us.api.blizzard.com\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _onPendingData: [Function: noopPendingOutput],
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 443,
      protocol: 'https:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      maxCachedSessions: 100,
      _sessionCache: [Object],
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'GET',
    insecureHTTPParser: undefined,
    path: '/data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      readable: false,
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [TLSSocket],
      connection: [TLSSocket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      headers: [Object],
      rawHeaders: [Array],
      trailers: {},
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 404,
      statusMessage: 'Not Found',
      client: [TLSSocket],
      _consuming: false,
      _dumped: false,
      req: [Circular],
      responseUrl: 'https://us.api.blizzard.com/data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU',
      redirects: [],
      [Symbol(kCapture)]: false
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    _redirectable: Writable {
      _writableState: [WritableState],
      writable: true,
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _ended: true,
      _ending: true,
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 0,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function],
      _currentRequest: [Circular],
      _currentUrl: 'https://us.api.blizzard.com/data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU',
      _timeout: Timeout {
        _idleTimeout: -1,
        _idlePrev: null,
        _idleNext: null,
        _idleStart: 4005,
        _onTimeout: null,
        _timerArgs: undefined,
        _repeat: null,
        _destroyed: true,
        [Symbol(refed)]: true,
        [Symbol(asyncId)]: 60,
        [Symbol(triggerId)]: 57
      },
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      authorization: [Array],
      'user-agent': [Array],
      host: [Array]
    }
  },
  response: {
    status: 404,
    statusText: 'Not Found',
    headers: {
      'content-length': '0',
      'x-trace-traceid': '138df95e-232d-38c1-9567-836152607aa6',
      'x-trace-spanid': '16756e92-e255-b8d0-dfd8-fa164c0f4436',
      'x-trace-parentspanid': '16756e92-e255-b8a0-dfd8-fa164c0f4436',
      'x-frame-options': 'SAMEORIGIN',
      'x-content-type-options': 'nosniff',
      connection: 'keep-alive'
    },
    config: {
      url: 'https://us.api.blizzard.com/data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU',
      method: 'get',
      headers: [Object],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 10000,
      adapter: [Function: httpAdapter],
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      validateStatus: [Function: validateStatus],
      data: undefined
    },
    request: ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 7,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      useChunkedEncodingByDefault: false,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: 0,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      socket: [TLSSocket],
      connection: [TLSSocket],
      _header: 'GET /data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Authorization: Bearer US44blOychwNcckTfGk02C99lY9eHUNBcm\r\n' +
        'User-Agent: axios/0.21.1\r\n' +
        'Host: us.api.blizzard.com\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _onPendingData: [Function: noopPendingOutput],
      agent: [Agent],
      socketPath: undefined,
      method: 'GET',
      insecureHTTPParser: undefined,
      path: '/data/wow/playable-specialization/265?namespace=static-us&locale=ru_RU',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    data: ''
  },
  isAxiosError: true,
  toJSON: [Function: toJSON]
}

Various typing improvements

  • use enum types instead of generic strings for constant arrays
  • seek improvements in strict typing (better typing of responses maybe?)
  • research new features from new TS releases

TypeError: blizzapi_1.default is not a constructor

I start to implement Nest (which is quite popular nowadays) and using it with blizzapi.

The code is fine and pretty simple, if you are familiar with it:

import BlizzAPI from 'blizzapi';
// (2) import * as BlizzAPI from 'blizzapi';

@Injectable()
export class AppService {
  private readonly logger = new Logger(
    RealmsService.name, true,
  );

  // (1)
  private BNet: BlizzAPI // (2) BlizzAPI .default

  constuctor () {
    this.test()
  }

  async test() {
        this.BNet = new BlizzAPI({ // (2) BlizzAPI .default
          region: 'eu',
          clientId: id,
          clientSecret: secret,
          accessToken: token
      });
     ...other logic
  }
}

Unfortunately, I have found a strange error with import/export.

It doesn't matter, what kind of import I will be using: 1.import BlizzAPI from 'blizzapi'; or 2. import * as BlizzAPI from 'blizzapi'; both of them gives the same error, relevant with constuctor for default.

I am not so good with TS, and especially its import/export options. Of course, I already have already figure out the solution to the problem: Error: *.default is not a constructor

Also, I have tried dig to the root of the problem and trying to make some changes in */dist/index.d.ts according to SO, but it seems that following any other options, according to IDE doesn't bring a solution:

image

or export default class BlizzAPI;

As I understand it, it requires some small fix within the export file. I'll be more than welcome to make a PR, at the end of next week probably, as soon as I discover all the caveats of it.

Problem with Battlenet-Namespace header and statiс or dynamic endpoints

There is a problem with Battlenet-Namespace header and it values, like:

  • static-{region}
  • dynamic-{region}
  • profile-{region}

I don't know about SC2 and Diablo endpoints, but for world of warcraft this problem is very important.

As for now, the namespace parameter always should be defined in url or header. So the correct query example for world of warcraft character isn't BnetApi.query('/wow/character/гордунни/инициатива') but BnetApi.query('/wow/character/гордунни/инициатива?namespace=profile-eu') so according to that, I have made pull request and updated documentation.

But the actual problem, that different world of warcraft endpoints, have a different namespace types, some of them are static, another is dynamic. I am not a big fan of such arcitecture of battlenet-api-wrapper that I inherit from QuadDamn, so I prefer to use blizzapi for my site instead, but without the timeout and namespaces fix I can do nothing about it.

The real case starts when you are dealing with dynamic endpoints, especially auctions and guild-roster, as long as Blizzard makes support for If-Modified-Since headers when you need to check have the endpoint data been modified you don't need to request for the data itself, you can add an additional header to the request and if doesn't modify on the server-side, you'll receive a 304 response.

So, with blizzapi it's impossible to achieve. I can make a fork (as I usually do and made my own fix, it's not a problem) but I'd like to ask you, @lwojcik first. What architecture solution would you propose?

Something like: `query('/wow/character/гордунни/инициатива', 'if-modified-since') or anything else?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.