Category Archives: Angular

Using interfaces in Typescript and Angular

One of TypeScript’s core principles is that type-checking focuses on the shape that values have. Basically, as long as an object has the properties required by a function, it’s good to go. It can be a pain in the ass, especially when you come from strictly typed languages.

Introduced in Typescript 2.1, interfaces are your solution to work this issue around. They allow you to define contracts, and to enforce that these contracts are respected. They allow static type checking, and so your IDE can detect errors at compile time, while preserving runtime efficiency since interfaces do not appear in the generated javascript code !

Hence, interfaces solve a common typescript issue when working with objects which have been dynamically casted, and hence may have all properties from the target class, but no the methods. This is a frequent with JSON objects returned by an HTTP call to a REST API and then casted to a different type. Working with interfaces will help you avoid the “method undefined” error.

you define you interface similarly to how you define a class

export interface Book {
  name: string;
  description?: string;
}

Notice the ‘?’ suffix, which indicates that these properties are not mandatory. This will help with initialization of instances of your interface without requiring to initialize all properties :

const myBook: Book = { name: "My new book" };

So, once we know why we must use interfaces, next question is when we should rather use classes. The Mozilla Developper Network gives a quite straightforward answer :

JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript’s existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.

Fixing angular 404 page not found error on page refresh

By default, navigation within an Angular application relies on PathLocationStrategy, which uses HTML5 history.pushState, a technique that changes a browser’s location and history without sending an HTTP request to the server. This is sweet because your application behaves like any web site, while being way more reactive since it skips the browser/server communications.

However, there’s one major drawback, if you refresh your page after visiting an Angular deep link, or if you access it using your favourites or history, your browser will send the request to the server, which will have no hint about the requested resource, and will return a 404 error.

To prevent this, you need to set some server side configuration, which will depend on your web server. Here are the solutions for Apache and Tomcat, on a Debian 10.

Apache

The easiest way is to include a .htaccess, in your Angular application, and to enable Apache rewrite mod

1. Install Apache rewrite mod

sudo a2enmod rewrite
sudo systemctl restart apache

Then add .htaccess in your Angular app folder:

RewriteEngine On
 RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
 RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
 RewriteRule ^ - [L]
 RewriteRule ^ /myAngularAppBase

If you ship the .htaccess with your app, don’t forget to include it in the assets section of your angular.json file

{
...
"assets": [
              "src/.htaccess",
              "src/favicon.ico",
              "src/assets",
              {
                "glob": "**/*",
                "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
                "output": "/assets/"
              }
...
}

Tomcat

1. enable the rewrite valve in /opt/tomcat/conf/context.xml

 <!-- REWRITE VALVE -->  <Valve className="org.apache.catalina.valves.rewrite.RewriteValve" />  <!-- // -->  

2. add rewrite.config file in the project WEB-INF folder with below content such as on /opt/tomcat/webapps/myProject/WEB-INF/rewrite.config.

RewriteCond %{REQUEST_URI} !^.*\.(bmp|css|gif|htc|html?|ico|jpe?g|js|pdf|png|swf|txt|xml|svg|eot|woff|woff2|ttf|map)$ RewriteRule ^(.*)$ /index.html [L]

If you ship it with your Angular app, don’t forget to add WEB-INF folder to your angular.json assets section.

{
...
"assets": [
              "src/WEB-INF",
              "src/favicon.ico",
              "src/assets",
              {
                "glob": "**/*",
                "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/",
                "output": "/assets/"
              }
...
}

403 response to a CORS preflight request from an angular app to a spring security REST API caused by a Access-Control-Request-Headers mismatch

CORS is a pain, I’ve been struggling with a POST to an API whose CORS preflight OPTIONS request was rejected with a 403.

I was going crazy because while the OPTIONS request was rejected when executed from the navigator, it succeeded when executed from the command line using CURL.

curl -v -H "Access-Control-Request-Method: POST" -H "Origin: http://localhost:4200" -X OPTIONS http://localhost:8080/api/v1/documents/upload

 Trying ::1…
 TCP_NODELAY set
 Connected to localhost (::1) port 8080 (#0) 
   OPTIONS /api/v1/documents/upload HTTP/1.1
   Host: localhost:8080
   User-Agent: curl/7.55.1
   Accept: /
   Access-Control-Request-Method: POST
   Origin: http://localhost:4200
   < HTTP/1.1 200
   < Vary: Origin
   < Vary: Access-Control-Request-Method
   < Vary: Access-Control-Request-Headers
   < Access-Control-Allow-Origin: *
   < Access-Control-Allow-Methods: POST
   < X-Content-Type-Options: nosniff
   < X-XSS-Protection: 1; mode=block
   < Cache-Control: no-cache, no-store, max-age=0, must-revalidate
   < Pragma: no-cache
   < Expires: 0
   < X-Frame-Options: DENY
   < Referrer-Policy: origin
   < Content-Length: 0
   < Date: Thu, 18 Mar 2021 22:27:09 GMT
   <
      Connection #0 to host localhost left intact    

This had to be an issue with the browser cache, even though it was weird that it was affecting both Firefox and Chrome, both in normal and private sessions.
But then I started to ensure the CURL request was sending exactly the same headers, and I eventually identified the issue.

The browser, whether Firefox or Chrome, was adding a “Access-Control-Request-Headers: x-requested-with” header. And this header requires a response from the server indicating that it will accept a request with this header. And my Spring Security config was not allowing the “x-requested-with” header:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors()
            .and().csrf().disable()
            .authorizeRequests()
                .anyRequest().access("isAuthenticated() or hasIpAddress('127.0.0.1/24') or hasIpAddress('::1')")
            .and().httpBasic().and().headers().referrerPolicy(ReferrerPolicy.ORIGIN);
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedOriginPattern(CorsConfiguration.ALL);
        configuration.setAllowedMethods(List.of(CorsConfiguration.ALL));
        configuration.setAllowedHeaders(Arrays.asList("authorization", "content-type", "x-auth-token"));
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }    
}

Changing the setAllowedHeaders line to “configuration.setAllowedHeaders(List.of(CorsConfiguration.ALL)); ” eventually fixed the issue.

Fixing angular warning “exceeded maximum budget”

With your Angular application growing, you will bump into the following warning :

WARNING in budgets: bundle initial-es2015 exceeded maximum budget. Budget 2 MB was not met by 169 kB with a total of 2.16 MB.

Fixing it is quite easy, simply edit your angular.json file, locate the “budgets” node, and incrase the limit :

"budgets": [
                 {
                   "type": "initial",
                   "maximumWarning": "3mb",
                   "maximumError": "5mb"
                 },
                 {
                   "type": "anyComponentStyle",
                   "maximumWarning": "6kb",
                   "maximumError": "10kb"
                 }
               ]

Obviously, this is only valid if you’re getting just above the limit, or don’t care about application loading time. Because the warning is here for a reason, and you may eventually have to find out why your application is getting heavier, and how to trim it.