Add proxy with cache for coinbase API requests (#226)
This commit is contained in:
parent
670f071177
commit
4ab66a67ae
|
@ -11,7 +11,8 @@ import growth from './growth'
|
||||||
import search from './search'
|
import search from './search'
|
||||||
import rewards from './rewards'
|
import rewards from './rewards'
|
||||||
import referrals from './referrals'
|
import referrals from './referrals'
|
||||||
|
import price from './price'
|
||||||
import { GraphQLJSONObject } from 'graphql-type-json'
|
import { GraphQLJSONObject } from 'graphql-type-json'
|
||||||
|
|
||||||
export default [user, item, message, wallet, lnurl, notifications, invite, sub,
|
export default [user, item, message, wallet, lnurl, notifications, invite, sub,
|
||||||
upload, growth, search, rewards, referrals, { JSONObject: GraphQLJSONObject }]
|
upload, growth, search, rewards, referrals, price, { JSONObject: GraphQLJSONObject }]
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
const cache = new Map();
|
||||||
|
const expiresIn = 30000; // in milliseconds
|
||||||
|
|
||||||
|
async function getPrice(fiat) {
|
||||||
|
fiat ??= 'USD';
|
||||||
|
if (cache.has(fiat)) {
|
||||||
|
const { price, createdAt } = cache.get(fiat)
|
||||||
|
const expired = createdAt + expiresIn < Date.now()
|
||||||
|
if (!expired) {
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const url = `https://api.coinbase.com/v2/prices/BTC-${fiat}/spot`;
|
||||||
|
const price = await fetch(url)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((body) => parseFloat(body.data.amount))
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
return -1;
|
||||||
|
});
|
||||||
|
cache.set(fiat, { price, createdAt: Date.now() });
|
||||||
|
return price;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
Query: {
|
||||||
|
price: async (parent, { fiatCurrency }, ctx) => {
|
||||||
|
const price = await getPrice(fiatCurrency);
|
||||||
|
return price;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -10,7 +10,7 @@ import { print } from 'graphql'
|
||||||
import lnd from './lnd'
|
import lnd from './lnd'
|
||||||
import search from './search'
|
import search from './search'
|
||||||
import { ME } from '../fragments/users'
|
import { ME } from '../fragments/users'
|
||||||
import { getPrice } from '../components/price'
|
import { PRICE } from '../fragments/price'
|
||||||
|
|
||||||
export default async function getSSRApolloClient (req, me = null) {
|
export default async function getSSRApolloClient (req, me = null) {
|
||||||
const session = req && await getSession({ req })
|
const session = req && await getSession({ req })
|
||||||
|
@ -47,7 +47,9 @@ export function getGetServerSideProps (query, variables = null, notFoundFunc, re
|
||||||
query: ME
|
query: ME
|
||||||
})
|
})
|
||||||
|
|
||||||
const price = await getPrice(me?.fiatCurrency)
|
const { data: { price } } = await client.query({
|
||||||
|
query: PRICE, variables: { fiatCurrency: me?.fiatCurrency }
|
||||||
|
})
|
||||||
|
|
||||||
// we want to use client-side cache
|
// we want to use client-side cache
|
||||||
if (nodata && query) {
|
if (nodata && query) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ import upload from './upload'
|
||||||
import growth from './growth'
|
import growth from './growth'
|
||||||
import rewards from './rewards'
|
import rewards from './rewards'
|
||||||
import referrals from './referrals'
|
import referrals from './referrals'
|
||||||
|
import price from './price'
|
||||||
|
|
||||||
const link = gql`
|
const link = gql`
|
||||||
type Query {
|
type Query {
|
||||||
|
@ -28,4 +29,4 @@ const link = gql`
|
||||||
`
|
`
|
||||||
|
|
||||||
export default [link, user, item, message, wallet, lnurl, notifications, invite,
|
export default [link, user, item, message, wallet, lnurl, notifications, invite,
|
||||||
sub, upload, growth, rewards, referrals]
|
sub, upload, growth, rewards, referrals, price]
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { gql } from 'apollo-server-micro'
|
||||||
|
|
||||||
|
export default gql`
|
||||||
|
extend type Query {
|
||||||
|
price(fiatCurrency: String): Float
|
||||||
|
}
|
||||||
|
`
|
|
@ -9,7 +9,7 @@ import styles from '../styles/post.module.css'
|
||||||
import { useLazyQuery, gql, useMutation } from '@apollo/client'
|
import { useLazyQuery, gql, useMutation } from '@apollo/client'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { CURRENCY_SYMBOLS, usePrice } from './price'
|
import { usePrice } from './price'
|
||||||
import Avatar from './avatar'
|
import Avatar from './avatar'
|
||||||
import BootstrapForm from 'react-bootstrap/Form'
|
import BootstrapForm from 'react-bootstrap/Form'
|
||||||
import Alert from 'react-bootstrap/Alert'
|
import Alert from 'react-bootstrap/Alert'
|
||||||
|
@ -38,9 +38,7 @@ function satsMin2Mo (minute) {
|
||||||
|
|
||||||
function PriceHint ({ monthly }) {
|
function PriceHint ({ monthly }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const price = usePrice()
|
const { price, fiatSymbol } = usePrice()
|
||||||
|
|
||||||
const fiatSymbol = CURRENCY_SYMBOLS[me?.fiatCurrency || 'USD']
|
|
||||||
|
|
||||||
if (!price || !monthly) {
|
if (!price || !monthly) {
|
||||||
return null
|
return null
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import React, { useContext, useEffect, useState } from 'react'
|
import React, { useContext, useEffect, useState } from 'react'
|
||||||
|
import { useQuery } from '@apollo/client'
|
||||||
import { Button } from 'react-bootstrap'
|
import { Button } from 'react-bootstrap'
|
||||||
import useSWR from 'swr'
|
|
||||||
import { fixedDecimal } from '../lib/format'
|
import { fixedDecimal } from '../lib/format'
|
||||||
import { useMe } from './me'
|
import { useMe } from './me'
|
||||||
|
import { PRICE } from '../fragments/price'
|
||||||
const fetcher = url => fetch(url).then(res => res.json()).catch()
|
|
||||||
|
|
||||||
export const PriceContext = React.createContext({
|
export const PriceContext = React.createContext({
|
||||||
price: null
|
price: null,
|
||||||
|
fiatSymbol: null
|
||||||
})
|
})
|
||||||
|
|
||||||
export const CURRENCY_SYMBOLS = {
|
export const CURRENCY_SYMBOLS = {
|
||||||
|
@ -20,24 +20,18 @@ export const CURRENCY_SYMBOLS = {
|
||||||
ZAR: 'R '
|
ZAR: 'R '
|
||||||
}
|
}
|
||||||
|
|
||||||
const endpoint = (fiat) => `https://api.coinbase.com/v2/prices/BTC-${fiat ?? 'USD'}/spot`
|
export function usePrice () {
|
||||||
|
return useContext(PriceContext)
|
||||||
export async function getPrice (fiat) {
|
|
||||||
const data = await fetcher(endpoint(fiat))
|
|
||||||
return data?.data?.amount
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PriceProvider ({ price, children }) {
|
export function PriceProvider ({ price, children }) {
|
||||||
const me = useMe()
|
const me = useMe()
|
||||||
const { data } = useSWR(
|
const fiatCurrency = me?.fiatCurrency;
|
||||||
endpoint(me?.fiatCurrency),
|
const { data } = useQuery(PRICE, { variables: { fiatCurrency }, pollInterval: 30000, fetchPolicy: 'cache-and-network' })
|
||||||
fetcher,
|
|
||||||
{
|
|
||||||
refreshInterval: 30000
|
|
||||||
})
|
|
||||||
|
|
||||||
const contextValue = {
|
const contextValue = {
|
||||||
price: data?.data?.amount || price
|
price: data?.price || price,
|
||||||
|
fiatSymbol: CURRENCY_SYMBOLS[fiatCurrency] || '$'
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -47,19 +41,12 @@ export function PriceProvider ({ price, children }) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function usePrice () {
|
|
||||||
const { price } = useContext(PriceContext)
|
|
||||||
return price
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Price () {
|
export default function Price () {
|
||||||
const [asSats, setAsSats] = useState(undefined)
|
const [asSats, setAsSats] = useState(undefined)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setAsSats(localStorage.getItem('asSats'))
|
setAsSats(localStorage.getItem('asSats'))
|
||||||
}, [])
|
}, [])
|
||||||
const price = usePrice()
|
const { price, fiatSymbol } = usePrice()
|
||||||
const me = useMe()
|
|
||||||
const fiatSymbol = CURRENCY_SYMBOLS[me?.fiatCurrency || 'USD']
|
|
||||||
|
|
||||||
if (!price) return null
|
if (!price) return null
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import { gql } from '@apollo/client'
|
||||||
|
|
||||||
|
export const PRICE = gql`
|
||||||
|
query price($fiatCurrency: String) {
|
||||||
|
price(fiatCurrency: $fiatCurrency)
|
||||||
|
}`
|
Loading…
Reference in New Issue