using a remote schema instead of an action for getBoxProfile

This commit is contained in:
Pacien Boisson
2020-07-28 11:32:00 +02:00
committed by Hammad Jutt
parent af728ac53d
commit 6e0f0c9b66
21 changed files with 119 additions and 76 deletions

View File

@@ -8,12 +8,14 @@ RUN chmod +x /wait
ARG BACKEND_HOST
ARG AUTH_HOOK_PATH=auth-webhook
ARG ACTION_BASE_PATH=actions
ARG REMOTE_SCHEMA_PATH=remote-schemas/graphql
ENV HASURA_GRAPHQL_DEV_MODE false
ENV HASURA_GRAPHQL_ENABLE_TELEMETRY false
ENV HASURA_GRAPHQL_ENABLED_LOG_TYPES startup, http-log, webhook-log, websocket-log, query-log
ENV HASURA_GRAPHQL_AUTH_HOOK http://$BACKEND_HOST/$AUTH_HOOK_PATH
ENV ACTION_BASE_ENDPOINT http://$BACKEND_HOST/$ACTION_BASE_PATH
ENV REMOTE_SCHEMA_ENDPOINT http://$BACKEND_HOST/$REMOTE_SCHEMA_PATH
ENV HASURA_GRAPHQL_MIGRATIONS_DATABASE_ENV_VAR HASURA_GRAPHQL_DATABASE_URL
## Migrations

View File

@@ -1,10 +1,3 @@
type Query {
getBoxProfile (
address: String
): BoxProfile
}
type Mutation {
updateBoxProfile : UpdateBoxProfileResponse
}
@@ -17,13 +10,3 @@ type UpdateBoxProfileResponse {
updatedProfiles : [String!]!
}
type BoxProfile {
ethereumAddress : String
name : String
description : String
location : String
job : String
emoji : String
imageUrl : String
}

View File

@@ -1,22 +1,14 @@
actions:
- name: getBoxProfile
definition:
kind: ""
handler: '{{ACTION_BASE_ENDPOINT}}/getBoxProfile'
permissions:
- role: player
- role: public
- name: updateBoxProfile
definition:
kind: synchronous
handler: '{{ACTION_BASE_ENDPOINT}}/updateBoxProfile'
forward_client_headers: true
permissions:
- role: player
- name: updateBoxProfile
definition:
kind: synchronous
handler: '{{ACTION_BASE_ENDPOINT}}/updateBoxProfile'
forward_client_headers: true
permissions:
- role: player
custom_types:
enums: []
input_objects: []
objects:
- name: UpdateBoxProfileResponse
- name: BoxProfile
- name: UpdateBoxProfileResponse
scalars: []

View File

@@ -1 +1,4 @@
[]
- name: backend
definition:
url_from_env: REMOTE_SCHEMA_ENDPOINT
timeout_seconds: 60

View File

@@ -5,6 +5,16 @@
- name: Player
using:
foreign_key_constraint_on: player_id
remote_relationships:
- definition:
remote_field:
getBoxProfile:
arguments:
address: $identifier
hasura_fields:
- identifier
remote_schema: backend
name: boxProfile
select_permissions:
- role: player
permission:

View File

@@ -0,0 +1 @@
declare module 'express-graphql';

View File

