Skip to content

Commit

Permalink
fix: serialisation nextjs requests
Browse files Browse the repository at this point in the history
  • Loading branch information
ErnoW committed Jan 9, 2023
1 parent 8927132 commit fa40ad7
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 58 deletions.
5 changes: 5 additions & 0 deletions .changeset/five-moles-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@moralisweb3/next': patch
---

Fix issues related to several NextJS hooks, due to the serialisation of the request
60 changes: 60 additions & 0 deletions packages/next/src/MoralisNextApi/Modules.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { EvmApi } from '@moralisweb3/evm-api';
import { operations as evmOperations } from 'moralis/common-evm-utils';
import { operations as solOperations } from 'moralis/common-sol-utils';
import { Operation } from 'moralis/common-core';
import { operations as authOperations } from '@moralisweb3/common-auth-utils';
import { Auth } from '@moralisweb3/auth';
import { SolApi } from '@moralisweb3/sol-api';
import Moralis from 'moralis';

export type UnknownOperation = Operation<unknown, unknown, unknown, unknown>;

export class Module {
public name: string;
public baseUrl: string;
public operations: UnknownOperation[];

constructor({ name, baseUrl, operations }: { name: string; baseUrl: string; operations: UnknownOperation[] }) {
this.name = name;
this.baseUrl = baseUrl;
this.operations = operations;
}

getOperationByName(operationName: string) {
const operation = this.operations.find((op) => op.name === operationName);

if (!operation) {
throw new Error(`Operation ${operationName} not found`);
}

return operation;
}
}

const modules: Module[] = [
new Module({
name: EvmApi.moduleName,
baseUrl: Moralis.EvmApi.baseUrl,
operations: evmOperations as UnknownOperation[],
}),
new Module({
name: SolApi.moduleName,
baseUrl: Moralis.SolApi.baseUrl,
operations: solOperations as UnknownOperation[],
}),
new Module({
name: Auth.moduleName,
baseUrl: Moralis.Auth.baseUrl,
operations: authOperations as UnknownOperation[],
}),
];

export function getModuleByName(moduleName: string) {
const module = modules.find((mod) => mod.name === moduleName);

if (!module) {
throw new Error(`Module ${moduleName} not found`);
}

return module;
}
18 changes: 10 additions & 8 deletions packages/next/src/MoralisNextApi/MoralisNextApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ import { RequestHandlerResolver } from './RequestHandlerResolver';
import Moralis from 'moralis';
import type { NextApiRequest, NextApiResponse } from 'next';
import { authOperationNames, moralisNextAuthHandler } from '../auth/moralisNextAuthHandler';
import { getModuleByName } from './Modules';

