In production-grade Angular applications, API URLs and other environment-specific properties are typically configured through environment files located in the src/environments/
directory. These can be generated using the Angular CLI command:
ng generate environments
This creates the standard environment files:
-
environment.ts
(production defaults) -
environment.development.ts
(development configuration) - You could add other environments like staging...
Secure Configuration Management
For security best practices:
- Never commit sensitive URLs directly in environment files
- Use CI/CD variables (GitLab, GitHub Actions, etc.) to inject values during build
Protect repository variables by marking them as:
- Masked (hidden in logs)
- Protected (only available on protected branches)
Update the files:
environment.ts
export const environment = {
production: true,
API_URL: '${API_URL}' // CI/CD variable - This will be replaced during build
};
environment.development.ts
export const environment = {
production: false,
API_URL: 'https://api.example.com/data' // Used only in development
};
Use the environment variables:
data-http.service.ts
...
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class DataHttpService {
http = inject(HttpClient);
getData(): Observable<unknown> {
return this.http.get<unknown>(environment.API_URL);
}
}
Unit testing with environment mocks
You could add an environment global mock in setup-jest.ts
:
...
jest.mock('./src/environments/environment', () => ({
environment: {
API_URL: 'https://api.example.com/data',
production: false
}
}));
Mocking environment variables in unit tests is strongly recommended to ensure isolation, consistency, and security while testing all scenarios.
data-http.service.spec.ts
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing';
import { DataHttpService } from './data-http.service';
import { environment } from '../environments/environment';
describe('DataHttpService', () => {
let service: DataHttpService;
let httpMock: HttpTestingController;
const mockData = { id: 1, name: 'Test Data' };
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [DataHttpService]
});
service = TestBed.inject(DataHttpService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => {
httpMock.verify(); // Verify no outstanding requests
});
it('should use mock API_URL', () => {
expect(environment.API_URL).toBe('https://api.example.com/data'); // Url defined in the setup-jest.ts file
});
describe('.getData', () => {
it('should make GET request and return data', () => {
service.getData().subscribe(data => {
expect(data).toEqual(mockData);
});
const req = httpMock.expectOne(environment.API_URL);
expect(req.request.method).toEqual('GET');
req.flush(mockData);
});
});
});