0

I'm currently working on creating a Firebase Cloud Function that retrieve a list of books from the NYTimes API and grabs some additional information from the Google Books API. By using the following URL : "https://www.googleapis.com/books/v1/volumes?q=isbn:&key=" I'm able to retrieve books' details based on an ISBN.

My FREE quota for Google Books API is 1000 request per day and 100 request every 100 seconds per user. I'm only sending 15 requests and my current quota is below 200.

My key is restricted only to be used with Google Books API and it could be use from anywhere (iOS, web, android...etc)

After building the function I'm testing everything locally and data gets populated correctly although once I deploy the function on firebase I get a 403 status code when trying to access to the API.

Unfortunately I'm not getting more details about the error. It just this:

{ Error: Request failed with status code 403
    at createError (/user_code/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/user_code/node_modules/axios/lib/core/settle.js:18:12)
    at IncomingMessage.handleStreamEnd (/user_code/node_modules/axios/lib/adapters/http.js:201:11)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:80:11)
    at process._tickDomainCallback (internal/process/next_tick.js:128:9)
  config: 
   { adapter: [Function: httpAdapter],
     transformRequest: { '0': [Function: transformRequest] },
     transformResponse: { '0': [Function: transformResponse] },
     timeout: 0,
     xsrfCookieName: 'XSRF-TOKEN',
     xsrfHeaderName: 'X-XSRF-TOKEN',
     maxContentLength: -1,
     validateStatus: [Function: validateStatus],
     headers: 
      { Accept: 'application/json, text/plain, */*',
        'User-Agent': 'axios/0.18.0' },
     method: 'get',
     url: 'https://www.googleapis.com/books/v1/volumes?q=isbn:0525520384&key=##########’,
     data: undefined },
  request: 
   ClientRequest {
     domain: null,
     _events: 
      { socket: [Function],
        abort: [Function],
        aborted: [Function],
        error: [Function],
        timeout: [Function],
        prefinish: [Function: requestOnPrefinish] },
     _eventsCount: 6,
     _maxListeners: undefined,
     output: [],
     outputEncodings: [],
     outputCallbacks: [],
     outputSize: 0,
     writable: true,
     _last: true,
     upgrading: false,
     chunkedEncoding: false,
     shouldKeepAlive: false,
     useChunkedEncodingByDefault: false,
     sendDate: false,
     _removedHeader: {},
     _contentLength: 0,
     _hasBody: true,
     _trailer: '',
     finished: true,
     _headerSent: true,
     socket: 
      TLSSocket {
        _tlsOptions: [Object],
        _secureEstablished: true,
        _securePending: false,
        _newSessionPending: false,
        _controlReleased: true,
        _SNICallback: null,
        servername: null,
        npnProtocol: false,
        alpnProtocol: false,
        authorized: true,
        authorizationError: null,
        encrypted: true,
        _events: [Object],
        _eventsCount: 10,
        connecting: false,
        _hadError: false,
        _handle: null,
        _parent: null,
        _host: 'www.googleapis.com',
        _readableState: [Object],
        readable: false,
        domain: null,
        _maxListeners: undefined,
        _writableState: [Object],
        writable: false,
        allowHalfOpen: false,
        destroyed: true,
        _bytesDispatched: 210,
        _sockname: null,
        _pendingData: null,
        _pendingEncoding: '',
        server: undefined,
        _server: null,
        ssl: null,
        _requestCert: true,
        _rejectUnauthorized: true,
        parser: null,
        _httpMessage: [Circular],
        read: [Function],
        _consuming: true,
        write: [Function: writeAfterFIN],
        _idleNext: null,
        _idlePrev: null,
        _idleTimeout: -1 },
     connection: 
      TLSSocket {
        _tlsOptions: [Object],
        _secureEstablished: true,
        _securePending: false,
        _newSessionPending: false,
        _controlReleased: true,
        _SNICallback: null,
        servername: null,
        npnProtocol: false,
        alpnProtocol: false,
        authorized: true,
        authorizationError: null,
        encrypted: true,
        _events: [Object],
        _eventsCount: 10,
        connecting: false,
        _hadError: false,
        _handle: null,
        _parent: null,
        _host: 'www.googleapis.com',
        _readableState: [Object],
        readable: false,
        domain: null,
        _maxListeners: undefined,
        _writableState: [Object],
        writable: false,
        allowHalfOpen: false,
        destroyed: true,
        _bytesDispatched: 210,
        _sockname: null,
        _pendingData: null,
        _pendingEncoding: '',
        server: undefined,
        _server: null,
        ssl: null,
        _requestCert: true,
        _rejectUnauthorized: true,
        parser: null,
        _httpMessage: [Circular],
        read: [Function],
        _consuming: true,
        write: [Function: writeAfterFIN],
        _idleNext: null,
        _idlePrev: null,
        _idleTimeout: -1 },
     _header: 'GET /books/v1/volumes?q=isbn:0525520384&key=##### HTTP/1.1\r\nAccept: application/json, text/plain, */*\r\nUser-Agent: axios/0.18.0\r\nHost: www.googleapis.com\r\nConnection: close\r\n\r\n',
     _headers: 
      { accept: 'application/json, text/plain, */*',
        'user-agent': 'axios/0.18.0',
        host: 'www.googleapis.com' },
     _headerNames: { accept: 'Accept', 'user-agent': 'User-Agent', host: 'Host' },
     _onPendingData: null,
     agent: 
      Agent {
        domai
rudymatos
  • 321
  • 1
  • 3
  • 12

3 Answers3

3

I was facing a similar issue. I was able to sucessfully use the Books API when I was running my functions locally (ie. firebase serve). But when I deployed the functions and the app to hosting, I was getting a mysterious 403: Forbidden error.

I tried several things so I'm not sure which helped so I'll just list everything:

  • Updated firebase functions: npm install --save firebase-functions@latest
  • Switched from using node-fetch to using axios for calling the API
  • Add country to URL: https://www.googleapis.com/books/v1/volumes?country=US&q=insubject:${randomWord}&key=${functions.config().books.api.key}
  • Regenerated Google Books API key
  • Removed all Application restrictions in the google cloud console

Hope this helps somebody out there because I was wrestling with it for hours!

April Polubiec
  • 598
  • 5
  • 13
  • Is there a way to restrict the api key to only http cloud function? I don't want to remove all application restriciton – Leonardo Rick Mar 06 '21 at 20:07
  • 1
    Wow, thanks for this. It was the country parameter. Calling the API locally worked fine, but calling from a function gave me a 403. Only started working in the function when I added the country parameter which I can't seem to find documentation of. – Dracorex Mar 11 '21 at 04:12
2

By adding more restriction to the key (HTTP Only) and adding a referer header to my request and finally adding a country code to the end of the request my original issue is now gone.

Note: Referer should match the http restriction value on your key.

Final URL :

https://www.googleapis.com/books/v1/volumes?q=isbn:#book-isbn#&key=#app-key#&country=US

rudymatos
  • 321
  • 1
  • 3
  • 12
0

Google books apis need to know the country to show relevant books. either pass it through the country parameter or you can use the client to call the api's directly.