async function MoralisNextHandler({ req, res, authentication }: MoralisNextHandlerParams) {
async function MoralisNextHandler({ req, res, authentication, core }: MoralisNextHandlerParams) {
const [moduleName, operationName] = req.query.moralis as string[];

try {
const requestHandler = RequestHandlerResolver.tryResolve(moduleName, operationName);
if (!requestHandler) {
return res.status(500).json({ error: `Operation ${moduleName}/${operationName} is not supported` });
}
const module = getModuleByName(moduleName);
const operation = module?.getOperationByName(operationName);
const requestHandler = RequestHandlerResolver.tryResolve(module, operation);
const deserialisedRequest = operation.deserializeRequest(req.body, core);

let response;

if (authOperationNames.includes(operationName)) {
response = await moralisNextAuthHandler({ req, res, authentication, requestHandler, operationName });
response = await moralisNextAuthHandler({ req, res, authentication, requestHandler, operation, core });
} else {
response = await requestHandler.fetch(req.body);
response = await requestHandler.fetch(deserialisedRequest);
}

return res.status(200).json(response);
Expand All @@ -32,7 +33,8 @@ const MoralisNextApi = ({ authentication, ...config }: MoralisNextApiParams) =>
Moralis.start(config);
}

return async (req: NextApiRequest, res: NextApiResponse) => MoralisNextHandler({ req, res, authentication });
return async (req: NextApiRequest, res: NextApiResponse) =>
MoralisNextHandler({ req, res, authentication, core: Moralis.Core });
};

export default MoralisNextApi;
47 changes: 3 additions & 44 deletions packages/next/src/MoralisNextApi/RequestHandlerResolver.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,10 @@
import { EvmApi } from '@moralisweb3/evm-api';
import { operations as evmOperations } from 'moralis/common-evm-utils';
import { operations as solOperations } from 'moralis/common-sol-utils';
import { Operation } from 'moralis/common-core';
import { OperationResolver } from '@moralisweb3/api-utils';
import { operations as authOperations } from '@moralisweb3/common-auth-utils';
import { Auth } from '@moralisweb3/auth';
import { SolApi } from '@moralisweb3/sol-api';
import Moralis from 'moralis';

type UnknownOperation = Operation<unknown, unknown, unknown, unknown>;

interface Module {
name: string;
baseUrl: string;
operations: UnknownOperation[];
}

const modules: Module[] = [
{
name: EvmApi.moduleName,
baseUrl: Moralis.EvmApi.baseUrl,
operations: evmOperations as UnknownOperation[],
},
{
name: SolApi.moduleName,
baseUrl: Moralis.SolApi.baseUrl,
operations: solOperations as UnknownOperation[],
},
{
name: Auth.moduleName,
baseUrl: Moralis.Auth.baseUrl,
operations: authOperations as UnknownOperation[],
},
];
import { Module, UnknownOperation } from './Modules';

export class RequestHandlerResolver {
public static tryResolve(moduleName: string, operationName: string) {
const module = modules.find((mod) => mod.name === moduleName);
if (!module) {
return null;
}

const operation = module.operations.find((op) => op.name === operationName);
if (!operation) {
return null;
}

public static tryResolve(module: Module, operation: UnknownOperation) {
// TODO: use nullable/pagianted resolver here
return new OperationResolver(operation, module.baseUrl, Moralis.Core);
}
}
3 changes: 2 additions & 1 deletion packages/next/src/MoralisNextApi/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApiUtilsConfigValues } from '@moralisweb3/api-utils';
import { RequestChallengeEvmRequest, RequestChallengeSolanaRequest } from '@moralisweb3/common-auth-utils';
import { MoralisCoreConfigValues } from 'moralis/common-core';
import { MoralisCoreConfigValues, Core } from 'moralis/common-core';
import type { NextApiRequest, NextApiResponse } from 'next';

export type MoralisConfigValues = MoralisCoreConfigValues | ApiUtilsConfigValues;
Expand All @@ -15,4 +15,5 @@ export interface MoralisNextHandlerParams {
req: NextApiRequest;
res: NextApiResponse;
authentication?: AuthConfig;
core: Core;
}
14 changes: 10 additions & 4 deletions packages/next/src/auth/moralisNextAuthHandler.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { OperationResolver } from '@moralisweb3/api-utils';
import { UnknownOperation } from '../MoralisNextApi/Modules';
import { MoralisNextHandlerParams } from '../MoralisNextApi/types';

export const authOperationNames = [
Expand All @@ -10,27 +11,32 @@ export const authOperationNames = [

export interface MoralisNextAuthHandler extends MoralisNextHandlerParams {
requestHandler: OperationResolver<unknown, unknown, unknown, unknown>;
operationName: string;
operation: UnknownOperation;
}

export const moralisNextAuthHandler = async ({
req,
authentication,
requestHandler,
operationName,
operation,
core,
}: MoralisNextAuthHandler) => {
const operationName = operation.name;
if (!authentication) {
throw new Error(
`Error running the '${operationName}' operation. No authentication config provided in 'pages/api/moralis/[...moralis].ts'`,
);
}

const deserlialisedRequest = operation.deserializeRequest(req.body, core) as Record<string, unknown>;

switch (operationName) {
case 'requestChallengeEvm':
case 'requestChallengeSolana':
return requestHandler.fetch({ ...req.body, ...authentication });
return requestHandler.fetch({ ...deserlialisedRequest, ...authentication });
case 'verifyChallengeEvm':
case 'verifyChallengeSolana':
return requestHandler.fetch(req.body);
return requestHandler.fetch(deserlialisedRequest);
default:
throw new Error(`${operationName} is not supported authentication operation`);
}
Expand Down
2 changes: 1 addition & 1 deletion packages/next/src/utils/fetchers/fetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ async function fetcher<Request, Response, JSONResponse>(
) {
endpoint = `/api/moralis/${endpoint}`;

const { data } = await axios.post<JSONResponse>(endpoint, operation.serializeRequest(request, Moralis.Core));
const { data } = await axios.post<JSONResponse>(endpoint, request);

return operation.deserializeResponse(data, request, Moralis.Core);
}
Expand Down

0 comments on commit fa40ad7

Please sign in to comment.