Skip to content

Commit 6f8ab95

Browse files
authored
Initialize API gateway (#51)
* Add minimial gateway * Configure frontend to use api gateway
1 parent 26ac65f commit 6f8ab95

File tree

6 files changed

+77
-18
lines changed

6 files changed

+77
-18
lines changed

compose.dev.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ services:
66

77
question:
88
command: npm run dev
9+
ports:
10+
- 8081:8081
911
volumes:
1012
- /app/node_modules
1113
- ./services/question:/app
@@ -16,6 +18,8 @@ services:
1618

1719
user:
1820
command: npm run dev
21+
ports:
22+
- 8082:8082
1923
volumes:
2024
- /app/node_modules
2125
- ./services/user:/app

compose.yml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,29 @@ services:
99
- 4200:4200
1010
restart: always
1111

12+
gateway:
13+
container_name: gateway
14+
image: nginx:1.27
15+
ports:
16+
- 8080:8080
17+
volumes:
18+
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
19+
networks:
20+
- gateway-network
21+
1222
question:
1323
container_name: question
1424
image: question
1525
build:
1626
context: services/question
1727
dockerfile: Dockerfile
18-
ports:
19-
- 8081:8081
2028
environment:
2129
DB_CLOUD_URI: ${QUESTION_DB_CLOUD_URI}
2230
DB_LOCAL_URI: ${QUESTION_DB_LOCAL_URI}
2331
DB_USERNAME: ${QUESTION_DB_USERNAME}
2432
DB_PASSWORD: ${QUESTION_DB_PASSWORD}
2533
networks:
34+
- gateway-network
2635
- question-db-network
2736
restart: always
2837

@@ -46,15 +55,14 @@ services:
4655
build:
4756
context: services/user
4857
dockerfile: Dockerfile
49-
ports:
50-
- 8082:8082
5158
environment:
5259
DB_CLOUD_URI: ${USER_DB_CLOUD_URI}
5360
DB_LOCAL_URI: ${USER_DB_LOCAL_URI}
5461
DB_USERNAME: ${USER_DB_USERNAME}
5562
DB_PASSWORD: ${USER_DB_PASSWORD}
5663
JWT_SECRET: ${JWT_SECRET}
5764
networks:
65+
- gateway-network
5866
- user-db-network
5967
restart: always
6068

@@ -76,6 +84,8 @@ volumes:
7684
user-db:
7785

7886
networks:
87+
gateway-network:
88+
driver: bridge
7989
question-db-network:
8090
driver: bridge
8191
user-db-network:
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { API_CONFIG } from '../app/api.config';
2+
3+
/**
4+
* Abstract class that serves as a base for API services.
5+
*/
6+
export abstract class ApiService {
7+
/**
8+
* The path for the specific resource, e.g. 'user', 'question', etc.
9+
* This property must be implemented by subclasses to specify the
10+
* endpoint path for the API resource they represent.
11+
*/
12+
protected abstract apiPath: string;
13+
14+
/**
15+
* Returns the full URL for the API endpoint based on
16+
* the specified apiPath.
17+
*/
18+
get apiUrl(): string {
19+
return API_CONFIG.baseUrl + this.apiPath;
20+
}
21+
}

frontend/src/_services/question.service.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular/common/http';
22
import { Injectable } from '@angular/core';
3-
import { API_CONFIG } from '../app/api.config';
43
import { catchError, Observable, throwError } from 'rxjs';
54
import {
65
SingleQuestionResponse,
@@ -9,20 +8,23 @@ import {
98
MessageOnlyResponse,
109
} from '../app/questions/question.model';
1110
import { TopicResponse } from '../app/questions/topic.model';
11+
import { ApiService } from './api.service';
1212

1313
@Injectable({
1414
providedIn: 'root',
1515
})
16-
export class QuestionService {
17-
private baseUrl = API_CONFIG.baseUrl + '/questions';
16+
export class QuestionService extends ApiService {
17+
protected apiPath = 'question/questions';
1818

1919
private httpOptions = {
2020
headers: new HttpHeaders({
2121
'Content-Type': 'application/json',
2222
}),
2323
};
2424

25-
constructor(private http: HttpClient) {}
25+
constructor(private http: HttpClient) {
26+
super();
27+
}
2628

2729
getQuestions(
2830
title?: string,
@@ -46,11 +48,11 @@ export class QuestionService {
4648
}
4749

4850
// send request
49-
return this.http.get<QuestionResponse>(this.baseUrl, { params });
51+
return this.http.get<QuestionResponse>(this.apiUrl, { params });
5052
}
5153

52-
getQuestionByID(id: number): Observable<SingleQuestionResponse> {
53-
return this.http.get<SingleQuestionResponse>(this.baseUrl + '/' + id);
54+
getQuestionByID(id: number): Observable<QuestionResponse> {
55+
return this.http.get<QuestionResponse>(this.apiUrl + '/' + id);
5456
}
5557

5658
getQuestionByParam(topics: string[], difficulty: string, limit?: number): Observable<QuestionResponse> {
@@ -61,32 +63,32 @@ export class QuestionService {
6163
}
6264
params = params.append('topics', topics.join(',')).append('difficulty', difficulty);
6365

64-
return this.http.get<QuestionResponse>(this.baseUrl + '/search', { params });
66+
return this.http.get<QuestionResponse>(this.apiUrl + '/search', { params });
6567
}
6668

6769
getTopics(): Observable<TopicResponse> {
68-
return this.http.get<TopicResponse>(this.baseUrl + '/topics');
70+
return this.http.get<TopicResponse>(this.apiUrl + '/topics');
6971
}
7072

7173
addQuestion(question: QuestionBody): Observable<SingleQuestionResponse> {
7274
return this.http
73-
.post<SingleQuestionResponse>(this.baseUrl, question, this.httpOptions)
75+
.post<SingleQuestionResponse>(this.apiUrl, question, this.httpOptions)
7476
.pipe(catchError(this.handleError));
7577
}
7678

7779
updateQuestion(id: number, question: QuestionBody): Observable<SingleQuestionResponse> {
7880
return this.http
79-
.put<SingleQuestionResponse>(this.baseUrl + '/' + id, question, this.httpOptions)
81+
.put<SingleQuestionResponse>(this.apiUrl + '/' + id, question, this.httpOptions)
8082
.pipe(catchError(this.handleError));
8183
}
8284

8385
deleteQuestion(id: number): Observable<SingleQuestionResponse> {
84-
return this.http.delete<SingleQuestionResponse>(this.baseUrl + '/' + id).pipe(catchError(this.handleError));
86+
return this.http.delete<SingleQuestionResponse>(this.apiUrl + '/' + id).pipe(catchError(this.handleError));
8587
}
8688

8789
deleteQuestions(ids: number[]): Observable<MessageOnlyResponse> {
8890
return this.http
89-
.post<MessageOnlyResponse>(this.baseUrl + '/delete', { ids }, this.httpOptions)
91+
.post<MessageOnlyResponse>(this.apiUrl + '/delete', { ids }, this.httpOptions)
9092
.pipe(catchError(this.handleError));
9193
}
9294

frontend/src/app/api.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export const API_CONFIG = {
2-
baseUrl: 'http://localhost:8081',
2+
baseUrl: 'http://localhost:8080/api/',
33
};

nginx/default.conf

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
upstream question-api {
2+
server question:8081;
3+
}
4+
5+
upstream user-api {
6+
server user:8082;
7+
}
8+
9+
server {
10+
listen 8080;
11+
server_name localhost;
12+
13+
location /api/question/ {
14+
proxy_pass http://question-api/;
15+
proxy_set_header Host $host;
16+
}
17+
18+
location /api/user/ {
19+
proxy_pass http://user-api/;
20+
proxy_set_header Host $host;
21+
}
22+
}

0 commit comments

Comments
 (0)