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 rewards from './rewards'
|
||||
import referrals from './referrals'
|
||||
import price from './price'
|
||||
import { GraphQLJSONObject } from 'graphql-type-json'
|
||||
|
||||
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 search from './search'
|
||||
import { ME } from '../fragments/users'
|
||||
import { getPrice } from '../components/price'
|
||||
import { PRICE } from '../fragments/price'
|
||||
|
||||
export default async function getSSRApolloClient (req, me = null) {
|
||||
const session = req && await getSession({ req })
|
||||
|
@ -47,7 +47,9 @@ export function getGetServerSideProps (query, variables = null, notFoundFunc, re
|
|||
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
|
||||
if (nodata && query) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import upload from './upload'
|
|||
import growth from './growth'
|
||||
import rewards from './rewards'
|
||||
import referrals from './referrals'
|
||||
import price from './price'
|
||||
|
||||
const link = gql`
|
||||
type Query {
|
||||
|
@ -28,4 +29,4 @@ const link = gql`
|
|||
`
|
||||
|
||||
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 { useRouter } from 'next/router'
|
||||
import Link from 'next/link'
|
||||
import { CURRENCY_SYMBOLS, usePrice } from './price'
|
||||
import { usePrice } from './price'
|
||||
import Avatar from './avatar'
|
||||
import BootstrapForm from 'react-bootstrap/Form'
|
||||
import Alert from 'react-bootstrap/Alert'
|
||||
|
@ -38,9 +38,7 @@ function satsMin2Mo (minute) {
|
|||
|
||||
function PriceHint ({ monthly }) {
|
||||
const me = useMe()
|
||||
const price = usePrice()
|
||||
|
||||
const fiatSymbol = CURRENCY_SYMBOLS[me?.fiatCurrency || 'USD']
|
||||
const { price, fiatSymbol } = usePrice()
|
||||
|
||||
if (!price || !monthly) {
|
||||
return null
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import React, { useContext, useEffect, useState } from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import useSWR from 'swr'
|
||||
import { fixedDecimal } from '../lib/format'
|
||||
import { useMe } from './me'
|
||||
|
||||
const fetcher = url => fetch(url).then(res => res.json()).catch()
|
||||
import { PRICE } from '../fragments/price'
|
||||
|
||||
export const PriceContext = React.createContext({
|
||||
price: null
|
||||
price: null,
|
||||
fiatSymbol: null
|
||||
})
|
||||
|
||||
export const CURRENCY_SYMBOLS = {
|
||||
|
@ -20,24 +20,18 @@ export const CURRENCY_SYMBOLS = {
|
|||
ZAR: 'R '
|
||||
}
|
||||
|
||||
const endpoint = (fiat) => `https://api.coinbase.com/v2/prices/BTC-${fiat ?? 'USD'}/spot`
|
||||
|
||||
export async function getPrice (fiat) {
|
||||
const data = await fetcher(endpoint(fiat))
|
||||
return data?.data?.amount
|
||||
export function usePrice () {
|
||||
return useContext(PriceContext)
|
||||
}
|
||||
|
||||
export function PriceProvider ({ price, children }) {
|
||||
const me = useMe()
|
||||
const { data } = useSWR(
|
||||
endpoint(me?.fiatCurrency),
|
||||
fetcher,
|
||||
{
|
||||
refreshInterval: 30000
|
||||
})
|
||||
const fiatCurrency = me?.fiatCurrency;
|
||||
const { data } = useQuery(PRICE, { variables: { fiatCurrency }, pollInterval: 30000, fetchPolicy: 'cache-and-network' })
|
||||
|
||||
const contextValue = {
|
||||
price: data?.data?.amount || price
|
||||
price: data?.price || price,
|
||||
fiatSymbol: CURRENCY_SYMBOLS[fiatCurrency] || '$'
|
||||
}
|
||||
|
||||
return (
|
||||
|
@ -47,19 +41,12 @@ export function PriceProvider ({ price, children }) {
|
|||
)
|
||||
}
|
||||
|
||||
export function usePrice () {
|
||||
const { price } = useContext(PriceContext)
|
||||
return price
|
||||
}
|
||||
|
||||
export default function Price () {
|
||||
const [asSats, setAsSats] = useState(undefined)
|
||||
useEffect(() => {
|
||||
setAsSats(localStorage.getItem('asSats'))
|
||||
}, [])
|
||||
const price = usePrice()
|
||||
const me = useMe()
|
||||
const fiatSymbol = CURRENCY_SYMBOLS[me?.fiatCurrency || 'USD']
|
||||
const { price, fiatSymbol } = usePrice()
|
||||
|
||||
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