feat: enhance API and query handling with Redis caching; add QueryGuard for query validation; refactor services to utilize RedisClient for improved performance
This commit is contained in:
@ -10,6 +10,10 @@ export class ApiController {
|
||||
|
||||
@Post("token/generate")
|
||||
generateToken(@Body() body: { id: string }) {
|
||||
if (!body.id) {
|
||||
throw new Error("Project ID is required");
|
||||
}
|
||||
|
||||
return this.apiService.generateToken(body.id);
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { forwardRef, Module } from "@nestjs/common";
|
||||
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||
import { Token } from "./entities/token.entity";
|
||||
import { ProjectModule } from "../project/project.module";
|
||||
@ -6,11 +6,19 @@ import { ApiService } from "./api.service";
|
||||
import { ApiController } from "./api.controller";
|
||||
import { Project } from "../project/entities/project.entity";
|
||||
import { ApiTokenGuard } from "./guards/api-token.guard";
|
||||
import { RedisModule } from "src/redis/redis.module";
|
||||
import { QueryGuard } from "./guards/query.guard";
|
||||
import { QueryModule } from "src/query/query.module";
|
||||
|
||||
@Module({
|
||||
imports: [ProjectModule, TypeOrmModule.forFeature([Token, Project])],
|
||||
imports: [
|
||||
forwardRef(() => RedisModule),
|
||||
forwardRef(() => QueryModule),
|
||||
ProjectModule,
|
||||
TypeOrmModule.forFeature([Token, Project]),
|
||||
],
|
||||
controllers: [ApiController],
|
||||
providers: [ApiService, ApiTokenGuard],
|
||||
exports: [ApiTokenGuard, TypeOrmModule],
|
||||
providers: [ApiService, ApiTokenGuard, QueryGuard],
|
||||
exports: [ApiTokenGuard, ApiService, TypeOrmModule],
|
||||
})
|
||||
export class ApiModule {}
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Inject, Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Token } from "./entities/token.entity";
|
||||
import { Repository } from "typeorm";
|
||||
import { Project } from "../project/entities/project.entity";
|
||||
import { RedisClient } from "src/redis/redis.service";
|
||||
|
||||
@Injectable()
|
||||
export class ApiService {
|
||||
constructor(
|
||||
@InjectRepository(Token)
|
||||
private readonly tokenRepository: Repository<Token>,
|
||||
|
||||
@Inject(RedisClient)
|
||||
private readonly redisClient: RedisClient,
|
||||
@InjectRepository(Project)
|
||||
private readonly projectRepository: Repository<Project>
|
||||
) {}
|
||||
@ -27,6 +29,25 @@ export class ApiService {
|
||||
return this.tokenRepository.save(token);
|
||||
}
|
||||
|
||||
async getTokenDetails(tokenString: string) {
|
||||
const cached = await this.redisClient.get(`token_${tokenString}`);
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const token = await this.tokenRepository.findOne({
|
||||
where: { token: tokenString },
|
||||
relations: ["project"],
|
||||
});
|
||||
|
||||
if (token) {
|
||||
await this.redisClient.set(`token_${token.token}`, token, 300);
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
async revokeToken(tokenString: string) {
|
||||
const token = await this.tokenRepository.findOne({
|
||||
where: { token: tokenString },
|
||||
@ -36,6 +57,8 @@ export class ApiService {
|
||||
throw new Error("Token not found");
|
||||
}
|
||||
|
||||
await this.redisClient.del(`token_${tokenString}`);
|
||||
|
||||
token.isActive = false;
|
||||
return this.tokenRepository.save(token);
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ export class Token {
|
||||
@PrimaryGeneratedColumn("uuid")
|
||||
token: string;
|
||||
|
||||
@Column({ type: "tinyint", default: 0 })
|
||||
@Column({ type: "tinyint", default: 1 })
|
||||
isActive: boolean;
|
||||
|
||||
@ManyToOne(() => Project, (project) => project.apiTokens)
|
||||
|
||||
@ -1,34 +1,28 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Inject,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { Token } from "../entities/token.entity";
|
||||
import { ApiService } from "../api.service";
|
||||
|
||||
@Injectable()
|
||||
export class ApiTokenGuard implements CanActivate {
|
||||
constructor(
|
||||
@InjectRepository(Token)
|
||||
private readonly tokenRepository: Repository<Token>
|
||||
@Inject(ApiService)
|
||||
private readonly apiService: ApiService
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
return true;
|
||||
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const token = request.params?.token || request.headers?.["x-api-token"];
|
||||
const token = request.headers?.["x-api-token"];
|
||||
|
||||
if (!token) {
|
||||
throw new UnauthorizedException("API token is required");
|
||||
}
|
||||
|
||||
const tokenEntity = await this.tokenRepository.findOne({
|
||||
where: { token },
|
||||
relations: ["project"],
|
||||
});
|
||||
const tokenEntity = await this.apiService.getTokenDetails(token);
|
||||
|
||||
if (!tokenEntity) {
|
||||
throw new UnauthorizedException("Invalid API token");
|
||||
@ -38,6 +32,8 @@ export class ApiTokenGuard implements CanActivate {
|
||||
throw new UnauthorizedException("API token is inactive");
|
||||
}
|
||||
|
||||
request.apiToken = tokenEntity;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
49
src/api/guards/query.guard.ts
Normal file
49
src/api/guards/query.guard.ts
Normal file
@ -0,0 +1,49 @@
|
||||
import {
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
Inject,
|
||||
Injectable,
|
||||
UnauthorizedException,
|
||||
} from "@nestjs/common";
|
||||
import { QueryHandlerService } from "src/query/handler/query.handler.service";
|
||||
|
||||
@Injectable()
|
||||
export class QueryGuard implements CanActivate {
|
||||
constructor(
|
||||
@Inject(QueryHandlerService)
|
||||
private readonly queryHandlerService: QueryHandlerService
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest();
|
||||
const apiToken = request.apiToken;
|
||||
|
||||
if (!apiToken || !apiToken.project) {
|
||||
throw new UnauthorizedException("Project not found for the API token");
|
||||
}
|
||||
|
||||
const queryId = request.params?.id;
|
||||
|
||||
if (!queryId) {
|
||||
throw new UnauthorizedException("Query ID is required");
|
||||
}
|
||||
|
||||
const query = await this.queryHandlerService.getQueryById(queryId);
|
||||
|
||||
if (!query) {
|
||||
throw new UnauthorizedException("Query not found");
|
||||
}
|
||||
|
||||
if (!query.isActive) {
|
||||
throw new UnauthorizedException("Query is inactive");
|
||||
}
|
||||
|
||||
if (query.project.id !== apiToken.project.id) {
|
||||
throw new UnauthorizedException("You do not have access to this query");
|
||||
}
|
||||
|
||||
request.query = query;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -9,12 +9,14 @@ import { DatabaseManagerController } from "./database/database.manager.controlle
|
||||
import { DatabaseManagerService } from "./database/database.manager.service";
|
||||
import { DatabaseNodeService } from "./databaseNode/database.node.service";
|
||||
import { ApiModule } from "src/api/api.module";
|
||||
import { RedisModule } from "src/redis/redis.module";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
forwardRef(() => ProjectModule),
|
||||
forwardRef(() => MigrationModule),
|
||||
forwardRef(() => ApiModule),
|
||||
forwardRef(() => RedisModule),
|
||||
TypeOrmModule.forFeature([Database, DatabaseNode, Project]),
|
||||
],
|
||||
controllers: [DatabaseManagerController],
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Inject, Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Database } from "../entities/database.entity";
|
||||
import { Repository } from "typeorm";
|
||||
@ -6,6 +6,7 @@ import { ProjectService } from "src/project/project.service";
|
||||
import { DatabaseEncryptionService } from "../database.encryption.service";
|
||||
import { DatabaseNodeService } from "../databaseNode/database.node.service";
|
||||
import * as mysql from "mysql2/promise";
|
||||
import { RedisClient } from "src/redis/redis.service";
|
||||
|
||||
@Injectable()
|
||||
export class DatabaseManagerService extends DatabaseEncryptionService {
|
||||
@ -13,7 +14,9 @@ export class DatabaseManagerService extends DatabaseEncryptionService {
|
||||
@InjectRepository(Database)
|
||||
private databaseRepository: Repository<Database>,
|
||||
private readonly projectService: ProjectService,
|
||||
private readonly databaseNodeService: DatabaseNodeService
|
||||
private readonly databaseNodeService: DatabaseNodeService,
|
||||
@Inject(RedisClient)
|
||||
private readonly redisClient: RedisClient
|
||||
) {
|
||||
super();
|
||||
}
|
||||
@ -64,6 +67,14 @@ export class DatabaseManagerService extends DatabaseEncryptionService {
|
||||
throw new Error("Project not found");
|
||||
}
|
||||
|
||||
const cached = await this.redisClient.get(
|
||||
`db_conn_opts_${projectId}_${queryUser}`
|
||||
);
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const database = await this.databaseRepository.findOne({
|
||||
where: { project: { id: project.id } },
|
||||
relations: ["node"],
|
||||
@ -73,7 +84,7 @@ export class DatabaseManagerService extends DatabaseEncryptionService {
|
||||
throw new Error("Database not found");
|
||||
}
|
||||
|
||||
return {
|
||||
const connectionOptions = {
|
||||
host: database.node.host,
|
||||
port: database.node.port,
|
||||
user: queryUser ? database.q_username : database.c_username,
|
||||
@ -82,6 +93,14 @@ export class DatabaseManagerService extends DatabaseEncryptionService {
|
||||
idleTimeout: 150e3,
|
||||
connectTimeout: 2e3,
|
||||
};
|
||||
|
||||
await this.redisClient.set(
|
||||
`db_conn_opts_${projectId}_${queryUser}`,
|
||||
connectionOptions,
|
||||
300
|
||||
);
|
||||
|
||||
return connectionOptions;
|
||||
}
|
||||
|
||||
async createDatabase(projectId: string): Promise<Database> {
|
||||
|
||||
@ -4,9 +4,14 @@ import { Project } from "./entities/project.entity";
|
||||
import { ProjectService } from "./project.service";
|
||||
import { ProjectController } from "./project.controller";
|
||||
import { ApiModule } from "src/api/api.module";
|
||||
import { RedisModule } from "src/redis/redis.module";
|
||||
|
||||
@Module({
|
||||
imports: [forwardRef(() => ApiModule), TypeOrmModule.forFeature([Project])],
|
||||
imports: [
|
||||
forwardRef(() => ApiModule),
|
||||
forwardRef(() => RedisModule),
|
||||
TypeOrmModule.forFeature([Project]),
|
||||
],
|
||||
controllers: [ProjectController],
|
||||
providers: [ProjectService],
|
||||
exports: [ProjectService],
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Inject, Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { Project } from "./entities/project.entity";
|
||||
import { RedisClient } from "src/redis/redis.service";
|
||||
|
||||
@Injectable()
|
||||
export class ProjectService {
|
||||
constructor(
|
||||
@InjectRepository(Project)
|
||||
private readonly projectRepository: Repository<Project>
|
||||
private readonly projectRepository: Repository<Project>,
|
||||
@Inject(RedisClient)
|
||||
private readonly redisClient: RedisClient
|
||||
) {}
|
||||
|
||||
create(name: string) {
|
||||
@ -15,17 +18,33 @@ export class ProjectService {
|
||||
return this.projectRepository.save(project);
|
||||
}
|
||||
|
||||
findById(id: string) {
|
||||
return this.projectRepository.findOne({ where: { id: id } });
|
||||
async findById(id: string) {
|
||||
const cached = await this.redisClient.get(`project_${id}`);
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
updateDatabase(projectId: string, databaseId: string) {
|
||||
const project = await this.projectRepository.findOne({ where: { id: id } });
|
||||
|
||||
if (project) {
|
||||
await this.redisClient.set(`project_${id}`, project, 300);
|
||||
}
|
||||
|
||||
return project;
|
||||
}
|
||||
|
||||
async updateDatabase(projectId: string, databaseId: string) {
|
||||
await this.redisClient.del(`project_${projectId}`);
|
||||
|
||||
return this.projectRepository.update(projectId, {
|
||||
database: { id: databaseId },
|
||||
});
|
||||
}
|
||||
|
||||
updateRedisNode(projectId: string, redisNodeId: { id: string }[]) {
|
||||
async updateRedisNode(projectId: string, redisNodeId: { id: string }[]) {
|
||||
await this.redisClient.del(`project_${projectId}`);
|
||||
|
||||
return this.projectRepository.update(projectId, {
|
||||
redisNodes: redisNodeId,
|
||||
});
|
||||
|
||||
@ -11,6 +11,7 @@ import { Response } from "express";
|
||||
import { QueryHandlerService } from "../handler/query.handler.service";
|
||||
import { ApiTokenGuard } from "src/api/guards/api-token.guard";
|
||||
import { QueryExecuterService } from "../executer/query.executer.service";
|
||||
import { QueryGuard } from "src/api/guards/query.guard";
|
||||
|
||||
@UseGuards(ApiTokenGuard)
|
||||
export abstract class BaseQueryController {
|
||||
@ -31,22 +32,24 @@ export abstract class BaseQueryController {
|
||||
}
|
||||
|
||||
@Post("update/:id")
|
||||
@UseGuards(QueryGuard)
|
||||
async updateQuery(
|
||||
@Body() updateData: Partial<{ source: string }>,
|
||||
@Inject("id") id: string
|
||||
@Param("id") id: string
|
||||
) {
|
||||
return this.queryHandlerService.updateQuery(id, updateData);
|
||||
}
|
||||
|
||||
@Post("/run/:token")
|
||||
@Post("/run/:id")
|
||||
@UseGuards(QueryGuard)
|
||||
async runQuery(
|
||||
@Param("token") token: string,
|
||||
@Param("id") id: string,
|
||||
@Body() query: Record<string, any>,
|
||||
@Headers() headers: Record<string, any>,
|
||||
@Res() res: Response
|
||||
) {
|
||||
const queryResult = await this.queryExecuterService.runQueryQueued(
|
||||
token,
|
||||
id,
|
||||
query,
|
||||
headers
|
||||
);
|
||||
|
||||
@ -14,7 +14,7 @@ import { DatabaseManagerService } from "src/databaseManager/database/database.ma
|
||||
import { InjectQueue } from "@nestjs/bullmq";
|
||||
import { QUEUE_NAMES } from "src/queue/constants";
|
||||
import { Queue, QueueEvents } from "bullmq";
|
||||
import { FunctionService } from "src/project/function/function.service";
|
||||
import { FunctionService } from "src/query/function/function.service";
|
||||
|
||||
@Injectable()
|
||||
export class QueryExecuterService {
|
||||
|
||||
@ -2,7 +2,7 @@ import { Inject, Injectable } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { FunctionEntity } from "src/query/entities/function.entity";
|
||||
import { In, Repository } from "typeorm";
|
||||
import { ProjectService } from "../project.service";
|
||||
import { ProjectService } from "../../project/project.service";
|
||||
|
||||
@Injectable()
|
||||
export class FunctionService {
|
||||
@ -3,6 +3,7 @@ import { Repository } from "typeorm";
|
||||
import { Query } from "../entities/query.entity";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { ProjectService } from "src/project/project.service";
|
||||
import { RedisClient } from "src/redis/redis.service";
|
||||
|
||||
@Injectable()
|
||||
export class QueryHandlerService {
|
||||
@ -10,7 +11,9 @@ export class QueryHandlerService {
|
||||
@InjectRepository(Query)
|
||||
private readonly queryRepository: Repository<Query>,
|
||||
@Inject(ProjectService)
|
||||
private readonly projectService: ProjectService
|
||||
private readonly projectService: ProjectService,
|
||||
@Inject(RedisClient)
|
||||
private readonly redisClient: RedisClient
|
||||
) {}
|
||||
|
||||
async createQuery(
|
||||
@ -34,6 +37,25 @@ export class QueryHandlerService {
|
||||
return query;
|
||||
}
|
||||
|
||||
async getQueryById(id: string) {
|
||||
const cached = await this.redisClient.get(`query_${id}`);
|
||||
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const query = await this.queryRepository.findOne({
|
||||
where: { id },
|
||||
relations: ["project"],
|
||||
});
|
||||
|
||||
if (query) {
|
||||
await this.redisClient.set(`query_${id}`, query, 300);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
async updateQuery(id: string, updateData: Partial<Query>) {
|
||||
const query = await this.queryRepository.findOne({ where: { id } });
|
||||
|
||||
@ -41,6 +63,8 @@ export class QueryHandlerService {
|
||||
throw new Error("Query not found");
|
||||
}
|
||||
|
||||
await this.redisClient.del(`query_${id}`);
|
||||
|
||||
Object.assign(query, updateData);
|
||||
return this.queryRepository.save(query);
|
||||
}
|
||||
|
||||
@ -10,9 +10,10 @@ import { CommandController } from "./command/command.controller";
|
||||
import { ApiModule } from "src/api/api.module";
|
||||
import { QueueModule } from "src/queue/queue.module";
|
||||
import { FunctionEntity } from "./entities/function.entity";
|
||||
import { FunctionService } from "src/project/function/function.service";
|
||||
import { FunctionController } from "src/project/function/function.controller";
|
||||
import { FunctionService } from "src/query/function/function.service";
|
||||
import { FunctionController } from "src/query/function/function.controller";
|
||||
import { RedisManagerModule } from "src/redisManager/redisManager.module";
|
||||
import { RedisModule } from "src/redis/redis.module";
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -20,11 +21,12 @@ import { RedisManagerModule } from "src/redisManager/redisManager.module";
|
||||
forwardRef(() => DatabaseManagerModule),
|
||||
forwardRef(() => ApiModule),
|
||||
forwardRef(() => QueueModule),
|
||||
forwardRef(() => RedisModule),
|
||||
forwardRef(() => RedisManagerModule),
|
||||
TypeOrmModule.forFeature([Query, FunctionEntity]),
|
||||
],
|
||||
controllers: [QueryController, CommandController, FunctionController],
|
||||
providers: [QueryExecuterService, QueryHandlerService, FunctionService],
|
||||
exports: [QueryExecuterService, TypeOrmModule],
|
||||
exports: [QueryExecuterService, TypeOrmModule, QueryHandlerService],
|
||||
})
|
||||
export class QueryModule {}
|
||||
|
||||
@ -12,7 +12,7 @@ export class RedisClient {
|
||||
|
||||
async set(
|
||||
key: string,
|
||||
value: string,
|
||||
value: any,
|
||||
expireInSeconds?: number
|
||||
): Promise<"OK" | null> {
|
||||
if (!this.redis) {
|
||||
@ -20,18 +20,23 @@ export class RedisClient {
|
||||
}
|
||||
|
||||
if (expireInSeconds) {
|
||||
return await this.redis.set(key, value, "EX", expireInSeconds);
|
||||
return await this.redis.set(
|
||||
key,
|
||||
JSON.stringify(value),
|
||||
"EX",
|
||||
expireInSeconds
|
||||
);
|
||||
}
|
||||
|
||||
return await this.redis.set(key, value);
|
||||
return await this.redis.set(key, JSON.stringify(value));
|
||||
}
|
||||
|
||||
async get(key: string): Promise<string | null> {
|
||||
async get(key: string): Promise<any | null> {
|
||||
if (!this.redis) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await this.redis.get(key);
|
||||
return JSON.parse(await this.redis.get(key));
|
||||
}
|
||||
|
||||
async del(key: string): Promise<number | null> {
|
||||
|
||||
@ -10,33 +10,33 @@ import * as path from "path";
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const node = await createDatabaseNode("localhost", 3306, "root", "root");
|
||||
// const node = await createDatabaseNode("localhost", 3306, "root", "root");
|
||||
|
||||
console.log("Database node created:", node);
|
||||
// console.log("Database node created:", node);
|
||||
|
||||
const project = await createProject("Test Project");
|
||||
// const project = await createProject("Test Project");
|
||||
|
||||
console.log("Project created:", project);
|
||||
// console.log("Project created:", project);
|
||||
|
||||
const db = await createDatabase(project.id, node.id);
|
||||
// const db = await createDatabase(project.id, node.id);
|
||||
|
||||
console.log("Database created:", db);
|
||||
// console.log("Database created:", db);
|
||||
|
||||
const migration = await createMigration(
|
||||
db.id,
|
||||
"CREATE TABLE `test` (id INT AUTO_INCREMENT PRIMARY KEY, col1 VARCHAR(255))",
|
||||
"DROP TABLE `test`"
|
||||
);
|
||||
// const migration = await createMigration(
|
||||
// db.id,
|
||||
// "CREATE TABLE `test` (id INT AUTO_INCREMENT PRIMARY KEY, col1 VARCHAR(255))",
|
||||
// "DROP TABLE `test`"
|
||||
// );
|
||||
|
||||
console.log("Migration created:", migration);
|
||||
// console.log("Migration created:", migration);
|
||||
|
||||
const migrationResult = await databaseMigrationUp(db.id);
|
||||
// const migrationResult = await databaseMigrationUp(db.id);
|
||||
|
||||
console.log("Migrations applied:", migrationResult);
|
||||
// console.log("Migrations applied:", migrationResult);
|
||||
|
||||
const payloadPath = path.join(__dirname, "case1-payload.js");
|
||||
const query = await createQuery(
|
||||
project,
|
||||
{ token: "04c38f93-f2fb-4d2c-a8e2-791effa35239" },
|
||||
fs.readFileSync(payloadPath, { encoding: "utf-8" })
|
||||
);
|
||||
|
||||
|
||||
@ -3,10 +3,14 @@ import { config } from "../config";
|
||||
|
||||
export default async (project: { token: string }, source: string) => {
|
||||
try {
|
||||
const response = await axios.post(`${config.url}/query/create`, {
|
||||
const response = await axios.post(
|
||||
`${config.url}/query/create`,
|
||||
{
|
||||
source,
|
||||
projectToken: project.token,
|
||||
});
|
||||
},
|
||||
{ headers: { "x-api-token": "efbeccd6-dde1-47dc-b3aa-4fbd773d5429" } }
|
||||
);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error("Error creating query:", error);
|
||||
|
||||
@ -5,7 +5,8 @@ export default async (token: string, queryData: Record<string, any>) => {
|
||||
try {
|
||||
const response = await axios.post(
|
||||
`${config.url}/query/run/${token}`,
|
||||
queryData
|
||||
queryData,
|
||||
{ headers: { "x-api-token": "efbeccd6-dde1-47dc-b3aa-4fbd773d5429" } }
|
||||
);
|
||||
|
||||
return response;
|
||||
|
||||
Reference in New Issue
Block a user