mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-24 03:00:09 -04:00
Generate Typesafe SDK for Hasura in Backend (#68)
This commit is contained in:
@@ -5,6 +5,12 @@
|
||||
"rules": {
|
||||
"@typescript-eslint/naming-convention": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["./src/handlers/**/*.ts"],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-module-boundary-types": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -11,3 +11,16 @@ generates:
|
||||
noSchemaStitching: true
|
||||
avoidOptionals: true
|
||||
maybeValue: 'T extends PromiseLike<infer U> ? Promise<U | null> : T | null | undefined'
|
||||
./src/lib/autogen/sdk.ts:
|
||||
schema: '../codegen/schema.graphql'
|
||||
documents:
|
||||
- ./src/handlers/**/(!(*.d)).ts
|
||||
- ./src/handlers/**/*.graphql
|
||||
plugins:
|
||||
- typescript
|
||||
- typescript-operations
|
||||
- typescript-graphql-request
|
||||
- add:
|
||||
content: '/* eslint-disable */'
|
||||
config:
|
||||
immutableTypes: true
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
"dev-ts": "ts-node-dev --exit-child --respawn --transpile-only -- src/index.ts",
|
||||
"typecheck": "yarn build",
|
||||
"precommit": "yarn lint-staged",
|
||||
"generate": "graphql-codegen --config=codegen.yml"
|
||||
"generate": "graphql-codegen --config=codegen.yml",
|
||||
"lintfix": "eslint --fix"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
@@ -23,6 +24,7 @@
|
||||
"express": "^4.17.1",
|
||||
"express-graphql": "^0.11.0",
|
||||
"graphql": "^15.3.0",
|
||||
"graphql-tag": "^2.10.4",
|
||||
"graphql-tools": "^6.0.15",
|
||||
"node-fetch": "^2.6.0",
|
||||
"graphql-request": "^3.0.0-next.4"
|
||||
|
||||
@@ -1,37 +1,7 @@
|
||||
import Box, { VerifiedAccounts } from '3box';
|
||||
import { Request, Response } from 'express';
|
||||
import { gql } from 'graphql-request';
|
||||
|
||||
import { hasuraQuery } from '../../../lib/hasuraHelpers';
|
||||
|
||||
type PlayerResult = {
|
||||
Player: Array<{
|
||||
id: string;
|
||||
ethereum_address: string | null | undefined;
|
||||
}>;
|
||||
};
|
||||
const getPlayerQuery = gql`
|
||||
query GetPlayer($playerId: uuid!) {
|
||||
Player(where: { id: { _eq: $playerId } }) {
|
||||
id
|
||||
ethereum_address
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const upsertAccount = gql`
|
||||
mutation upsert_Account($objects: [Account_insert_input!]!) {
|
||||
insert_Account(
|
||||
objects: $objects
|
||||
on_conflict: {
|
||||
constraint: Account_identifier_type_player_key
|
||||
update_columns: [identifier]
|
||||
}
|
||||
) {
|
||||
affected_rows
|
||||
}
|
||||
}
|
||||
`;
|
||||
import { client } from '../../../lib/hasuraClient';
|
||||
|
||||
export const updateBoxProfileHandler = async (
|
||||
req: Request,
|
||||
@@ -45,11 +15,9 @@ export const updateBoxProfileHandler = async (
|
||||
throw new Error('expected role player');
|
||||
}
|
||||
|
||||
const data = await hasuraQuery<PlayerResult>(getPlayerQuery, {
|
||||
playerId,
|
||||
});
|
||||
const data = await client.GetPlayer({ playerId });
|
||||
|
||||
const ethAddress = data.Player[0]?.ethereum_address;
|
||||
const ethAddress = data.Player_by_pk?.ethereum_address;
|
||||
|
||||
if (!ethAddress) {
|
||||
throw new Error('unknown-player');
|
||||
@@ -69,7 +37,7 @@ async function updateVerifiedProfiles(
|
||||
const updatedProfiles: string[] = [];
|
||||
|
||||
if (verifiedProfiles.github) {
|
||||
const result = await hasuraQuery(upsertAccount, {
|
||||
const result = await client.UpsertAccount({
|
||||
objects: [
|
||||
{
|
||||
player_id: playerId,
|
||||
@@ -78,14 +46,14 @@ async function updateVerifiedProfiles(
|
||||
},
|
||||
],
|
||||
});
|
||||
if (result.affected_rows === 0) {
|
||||
if (result.insert_Account?.affected_rows === 0) {
|
||||
throw new Error('Error while upserting github profile');
|
||||
}
|
||||
updatedProfiles.push('github');
|
||||
}
|
||||
|
||||
if (verifiedProfiles.twitter) {
|
||||
const result = await hasuraQuery(upsertAccount, {
|
||||
const result = await client.UpsertAccount({
|
||||
objects: [
|
||||
{
|
||||
player_id: playerId,
|
||||
@@ -94,7 +62,7 @@ async function updateVerifiedProfiles(
|
||||
},
|
||||
],
|
||||
});
|
||||
if (result.affected_rows === 0) {
|
||||
if (result.insert_Account?.affected_rows === 0) {
|
||||
throw new Error('Error while upserting github profile');
|
||||
}
|
||||
updatedProfiles.push('twitter');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { did } from '@metafam/utils';
|
||||
import { Request, Response } from 'express';
|
||||
|
||||
import { getPlayer } from './users';
|
||||
import { getOrCreatePlayer } from './users';
|
||||
|
||||
const unauthorizedVariables = {
|
||||
'X-Hasura-Role': 'public',
|
||||
@@ -30,7 +30,7 @@ export const authHandler = async (
|
||||
return;
|
||||
}
|
||||
|
||||
const player = await getPlayer(claim.iss);
|
||||
const player = await getOrCreatePlayer(claim.iss);
|
||||
|
||||
const hasuraVariables = {
|
||||
'X-Hasura-Role': 'player',
|
||||
|
||||
@@ -1,52 +1,18 @@
|
||||
import { hasuraQuery } from '../../lib/hasuraHelpers';
|
||||
import { client } from '../../lib/hasuraClient';
|
||||
|
||||
const getPlayerQuery = `
|
||||
query GetPlayerFromETH ($ethereum_address: String) {
|
||||
Player(
|
||||
where: {
|
||||
ethereum_address: { _eq: $ethereum_address }
|
||||
}
|
||||
) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const createProfileMutation = `
|
||||
mutation CreateAccountFromETH ($ethereum_address: String!, $username: String!) {
|
||||
insert_Player(
|
||||
objects: {
|
||||
username: $username,
|
||||
ethereum_address: $ethereum_address
|
||||
}) {
|
||||
affected_rows
|
||||
returning {
|
||||
id
|
||||
username
|
||||
ethereum_address
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
interface IPlayer {
|
||||
id: string;
|
||||
username: string;
|
||||
ethereum_address: string;
|
||||
}
|
||||
|
||||
export async function createPlayer(ethAddress: string): Promise<IPlayer> {
|
||||
const resProfile = await hasuraQuery(createProfileMutation, {
|
||||
async function createPlayer(ethAddress: string) {
|
||||
const resProfile = await client.CreatePlayerFromETH({
|
||||
ethereum_address: ethAddress,
|
||||
username: ethAddress,
|
||||
});
|
||||
if (resProfile.insert_Player.affected_rows !== 1) {
|
||||
if (resProfile.insert_Player?.affected_rows !== 1) {
|
||||
throw new Error('Error while creating player');
|
||||
}
|
||||
return resProfile.insert_Player.returning[0];
|
||||
}
|
||||
|
||||
export async function getPlayer(ethAddress: string): Promise<IPlayer> {
|
||||
const res = await hasuraQuery(getPlayerQuery, {
|
||||
export async function getOrCreatePlayer(ethAddress: string) {
|
||||
const res = await client.GetPlayerFromETH({
|
||||
ethereum_address: ethAddress,
|
||||
});
|
||||
|
||||
|
||||
30
packages/backend/src/handlers/graphql/mutations.ts
Normal file
30
packages/backend/src/handlers/graphql/mutations.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { gql } from 'graphql-request/dist';
|
||||
|
||||
export const CreatePlayerFromETH = gql`
|
||||
mutation CreatePlayerFromETH($ethereum_address: String!, $username: String!) {
|
||||
insert_Player(
|
||||
objects: { username: $username, ethereum_address: $ethereum_address }
|
||||
) {
|
||||
affected_rows
|
||||
returning {
|
||||
id
|
||||
username
|
||||
ethereum_address
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const UpsertAccount = gql`
|
||||
mutation UpsertAccount($objects: [Account_insert_input!]!) {
|
||||
insert_Account(
|
||||
objects: $objects
|
||||
on_conflict: {
|
||||
constraint: Account_identifier_type_player_key
|
||||
update_columns: [identifier]
|
||||
}
|
||||
) {
|
||||
affected_rows
|
||||
}
|
||||
}
|
||||
`;
|
||||
18
packages/backend/src/handlers/graphql/queries.ts
Normal file
18
packages/backend/src/handlers/graphql/queries.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { gql } from 'graphql-request/dist';
|
||||
|
||||
export const GetPlayer = gql`
|
||||
query GetPlayer($playerId: uuid!) {
|
||||
Player_by_pk(id: $playerId) {
|
||||
id
|
||||
ethereum_address
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const GetPlayerFromEth = gql`
|
||||
query GetPlayerFromETH($ethereum_address: String) {
|
||||
Player(where: { ethereum_address: { _eq: $ethereum_address } }) {
|
||||
id
|
||||
}
|
||||
}
|
||||
`;
|
||||
13
packages/backend/src/lib/hasuraClient.ts
Normal file
13
packages/backend/src/lib/hasuraClient.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { GraphQLClient } from 'graphql-request';
|
||||
|
||||
import { CONFIG } from '../config';
|
||||
import { getSdk } from './autogen/sdk';
|
||||
|
||||
export const client = getSdk(
|
||||
new GraphQLClient(CONFIG.graphqlURL, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-hasura-access-key': CONFIG.adminKey,
|
||||
},
|
||||
}),
|
||||
);
|
||||
@@ -1,22 +0,0 @@
|
||||
import { GraphQLClient } from 'graphql-request';
|
||||
import { Variables } from 'graphql-request/dist/types';
|
||||
|
||||
import { CONFIG } from '../config';
|
||||
|
||||
export async function hasuraQuery<T = any>(
|
||||
query: string,
|
||||
variables?: Variables,
|
||||
): Promise<T> {
|
||||
const graphQLClient = new GraphQLClient(CONFIG.graphqlURL, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'x-hasura-access-key': CONFIG.adminKey,
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
return await graphQLClient.request<T>(query, variables);
|
||||
} catch (error) {
|
||||
throw new Error(JSON.stringify(error, undefined, 2));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user