@@ -34,7 +34,7 @@ export async function login(client, token, ethAddress) {
query: GetMyAccount,
variables: { eth_address: ethAddress },
})
.then(async (res) => {
.then(async res => {
if (res.data.Account.length === 0) {
throw new Error('Impossible to fetch player, not found.');
}
@@ -46,7 +46,7 @@ export async function login(client, token, ethAddress) {
});
setTokenInStore(token);
})
.catch(async (error) => {
.catch(async error => {
logout(client);
throw error;
});

View File

@@ -47,11 +47,11 @@ export const PlayerDetails: React.FC<{ player: any }> = ({ player }) => {
variables: {
username: usernameInput,
},
}).then((res) => console.log('updated username', res.data));
}).then(res => console.log('updated username', res.data));
}, [usernameInput, updateUsername]);
const updateAccounts = useCallback(() => {
updateBoxProfiles().then((res) =>
updateBoxProfiles().then(res =>
console.log(
'updated verified profiles',
res.data.updateBoxProfile.updatedProfiles,
@@ -72,7 +72,7 @@ export const PlayerDetails: React.FC<{ player: any }> = ({ player }) => {
<div>
<input
value={usernameInput}
onChange={(e) => setUsernameInput(e.target.value)}
onChange={e => setUsernameInput(e.target.value)}
/>
<button type="button" onClick={editUserName}>
Change username

View File

@@ -65,7 +65,7 @@ export function register(config?: Config) {
function registerValidSW(swUrl: string, config?: Config) {
navigator.serviceWorker
.register(swUrl)
.then((registration) => {
.then(registration => {
// eslint-disable-next-line no-param-reassign
registration.onupdatefound = () => {
const installingWorker = registration.installing;
@@ -102,7 +102,7 @@ function registerValidSW(swUrl: string, config?: Config) {
};
};
})
.catch((error) => {
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
@@ -112,7 +112,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
fetch(swUrl, {
headers: { 'Service-Worker': 'script' },
})
.then((response) => {
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
@@ -120,7 +120,7 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then((registration) => {
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
@@ -140,10 +140,10 @@ function checkValidServiceWorker(swUrl: string, config?: Config) {
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready
.then((registration) => {
.then(registration => {
registration.unregister();
})
.catch((error) => {
.catch(error => {
console.error(error.message);
});
}

View File

@@ -14,11 +14,14 @@
"author": "",
"license": "ISC",
"dependencies": {
"@metafam/utils": "1.0.0",
"3box": "^1.18.1",
"@metafam/utils": "1.0.0",
"body-parser": "^1.19.0",
"ethers": "^4.0.46",
"express": "^4.17.1",
"express-graphql": "^0.11.0",
"graphql": "^15.3.0",
"graphql-tools": "^6.0.15",
"node-fetch": "^2.6.0"
},
"devDependencies": {

View File

@@ -1,13 +1,11 @@
import express from 'express';
import { asyncHandlerWrapper } from '../../lib/apiHelpers';
import getBoxProfile from './getBoxProfile/handler';
import { updateBoxProfileHandler } from './updateBoxProfile/handler';
export const actionRoutes = express.Router();
actionRoutes.post('/getBoxProfile', asyncHandlerWrapper(getBoxProfile));
actionRoutes.post('/updateBoxProfile', asyncHandlerWrapper(updateBoxProfileHandler));
actionRoutes.post(
'/updateBoxProfile',
asyncHandlerWrapper(updateBoxProfileHandler),
);

View File

@@ -1,15 +1,5 @@
type Maybe<T> = T | null;
type BoxProfile = {
ethereumAddress: string | null;
name: string | null;
description: string | null;
location: string | null;
job: string | null;
emoji: string | null;
imageUrl: string | null;
};
type UpdateBoxProfileResponse = {
success: boolean;
updatedProfiles: Array<string>;

View File

@@ -1,18 +1,28 @@
import { Request, Response } from 'express';
import Box from '3box';
import config from '../../../config';
import { CONFIG } from '../../../../config';
const handler = async (req: Request, res: Response) => {
interface BoxProfileRequest {
address: string,
}
interface BoxProfileResponse {
ethereumAddress: string | null;
name: string | null;
description: string | null;
location: string | null;
job: string | null;
emoji: string | null;
imageUrl: string | null;
}
const { address } = req.body.input;
export const getBoxProfile = async (_: any, { address }: BoxProfileRequest) => {
const boxProfile = await Box.getProfile(address);
if (Object.keys(boxProfile).length === 0) {
return res.json({});
return {};
}
const parsedProfile: BoxProfile = {
const parsedProfile: BoxProfileResponse = {
ethereumAddress: address,
name: boxProfile.name,
description: boxProfile.description,
@@ -22,7 +32,7 @@ const handler = async (req: Request, res: Response) => {
imageUrl: getProfilePicture(boxProfile),
};
return res.json(parsedProfile);
return parsedProfile;
};
function getProfilePicture(boxProfile: any) {

View File

@@ -0,0 +1,14 @@
import express from 'express';
import { graphqlHTTP } from 'express-graphql';
import { graphqlSchema } from './schema';
export const remoteSchemaRoutes = express.Router();
remoteSchemaRoutes.use(
'/graphql',
graphqlHTTP({
schema: graphqlSchema,
graphiql: true,
}),
);

View File

@@ -0,0 +1,12 @@
import { makeExecutableSchema } from 'graphql-tools';
import { typeDefs } from './typeDefs';
import { getBoxProfile } from './resolvers/getBoxProfile/resolver';
const resolvers = {
Query: {
getBoxProfile,
},
};
export const graphqlSchema = makeExecutableSchema({ typeDefs, resolvers });

View File

@@ -0,0 +1,16 @@
export const typeDefs = `
type Query {
getBoxProfile(address: String!): BoxProfile
}
type BoxProfile {
ethereumAddress : String
name : String
description : String
location : String
job : String
emoji : String
imageUrl : String
}
`;

View File

@@ -2,13 +2,21 @@ import express from 'express';
import { asyncHandlerWrapper } from '../lib/apiHelpers';
import { actionRoutes } from './actions/routes';
import { remoteSchemaRoutes } from './remote-schemas/routes';
import { authHandler } from './auth-webhook/handler';
export const router = express.Router();
router.get('/', function (_, res) {
res.send('pong');
router.get('/', function(_, res) {
res.send('ok');
});
router.get('/healthz', function(_, res) {
res.send('ok');
});
router.get('/auth-webhook', asyncHandlerWrapper(authHandler));
router.use('/actions', actionRoutes);
router.use('/remote-schemas', remoteSchemaRoutes);

View File

@@ -2,7 +2,7 @@ import React from 'react';
import { GlobalStyle, ThemeProvider, theme } from '../src';
import GoogleFontLoader from 'react-google-font-loader';
const ThemeDecorator = (storyFn) => (
const ThemeDecorator = storyFn => (
<ThemeProvider theme={theme}>
<GoogleFontLoader
fonts={[

View File

@@ -16,7 +16,7 @@ export const getStaticProps = async () => {
const Home: React.FC<Props> = ({ pokemon }) => (
<SimpleGrid columns={{ sm: 2, lg: 3 }} spacing={6}>
{pokemon.map((p) => (
{pokemon.map(p => (
<MetaLink as={`/pokemon/${p.name}`} href="pokemon/[name]">
<Box key={p.name}>
<Heading style={{ textTransform: 'capitalize' }}>{p.name}</Heading>

View File

@@ -38,9 +38,10 @@ export const getStaticPaths: GetStaticPaths = async () => {
};
};
export const getStaticProps: GetStaticProps<Props, { name: string }> = async (
context,
) => {
export const getStaticProps: GetStaticProps<
Props,
{ name: string }
> = async context => {
const name = context.params?.name;
const pokemon = await getPokemon(name);