1+ const got = require ( 'got' ) ;
2+ const compression = require ( "compression" )
3+ const cors = require ( "cors" )
4+ const express = require ( "express" )
5+ const functions = require ( "firebase-functions/v1" )
6+
7+ const config = functions . config ( )
8+ let BASE_URL = "https://pokeapi.co"
9+
10+ if ( process . env . FIREBASE_DEBUG_MODE ) {
11+ BASE_URL = "http://localhost:5000"
12+ } else if ( config . network && config . network . base_url ) {
13+ BASE_URL = config . network . base_url // To retrieve the config run: `firebase functions:config:get --project <PROJECT_ID>`
14+ }
15+
16+ function targetUrlForPath ( path ) {
17+ let target = BASE_URL + "/_gen" + path
18+ if ( ! target . endsWith ( "/" ) ) {
19+ target += "/"
20+ }
21+ return ( target + "index.json" )
22+ }
23+
24+ function paramsOrDefault ( query ) {
25+ return {
26+ offset : parseInt ( query . offset ) || 0 ,
27+ limit : parseInt ( query . limit ) || 20 ,
28+ }
29+ }
30+
31+ function getPageUrl ( path , params ) {
32+ if ( params === null ) {
33+ return null
34+ }
35+ return BASE_URL + path + "?offset=" + params . offset + "&limit=" + params . limit
36+ }
37+
38+ function getPreviousPage ( params ) {
39+ const newPage = {
40+ begin : params . offset - params . limit ,
41+ end : params . offset ,
42+ }
43+
44+ if ( newPage . begin < 0 ) {
45+ newPage . begin = 0
46+ }
47+
48+ // it's a prev page only if we've moved back
49+ if ( newPage . begin < params . offset ) {
50+ return {
51+ offset : newPage . begin ,
52+ limit : newPage . end - newPage . begin ,
53+ }
54+ }
55+
56+ return null
57+ }
58+
59+ function getNextPage ( params , count ) {
60+ const newPage = {
61+ begin : params . offset + params . limit ,
62+ end : params . offset + params . limit * 2 ,
63+ }
64+
65+ if ( newPage . end > count ) {
66+ newPage . end = count
67+ }
68+
69+ // it's a next page only if we've moved forward
70+ if ( newPage . end > params . offset + params . limit ) {
71+ return {
72+ offset : newPage . begin ,
73+ limit : newPage . end - newPage . begin ,
74+ }
75+ }
76+
77+ return null
78+ }
79+
80+ function handleErrors ( reason , req , res ) {
81+ if ( reason . response && reason . response . statusCode ) {
82+ res . set ( 'Cache-Control' , `public, max-age=${ failTtl } , s-maxage=${ failTtl } ` )
83+ res . sendStatus ( reason . response . statusCode )
84+ } else if ( reason . code === 'ETIMEDOUT' ) {
85+ console . error ( `504: ${ reason . name } for ${ req . path } ` )
86+ res . sendStatus ( 504 )
87+ } else {
88+ console . error ( `500: ${ reason . name } for ${ req . path } ` )
89+ res . sendStatus ( 500 )
90+ }
91+ }
92+
93+
94+ const api = express ( )
95+
96+ api . use ( compression ( ) )
97+ api . use ( cors ( ) )
98+
99+ const successTtl = 86400 // 1 day
100+ const failTtl = 432000 // 5 days
101+
102+ const gotConfig = {
103+ timeout : 8000 ,
104+ retry : {
105+ limit : 1 ,
106+ statusCodes : [ 404 , 408 , 413 , 429 , 500 , 502 , 503 , 504 , 521 , 522 , 524 ] , // maybe not needed
107+ } ,
108+ hooks : {
109+ beforeRetry : [
110+ ( options , error , retryCount ) => {
111+ console . log ( `${ error . name } : retrying ${ options . url . pathname } ` )
112+ }
113+ ]
114+ }
115+ }
116+
117+ api . get ( [
118+ "/api/v2/" ,
119+ "/api/v2/:endpoint/:id/" ,
120+ "/api/v2/:endpoint/:id/:extra/"
121+ ] , ( req , res ) => {
122+ got ( targetUrlForPath ( req . path ) , gotConfig )
123+ . json ( )
124+ . then ( json => {
125+ res . set ( 'Cache-Control' , `public, max-age=${ successTtl } , s-maxage=${ successTtl } ` )
126+ res . send ( json )
127+ } )
128+ . catch ( reason => {
129+ handleErrors ( reason , req , res )
130+ } )
131+ } )
132+
133+ api . get ( "/api/v2/:endpoint/" , ( req , res ) => {
134+ got ( targetUrlForPath ( req . path ) , gotConfig )
135+ . json ( )
136+ . then ( json => {
137+ const params = paramsOrDefault ( req . query )
138+ res . set ( 'Cache-Control' , `public, max-age=${ successTtl } , s-maxage=${ successTtl } ` )
139+ res . send (
140+ Object . assign ( json , {
141+ next : getPageUrl ( req . path , getNextPage ( params , json . count ) ) ,
142+ previous : getPageUrl ( req . path , getPreviousPage ( params ) ) ,
143+ results : json . results . slice ( params . offset , params . offset + params . limit )
144+ } )
145+ )
146+ } )
147+ . catch ( reason => {
148+ handleErrors ( reason , req , res )
149+ } )
150+ } )
151+
152+ exports . api_v1functions = functions . https . onRequest ( api )
0 commit comments