I am using proxy.conf.json as I develop my Angular application.
However I would like to, for a few endpoints, simply return a JSON object when called. Currently my proxy.conf file redirects to a locally running backend which returns these JSONs. However I'd rather not run the backend server and simply return the JSON from proxy.conf.json.
Is this possible somehow?
It is possible by using proxy.conf.js
instead of proxy.conf.json
. Then you can specify a bypass function where you can return a response directly. This is mentioned in the angular-cli documentation for the proxy but it does not give many details. Here is a sample proxy.conf.js
file to do it.
const PROXY_CONFIG = {
'/api': {
'target': 'http://localhost:5000',
'bypass': function (req, res, proxyOptions) {
switch (req.url) {
case '/api/json1':
const objectToReturn1 = {
value1: 1,
value2: 'value2',
value3: 'value3'
};
res.end(JSON.stringify(objectToReturn1));
return true;
case '/api/json2':
const objectToReturn2 = {
value1: 2,
value2: 'value3',
value3: 'value4'
};
res.end(JSON.stringify(objectToReturn2));
return true;
}
}
}
}
module.exports = PROXY_CONFIG;
You need to recheck the url in the bypass function because it is called for all /api
requests and then you just directly return a response for the ones you want the others will still be redirected to the target address. You return true to tell the proxy the request finished.
Make sure to then specify the correct file when running ng serve --proxy-config proxy.conf.js
.
For returning JSON from proxy.config.conf
, there doesn't seem to be an easy way to do it.
One way would be to have a baseApiUrl
in the environment.ts
file as well urlSuffix
set to .json
. Then all of the API calls would have to be something like this: enviroment.baseApiUrl
+ uri
+ environment.urlSuffix
. Then in environment.prod.ts
, the urlSuffix
would be an empty string. This is a hacky solution but would work.
Alternative using HTTP_INTERCEPTORS
A cleaner solution that leverages the framework, would be to use an HttpInterceptor
with the HttpClient
along with setting the baseApiUrl
in the environment.ts
file. This allows for different API endpoints per environment.
environment.ts
export const environment = {
apiBaseUrl: 'http://localhost:4200/assets/api',
production: false
}
development.interceptor.ts
import {Injectable} from '@angular/core';
import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {environment} from '../environments/environment';
@Injectable()
export class DevelopmentInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let clonedRequest = null;
if (!environment.production) {
clonedRequest = request.clone({
url: `${request.url}.json`
});
return next.handle(clonedRequest);
}
return next.handle(clonedRequest);
}
}
This class will intercept any http request made by the HttpClient
. Using the properties in the environment.ts
file, you can check if the current build is a production build. If it is, clone the request and append .json
to it. Anything that is in the assets
folder is accessible from the browser. Below is a sample file that maps to the url http:localhost:4200/assets/api/test.json
.
/src/assets/api/test.json
{
"name": "test",
"description": "Test Data"
}
Place this file in the assets directory and have the directory structure follow the endpoints of the actual API.
test.service.ts
import {Injectable} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {environment} from '../environments/environment';
@Injectable()
export class TestService {
private baseUrl = `${environment.apiBaseUrl}/test`;
constructor(private http: HttpClient) {
}
getTestData(): Observable<any> {
return this.http.get(this.baseUrl);
}
}
Import the environment.ts
file here and set the base url to the apiBaseurl
property. As long as you import the environment.ts
file and not the environment.prod.ts
file, this will work in all environments as the appropriate environment file will be read from when the app is built. So this url only has to be change in one place per environment.
Angular CLI Build Targets & Environment Files
app.component.ts
import {Component, OnInit} from '@angular/core';
import {TestService} from './test.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
title = 'app';
constructor(private testService: TestService) {
}
ngOnInit() {
this.testService.getTestData().subscribe(
(testData) => console.log(testData)
);
}
}
Here the TestService
is injected into the AppComponent
and the getTestData()
method is called to fetch data from the API. The DevelopmentInterceptor
checks the environment
and appends .json
to the request. Then the data is logged to the console.
app.module.ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http';
import {AppComponent} from './app.component';
import {DevelopmentInterceptor} from './development.interceptor';
import {TestService} from './test.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
TestService,
{
provide: HTTP_INTERCEPTORS,
useClass: DevelopmentInterceptor,
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
Register the TestService
and the DevelopmentInterceptor
as providers.
Using this setup, proxy.config.json
is not necessary.
For more information on HttpInterceptors
, there is the Angular Documentation Intercepting Http Requests & Responses.
There is also a tutorial by Jason Watmore that does some more advanced things with this approach. Angular 5 - Mock Backend Example for Backendless Development
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With