Skip to content

Commit 1423fef

Browse files
authored
Merge pull request #17 from sparrowapp-dev/feat/implement-graphql-proxy-service
feat: implement graphql proxy [#16]
2 parents 2413873 + 5bad1dd commit 1423fef

File tree

4 files changed

+150
-1
lines changed

4 files changed

+150
-1
lines changed
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
Controller,
3+
Post,
4+
Body,
5+
Headers,
6+
Query,
7+
Req,
8+
Res,
9+
HttpException,
10+
HttpStatus,
11+
} from '@nestjs/common';
12+
import { GraphqlService } from './graphql.service';
13+
import { Request, Response } from 'express';
14+
15+
@Controller('proxy')
16+
export class GraphqlController {
17+
constructor(private readonly graphqlService: GraphqlService) {}
18+
19+
@Post('graphql-request')
20+
async handleHttpRequest(
21+
@Body('url') url: string,
22+
@Body('method') method: string,
23+
@Body('headers') headers: string,
24+
@Body('body') body: any,
25+
@Body('contentType') contentType: string,
26+
@Req() req: Request,
27+
@Res() res: Response,
28+
) {
29+
try {
30+
const response = await this.graphqlService.makeGraphqlRequest({
31+
url,
32+
method,
33+
headers,
34+
body,
35+
contentType,
36+
});
37+
38+
return res.status(200).send(response);
39+
} catch (error) {
40+
throw new HttpException(error.message, HttpStatus.BAD_GATEWAY);
41+
}
42+
}
43+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { Module } from '@nestjs/common';
2+
import { GraphqlController } from './graphql.controller';
3+
import { GraphqlService } from './graphql.service';
4+
import { HttpModule as NestHttpModule } from '@nestjs/axios';
5+
6+
@Module({
7+
imports: [NestHttpModule],
8+
controllers: [GraphqlController],
9+
providers: [GraphqlService],
10+
})
11+
export class GraphqlModule {}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { Injectable } from '@nestjs/common';
2+
import { HttpService as NestHttpService } from '@nestjs/axios';
3+
4+
@Injectable()
5+
export class GraphqlService {
6+
constructor(private readonly httpService: NestHttpService) {}
7+
8+
async makeGraphqlRequest({
9+
url,
10+
method,
11+
headers,
12+
body,
13+
contentType,
14+
}: {
15+
url: string;
16+
method: string;
17+
headers: string;
18+
body: any;
19+
contentType: string;
20+
}): Promise<{ status: string; data: any; headers: any }> {
21+
try {
22+
// Parse headers from stringified JSON
23+
const parsedHeaders: Record<string, string> = {};
24+
let headersArray;
25+
26+
try {
27+
headersArray = JSON.parse(headers);
28+
if (Array.isArray(headersArray)) {
29+
headersArray.forEach((item: any) => {
30+
parsedHeaders[item.key] = item.value;
31+
});
32+
}
33+
} catch (headerError) {
34+
console.error('Error parsing headers:', headerError);
35+
throw new Error('Invalid headers format');
36+
}
37+
38+
// Prepare the request configuration
39+
const config: any = {
40+
url,
41+
method,
42+
headers: parsedHeaders,
43+
data: null,
44+
};
45+
46+
// Handle body based on content type
47+
try {
48+
switch (contentType) {
49+
case 'application/json':
50+
config.data = typeof body === 'string' ? JSON.parse(body) : body;
51+
break;
52+
53+
default:
54+
break;
55+
}
56+
} catch (bodyError) {
57+
console.error('Error processing request body:', bodyError);
58+
throw new Error('Invalid request body format');
59+
}
60+
61+
// Add custom user agent
62+
config.headers['User-Agent'] = 'SparrowRuntime/1.0.0';
63+
64+
try {
65+
const response = await this.httpService.axiosRef({
66+
url: config.url,
67+
method: config.method,
68+
headers: config.headers,
69+
data: config.data,
70+
});
71+
const resp = {
72+
status:
73+
response.status + ' ' + (response.statusText || 'Unknown Status'),
74+
data: response.data,
75+
headers: response.headers,
76+
};
77+
return resp;
78+
} catch (axiosError: any) {
79+
return {
80+
status: axiosError.response?.status
81+
? axiosError.response?.status +
82+
' ' +
83+
(axiosError.response?.statusText || 'Unknown Status')
84+
: null,
85+
data: axiosError.response?.data || { message: axiosError.message },
86+
headers: axiosError.response?.headers,
87+
};
88+
}
89+
} catch (error: any) {
90+
console.error('HTTP Service Error:', error);
91+
throw new Error(error.message || 'Unknown error occurred');
92+
}
93+
}
94+
}

src/proxy/proxy.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { Module } from '@nestjs/common';
22
import { SocketIoModule } from './socketio/socketio.module';
33
import { HttpModule } from './http/http.module';
44
import { WebSocketModule } from './websocket/websocket.module';
5+
import { GraphqlModule } from "./graphql/graphql.module";
56

67
@Module({
7-
imports: [HttpModule, SocketIoModule, WebSocketModule],
8+
imports: [HttpModule, SocketIoModule, WebSocketModule, GraphqlModule],
89
})
910
export class ProxyModule {}

0 commit comments

Comments
 (0)