diff --git a/config/config-dev.json b/config/config-dev.json
index 3320942c82b8a0ff6ae8e347c87e619f1ab91685..9308ae9e42a106a4b7a21fa2ffb36f679f8f4ea6 100644
--- a/config/config-dev.json
+++ b/config/config-dev.json
@@ -3,6 +3,6 @@
     "url": "https://kong-dev.alpha.grandlyon.com/organizations/"
   },
   "resources": {
-    "url": "https://kong-dev.alpha.grandlyon.com/resources/resources/"
+    "url": "https://kong-dev.alpha.grandlyon.com/resources/"
   }
 }
\ No newline at end of file
diff --git a/config/config-rec.json b/config/config-rec.json
index 4955a9a3ca1fb9c3cc45c9fc867b4ff120df5e06..a7de2abe2bba321edc2b665835b59d7146cd7e41 100644
--- a/config/config-rec.json
+++ b/config/config-rec.json
@@ -3,6 +3,6 @@
     "url": "https://kong-rec.alpha.grandlyon.com/organizations/"
   },
   "resources": {
-    "url": "https://kong-rec.alpha.grandlyon.com/resources/resources/"
+    "url": "https://kong-rec.alpha.grandlyon.com/resources/"
   }
 }
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 407e9f82fe0cc07b92a531131648fed6ca8d87f1..4880633268b69e163a910ab76ab2c76cce10bede 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -930,6 +930,46 @@
         }
       }
     },
+    "@fimbul/bifrost": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/@fimbul/bifrost/-/bifrost-0.17.0.tgz",
+      "integrity": "sha512-gVTkJAOef5HtN6LPmrtt5fAUmBywwlgmObsU3FBhPoNeXPLaIl2zywXkJEtvvVLQnaFmtff3x+wIj5lHRCDE3Q==",
+      "dev": true,
+      "requires": {
+        "@fimbul/ymir": "^0.17.0",
+        "get-caller-file": "^2.0.0",
+        "tslib": "^1.8.1",
+        "tsutils": "^3.5.0"
+      },
+      "dependencies": {
+        "get-caller-file": {
+          "version": "2.0.5",
+          "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+          "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+          "dev": true
+        },
+        "tsutils": {
+          "version": "3.10.0",
+          "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.10.0.tgz",
+          "integrity": "sha512-q20XSMq7jutbGB8luhKKsQldRKWvyBO2BGqni3p4yq8Ys9bEP/xQw3KepKmMRt9gJ4lvQSScrihJrcKdKoSU7Q==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.8.1"
+          }
+        }
+      }
+    },
+    "@fimbul/ymir": {
+      "version": "0.17.0",
+      "resolved": "https://registry.npmjs.org/@fimbul/ymir/-/ymir-0.17.0.tgz",
+      "integrity": "sha512-xMXM9KTXRLHLVS6dnX1JhHNEkmWHcAVCQ/4+DA1KKwC/AFnGHzu/7QfQttEPgw3xplT+ILf9e3i64jrFwB3JtA==",
+      "dev": true,
+      "requires": {
+        "inversify": "^5.0.0",
+        "reflect-metadata": "^0.1.12",
+        "tslib": "^1.8.1"
+      }
+    },
     "@ngtools/webpack": {
       "version": "7.3.1",
       "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-7.3.1.tgz",
@@ -1489,14 +1529,12 @@
     "ansi-regex": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-      "dev": true
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
     },
     "ansi-styles": {
       "version": "3.2.1",
       "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
       "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-      "dev": true,
       "requires": {
         "color-convert": "^1.9.0"
       }
@@ -1546,7 +1584,6 @@
       "version": "1.0.10",
       "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
       "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "dev": true,
       "requires": {
         "sprintf-js": "~1.0.2"
       }
@@ -1756,7 +1793,6 @@
       "version": "6.26.0",
       "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
       "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
-      "dev": true,
       "requires": {
         "chalk": "^1.1.3",
         "esutils": "^2.0.2",
@@ -1766,14 +1802,12 @@
         "ansi-styles": {
           "version": "2.2.1",
           "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
-          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
-          "dev": true
+          "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
         },
         "chalk": {
           "version": "1.1.3",
           "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
           "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
-          "dev": true,
           "requires": {
             "ansi-styles": "^2.2.1",
             "escape-string-regexp": "^1.0.2",
@@ -1785,8 +1819,7 @@
         "supports-color": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
-          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
-          "dev": true
+          "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
         }
       }
     },
@@ -1882,8 +1915,7 @@
     "balanced-match": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-      "dev": true
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
     },
     "base": {
       "version": "0.11.2",
@@ -2075,7 +2107,6 @@
       "version": "1.1.11",
       "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
       "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "dev": true,
       "requires": {
         "balanced-match": "^1.0.0",
         "concat-map": "0.0.1"
@@ -2118,7 +2149,7 @@
     },
     "browserify-aes": {
       "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+      "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
       "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
       "dev": true,
       "requires": {
@@ -2155,7 +2186,7 @@
     },
     "browserify-rsa": {
       "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+      "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
       "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
       "dev": true,
       "requires": {
@@ -2209,7 +2240,7 @@
     },
     "buffer": {
       "version": "4.9.1",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+      "resolved": "http://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
       "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
       "dev": true,
       "requires": {
@@ -2261,8 +2292,7 @@
     "builtin-modules": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
-      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
-      "dev": true
+      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
     },
     "builtin-status-codes": {
       "version": "3.0.0",
@@ -2340,7 +2370,7 @@
     },
     "camelcase-keys": {
       "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+      "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
       "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
       "dev": true,
       "optional": true,
@@ -2591,7 +2621,6 @@
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
       "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-      "dev": true,
       "requires": {
         "color-name": "1.1.3"
       }
@@ -2599,8 +2628,7 @@
     "color-name": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-      "dev": true
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
     },
     "colors": {
       "version": "1.1.2",
@@ -2629,8 +2657,7 @@
     "commander": {
       "version": "2.17.1",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
-      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
-      "dev": true
+      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
     },
     "commondir": {
       "version": "1.0.1",
@@ -2689,8 +2716,7 @@
     "concat-map": {
       "version": "0.0.1",
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-      "dev": true
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
     "concat-stream": {
       "version": "1.6.2",
@@ -2882,7 +2908,7 @@
     },
     "create-hash": {
       "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+      "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
       "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
       "dev": true,
       "requires": {
@@ -2895,7 +2921,7 @@
     },
     "create-hmac": {
       "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+      "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
       "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
       "dev": true,
       "requires": {
@@ -3208,12 +3234,11 @@
     "diff": {
       "version": "3.5.0",
       "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
-      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
-      "dev": true
+      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
     },
     "diffie-hellman": {
       "version": "5.0.3",
-      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+      "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
       "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
       "dev": true,
       "requires": {
@@ -3256,6 +3281,30 @@
         "buffer-indexof": "^1.0.0"
       }
     },
+    "doctrine": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-0.7.2.tgz",
+      "integrity": "sha1-fLhgNZujvpDgQLJrcpzkv6ZUxSM=",
+      "dev": true,
+      "requires": {
+        "esutils": "^1.1.6",
+        "isarray": "0.0.1"
+      },
+      "dependencies": {
+        "esutils": {
+          "version": "1.1.6",
+          "resolved": "https://registry.npmjs.org/esutils/-/esutils-1.1.6.tgz",
+          "integrity": "sha1-wBzKqa5LiXxtDD4hCuUvPHqEQ3U=",
+          "dev": true
+        },
+        "isarray": {
+          "version": "0.0.1",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
+          "dev": true
+        }
+      }
+    },
     "dom-serialize": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
@@ -3520,8 +3569,7 @@
     "escape-string-regexp": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-      "dev": true
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
     "eslint-scope": {
       "version": "4.0.0",
@@ -3551,8 +3599,7 @@
     "esutils": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
-      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
-      "dev": true
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
     },
     "etag": {
       "version": "1.8.1",
@@ -4022,7 +4069,7 @@
     },
     "finalhandler": {
       "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
+      "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
       "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
       "dev": true,
       "requires": {
@@ -4198,8 +4245,7 @@
     "fs.realpath": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-      "dev": true
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
     "fsevents": {
       "version": "1.2.4",
@@ -4242,14 +4288,12 @@
         "balanced-match": {
           "version": "1.0.0",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "brace-expansion": {
           "version": "1.1.11",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "balanced-match": "^1.0.0",
             "concat-map": "0.0.1"
@@ -4269,8 +4313,7 @@
         "concat-map": {
           "version": "0.0.1",
           "bundled": true,
-          "dev": true,
-          "optional": true
+          "dev": true
         },
         "console-control-strings": {
           "version": "1.1.0",
@@ -4418,7 +4461,6 @@
           "version": "3.0.4",
           "bundled": true,
           "dev": true,
-          "optional": true,
           "requires": {
             "brace-expansion": "^1.1.7"
           }
@@ -4815,7 +4857,6 @@
       "version": "7.1.3",
       "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
       "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
-      "dev": true,
       "requires": {
         "fs.realpath": "^1.0.0",
         "inflight": "^1.0.4",
@@ -4989,7 +5030,6 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
       "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
-      "dev": true,
       "requires": {
         "ansi-regex": "^2.0.0"
       }
@@ -5020,8 +5060,7 @@
     "has-flag": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-      "dev": true
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
     },
     "has-unicode": {
       "version": "2.0.1",
@@ -5180,7 +5219,7 @@
     },
     "http-proxy-middleware": {
       "version": "0.18.0",
-      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz",
+      "resolved": "http://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.18.0.tgz",
       "integrity": "sha512-Fs25KVMPAIIcgjMZkVHJoKg9VcXcC1C8yb9JUgeDvVXY0S/zgVIhMb+qVswDIgtJe2DfckMSY2d6TuTEutlk6Q==",
       "dev": true,
       "requires": {
@@ -5407,7 +5446,6 @@
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
       "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-      "dev": true,
       "requires": {
         "once": "^1.3.0",
         "wrappy": "1"
@@ -5416,8 +5454,7 @@
     "inherits": {
       "version": "2.0.3",
       "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-      "dev": true
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
     },
     "ini": {
       "version": "1.3.5",
@@ -5523,6 +5560,12 @@
         "loose-envify": "^1.0.0"
       }
     },
+    "inversify": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/inversify/-/inversify-5.0.1.tgz",
+      "integrity": "sha512-Ieh06s48WnEYGcqHepdsJUIJUXpwH5o5vodAX+DK2JA/gjy4EbEcQZxw+uFfzysmKjiLXGYwNG3qDZsKVMcINQ==",
+      "dev": true
+    },
     "invert-kv": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
@@ -6067,14 +6110,12 @@
     "js-tokens": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
-      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
-      "dev": true
+      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
     },
     "js-yaml": {
       "version": "3.12.0",
       "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
       "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==",
-      "dev": true,
       "requires": {
         "argparse": "^1.0.7",
         "esprima": "^4.0.0"
@@ -6083,8 +6124,7 @@
         "esprima": {
           "version": "4.0.1",
           "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-          "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-          "dev": true
+          "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
         }
       }
     },
@@ -6391,7 +6431,7 @@
     },
     "load-json-file": {
       "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
       "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
       "dev": true,
       "requires": {
@@ -6769,7 +6809,7 @@
       "dependencies": {
         "minimist": {
           "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
           "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
           "dev": true,
           "optional": true
@@ -6874,7 +6914,6 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
       "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "dev": true,
       "requires": {
         "brace-expansion": "^1.1.7"
       }
@@ -6882,8 +6921,7 @@
     "minimist": {
       "version": "0.0.8",
       "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
-      "dev": true
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
     },
     "minipass": {
       "version": "2.3.5",
@@ -7104,7 +7142,7 @@
       "dependencies": {
         "semver": {
           "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+          "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
           "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
           "dev": true,
           "optional": true
@@ -7196,7 +7234,7 @@
         },
         "chalk": {
           "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+          "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
           "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
           "dev": true,
           "optional": true,
@@ -7459,7 +7497,6 @@
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
       "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "dev": true,
       "requires": {
         "wrappy": "1"
       }
@@ -7486,7 +7523,6 @@
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
       "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-      "dev": true,
       "requires": {
         "minimist": "~0.0.1",
         "wordwrap": "~0.0.2"
@@ -7495,8 +7531,7 @@
         "wordwrap": {
           "version": "0.0.3",
           "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
-          "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
-          "dev": true
+          "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
         }
       }
     },
@@ -7523,7 +7558,7 @@
     },
     "os-locale": {
       "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
+      "resolved": "http://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
       "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
       "dev": true,
       "optional": true,
@@ -7868,8 +7903,7 @@
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
-      "dev": true
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
     },
     "path-is-inside": {
       "version": "1.0.2",
@@ -7886,8 +7920,7 @@
     "path-parse": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
-      "dev": true
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
     },
     "path-to-regexp": {
       "version": "0.1.7",
@@ -8689,7 +8722,6 @@
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz",
       "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==",
-      "dev": true,
       "requires": {
         "path-parse": "^1.0.5"
       }
@@ -8788,6 +8820,30 @@
         "tslib": "^1.9.0"
       }
     },
+    "rxjs-tslint": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/rxjs-tslint/-/rxjs-tslint-0.1.7.tgz",
+      "integrity": "sha512-NnOfqutNfdT7VQnQm32JLYh2gDZjc0gdWZFtrxf/czNGkLKJ1nOO6jbKAFI09W0f9lCtv6P2ozxjbQH8TSPPFQ==",
+      "requires": {
+        "chalk": "^2.4.0",
+        "optimist": "^0.6.1",
+        "tslint": "^5.9.1",
+        "tsutils": "^2.25.0",
+        "typescript": ">=2.8.3"
+      },
+      "dependencies": {
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "requires": {
+            "ansi-styles": "^3.2.1",
+            "escape-string-regexp": "^1.0.5",
+            "supports-color": "^5.3.0"
+          }
+        }
+      }
+    },
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -8852,7 +8908,7 @@
     },
     "sax": {
       "version": "0.5.8",
-      "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
+      "resolved": "http://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
       "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=",
       "dev": true
     },
@@ -8931,8 +8987,7 @@
     "semver": {
       "version": "5.6.0",
       "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
-      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
-      "dev": true
+      "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
     },
     "semver-dsl": {
       "version": "1.0.1",
@@ -9057,7 +9112,7 @@
     },
     "sha.js": {
       "version": "2.4.11",
-      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+      "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
       "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
       "dev": true,
       "requires": {
@@ -9587,8 +9642,7 @@
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
     },
     "sshpk": {
       "version": "1.15.1",
@@ -9754,7 +9808,6 @@
       "version": "3.0.1",
       "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
       "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
-      "dev": true,
       "requires": {
         "ansi-regex": "^2.0.0"
       }
@@ -9848,7 +9901,6 @@
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
       "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-      "dev": true,
       "requires": {
         "has-flag": "^3.0.0"
       }
@@ -10260,7 +10312,6 @@
       "version": "5.9.1",
       "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.9.1.tgz",
       "integrity": "sha1-ElX4ej/1frCw4fDmEKi0dIBGya4=",
-      "dev": true,
       "requires": {
         "babel-code-frame": "^6.22.0",
         "builtin-modules": "^1.1.1",
@@ -10280,7 +10331,6 @@
           "version": "2.4.1",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
           "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
-          "dev": true,
           "requires": {
             "ansi-styles": "^3.2.1",
             "escape-string-regexp": "^1.0.5",
@@ -10289,11 +10339,80 @@
         }
       }
     },
+    "tslint-config-airbnb": {
+      "version": "5.11.1",
+      "resolved": "https://registry.npmjs.org/tslint-config-airbnb/-/tslint-config-airbnb-5.11.1.tgz",
+      "integrity": "sha512-hkaittm2607vVMe8eotANGN1CimD5tor7uoY3ypg2VTtEcDB/KGWYbJOz58t8LI4cWSyWtgqYQ5F0HwKxxhlkQ==",
+      "dev": true,
+      "requires": {
+        "tslint-consistent-codestyle": "^1.14.1",
+        "tslint-eslint-rules": "^5.4.0",
+        "tslint-microsoft-contrib": "~5.2.1"
+      }
+    },
+    "tslint-consistent-codestyle": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/tslint-consistent-codestyle/-/tslint-consistent-codestyle-1.15.1.tgz",
+      "integrity": "sha512-38Y3Dz4zcABe/PlPAQSGNEWPGVq0OzcIQR7SEU6dNujp/SgvhxhJOhIhI9gY4r0I3/TNtvVQwARWor9O9LPZWg==",
+      "dev": true,
+      "requires": {
+        "@fimbul/bifrost": "^0.17.0",
+        "tslib": "^1.7.1",
+        "tsutils": "^2.29.0"
+      }
+    },
+    "tslint-eslint-rules": {
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/tslint-eslint-rules/-/tslint-eslint-rules-5.4.0.tgz",
+      "integrity": "sha512-WlSXE+J2vY/VPgIcqQuijMQiel+UtmXS+4nvK4ZzlDiqBfXse8FAvkNnTcYhnQyOTW5KFM+uRRGXxYhFpuBc6w==",
+      "dev": true,
+      "requires": {
+        "doctrine": "0.7.2",
+        "tslib": "1.9.0",
+        "tsutils": "^3.0.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "1.9.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.0.tgz",
+          "integrity": "sha512-f/qGG2tUkrISBlQZEjEqoZ3B2+npJjIf04H1wuAv9iA8i04Icp+61KRXxFdha22670NJopsZCIjhC3SnjPRKrQ==",
+          "dev": true
+        },
+        "tsutils": {
+          "version": "3.10.0",
+          "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.10.0.tgz",
+          "integrity": "sha512-q20XSMq7jutbGB8luhKKsQldRKWvyBO2BGqni3p4yq8Ys9bEP/xQw3KepKmMRt9gJ4lvQSScrihJrcKdKoSU7Q==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.8.1"
+          }
+        }
+      }
+    },
+    "tslint-microsoft-contrib": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/tslint-microsoft-contrib/-/tslint-microsoft-contrib-5.2.1.tgz",
+      "integrity": "sha512-PDYjvpo0gN9IfMULwKk0KpVOPMhU6cNoT9VwCOLeDl/QS8v8W2yspRpFFuUS7/c5EIH/n8ApMi8TxJAz1tfFUA==",
+      "dev": true,
+      "requires": {
+        "tsutils": "^2.27.2 <2.29.0"
+      },
+      "dependencies": {
+        "tsutils": {
+          "version": "2.28.0",
+          "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.28.0.tgz",
+          "integrity": "sha512-bh5nAtW0tuhvOJnx1GLRn5ScraRLICGyJV5wJhtRWOLsxW70Kk5tZtpK3O/hW6LDnqKS9mlUMPZj9fEMJ0gxqA==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.8.1"
+          }
+        }
+      }
+    },
     "tsutils": {
       "version": "2.29.0",
       "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
       "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
-      "dev": true,
       "requires": {
         "tslib": "^1.8.1"
       }
@@ -10338,8 +10457,7 @@
     "typescript": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.4.tgz",
-      "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg==",
-      "dev": true
+      "integrity": "sha512-0RNDbSdEokBeEAkgNbxJ+BLwSManFy9TeXz8uW+48j/xhEXv1ePME60olyzw2XzUqUBNAYFeJadIqAgNqIACwg=="
     },
     "uglify-js": {
       "version": "3.4.9",
@@ -11133,8 +11251,7 @@
     "wrappy": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
-      "dev": true
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
     },
     "xml2js": {
       "version": "0.4.19",
diff --git a/package.json b/package.json
index 44e295b09d709f0807cae53bd0e4fbed2c2ed20d..b439c2ad49e9862ec4e3af38cb8d4edeeb613360 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
     "bulma": "^0.7.4",
     "core-js": "^2.6.4",
     "rxjs": "^6.4.0",
+    "rxjs-tslint": "^0.1.7",
     "sass-recursive-map-merge": "^1.0.1",
     "zone.js": "^0.8.29"
   },
@@ -48,6 +49,7 @@
     "protractor": "^5.4.2",
     "ts-node": "~5.0.1",
     "tslint": "~5.9.1",
+    "tslint-config-airbnb": "^5.11.1",
     "typescript": "~3.2.4"
   }
 }
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 75e19beeeef3748f190ce47d71bba6935be957f6..d00c62e939d0fa8b9677eab2569861298897d7ec 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -1,8 +1,5 @@
 import { Component, OnInit } from '@angular/core';
 
-
-
-
 @Component({
   selector: 'app-root',
   templateUrl: './app.component.html',
@@ -14,13 +11,9 @@ export class AppComponent implements OnInit {
   sidebarOpened: boolean;
 
   constructor(
-  ) {
-  }
-
-
+  ) {}
 
   ngOnInit(): void {
     this.sidebarOpened = false;
   }
-
 }
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index c5e0ccd4a906c771333afc79d90f75d50cdf6476..9b843b6f527b5aebbae62eec91003795da9b875f 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -41,6 +41,6 @@ export function initAppConfig(appConfigService: AppConfigService) {
       multi: true,
     },
   ],
-  bootstrap: [AppComponent]
+  bootstrap: [AppComponent],
 })
 export class AppModule { }
diff --git a/src/app/app.routing.module.ts b/src/app/app.routing.module.ts
index 23e3d791e5f1e9615cc870ed1b5260219d76c007..2e229688a10fc14059435ecf98a68a990b6f7dc4 100644
--- a/src/app/app.routing.module.ts
+++ b/src/app/app.routing.module.ts
@@ -7,7 +7,7 @@ import { OrganizationFormComponent } from './components/organizations/edit/organ
 import { ResourcesComponent } from './components/resources/list/resources.component';
 import { ResourceFormComponent } from './components/resources/edit/resource-form.component';
 import { ResourceDetailComponent } from './components/resources/detail/resource-detail.component';
-
+import { FormatsComponent, FormatDetailComponent, FormatFormComponent } from './components';
 
 const appRoutes: Routes = [
   {
@@ -73,6 +73,34 @@ const appRoutes: Routes = [
       title: 'Ressource',
     },
   },
+  {
+    path: 'formats',
+    component: FormatsComponent,
+    data: {
+      title: 'Formats',
+    },
+  },
+  {
+    path: 'formats/new',
+    component: FormatFormComponent,
+    data: {
+      title: 'Nouveau format',
+    },
+  },
+  {
+    path: 'formats/:id/edit',
+    component: FormatFormComponent,
+    data: {
+      title: 'Modifier le format',
+    },
+  },
+  {
+    path: 'formats/:id',
+    component: FormatDetailComponent,
+    data: {
+      title: 'Format',
+    },
+  },
 ];
 
 @NgModule({
diff --git a/src/app/components/back-button/back-button.component.ts b/src/app/components/back-button/back-button.component.ts
index 33f58095d95ea1e96ecf536c83eef56992a6e48e..cc592862d5aa1e1a21ace689ea34303c7ba33bef 100644
--- a/src/app/components/back-button/back-button.component.ts
+++ b/src/app/components/back-button/back-button.component.ts
@@ -3,7 +3,7 @@ import { Component, OnInit, Input } from '@angular/core';
 @Component({
   selector: 'app-back-button',
   templateUrl: './back-button.component.html',
-  styleUrls: ['./back-button.component.scss']
+  styleUrls: ['./back-button.component.scss'],
 })
 export class BackButtonComponent implements OnInit {
 
diff --git a/src/app/components/crud-buttons/crud-buttons.component.ts b/src/app/components/crud-buttons/crud-buttons.component.ts
index 0a3bac7b3ca2f41be5acedecca3c21c68f6ff371..e2c660fee6700844e460b114711754ddc473b7ae 100644
--- a/src/app/components/crud-buttons/crud-buttons.component.ts
+++ b/src/app/components/crud-buttons/crud-buttons.component.ts
@@ -4,7 +4,7 @@ import { identifierModuleUrl } from '@angular/compiler';
 @Component({
   selector: 'app-crud-buttons',
   templateUrl: './crud-buttons.component.html',
-  styleUrls: ['./crud-buttons.component.scss']
+  styleUrls: ['./crud-buttons.component.scss'],
 })
 export class CrudButtonsComponent implements OnInit {
 
diff --git a/src/app/components/formats/detail/format-detail.component.html b/src/app/components/formats/detail/format-detail.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..5b979c6ae2423ed464967f896ab6b68b29ead171
--- /dev/null
+++ b/src/app/components/formats/detail/format-detail.component.html
@@ -0,0 +1,30 @@
+<ng-container *ngIf="format">
+
+  <app-back-button [route]="'/formats'" [title]="'Retourner à la liste des formats'"></app-back-button>
+
+  <section class="section">
+    <div class="columns is-centered">
+      <div class="column is-8">
+        <div class="card">
+          <header class="card-header">
+            <p class="card-header-title has-text-centered">
+              {{format.name}}
+            </p>
+          </header>
+          <div class="card-content">
+            <div class="content">
+              <p>
+                <span class="has-text-weight-bold">Id: </span>
+                <span>{{format.id}}</span>
+              </p>
+              <p>
+                <span class="has-text-weight-bold">Type MapServer: </span>
+                <span>{{format.mapServerType}}</span>
+              </p>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </section>
+</ng-container>
diff --git a/src/app/components/formats/detail/format-detail.component.scss b/src/app/components/formats/detail/format-detail.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..163f99f474dc5696a1670be5273eef97a2efbd39
--- /dev/null
+++ b/src/app/components/formats/detail/format-detail.component.scss
@@ -0,0 +1,3 @@
+.card-header-title {
+  justify-content: center;
+}
\ No newline at end of file
diff --git a/src/app/components/formats/detail/format-detail.component.ts b/src/app/components/formats/detail/format-detail.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..52b8bf8ce53e15d473d61a1639262df97609b87b
--- /dev/null
+++ b/src/app/components/formats/detail/format-detail.component.ts
@@ -0,0 +1,28 @@
+
+import { switchMap } from 'rxjs/operators';
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, ParamMap } from '@angular/router';
+import { FormatService } from 'src/app/services';
+import { Format } from 'src/app/models/format.model';
+
+@Component({
+  selector: 'app-format-detail',
+  templateUrl: './format-detail.component.html',
+  styleUrls: ['./format-detail.component.scss'],
+})
+export class FormatDetailComponent implements OnInit {
+
+  format: Format;
+
+  constructor(
+    private _route: ActivatedRoute,
+    private _formatService: FormatService,
+  ) {
+  }
+
+  ngOnInit(): void {
+    this._route.paramMap.pipe(
+      switchMap((params: ParamMap) => this._formatService.findById(params.get('id'))))
+      .subscribe((format: Format) => this.format = format);
+  }
+}
diff --git a/src/app/components/formats/edit/format-form.component.html b/src/app/components/formats/edit/format-form.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..767de654e6e0e0bf0f059b5312a9627c431aa551
--- /dev/null
+++ b/src/app/components/formats/edit/format-form.component.html
@@ -0,0 +1,35 @@
+<ng-container *ngIf="format">
+
+  <app-back-button [route]="'/organizations'" [title]="'Retourner à la liste des formats'"></app-back-button>
+
+  <h1>{{ title }}</h1>
+
+  <form [formGroup]="form" (ngSubmit)="onSubmit()" class="columns is-centered is-marginless">
+    <div class="column is-7">
+      <input type="hidden" formControlName="id" value="{{format.id}}">
+
+      <div class="field">
+        <label class="label required" for="name">Nom</label>
+        <div class="control">
+          <input class="input" type="text" [value]="format.name" formControlName="name" id="name" required>
+        </div>
+        <div *ngIf="name.invalid && (name.dirty || name.touched)" class="alert alert-danger">
+          <p *ngIf="name.errors['required']" class="help is-danger">
+            Le nom du format est obligatoire.
+          </p>
+        </div>
+      </div>
+
+      <div class="field">
+        <label class="label" for="mapServerType">Type MapServer</label>
+        <div class="control">
+          <input class="input" type="text" [value]="format.mapServerType" formControlName="mapServerType" id="mapServerType">
+        </div>
+      </div>
+
+      <div class="has-text-right">
+        <button class="button button-gl" type="submit" [disabled]="formInvalid == true">Valider</button>
+      </div>
+    </div>
+  </form>
+</ng-container>
diff --git a/src/app/components/formats/edit/format-form.component.scss b/src/app/components/formats/edit/format-form.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..5bea26fe55b4ab7bb07da39d6140df0c988864d4
--- /dev/null
+++ b/src/app/components/formats/edit/format-form.component.scss
@@ -0,0 +1,19 @@
+.full-width {
+  width: 100%;
+}
+
+h1 {
+  text-align: center
+}
+
+.icon {
+  cursor: pointer;
+  &:hover {
+    .fa-plus {
+      color: lightblue;
+    }
+    .fa-trash {
+      color: #d5232a;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/app/components/formats/edit/format-form.component.ts b/src/app/components/formats/edit/format-form.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..73665239d0f197242529f11b22649a127bd5d4e8
--- /dev/null
+++ b/src/app/components/formats/edit/format-form.component.ts
@@ -0,0 +1,78 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, ParamMap, Router } from '@angular/router';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { filter, switchMap } from 'rxjs/operators';
+import { Format } from 'src/app/models/format.model';
+import { FormatService } from 'src/app/services';
+
+@Component({
+  selector: 'app-format-form',
+  templateUrl: './format-form.component.html',
+  styleUrls: ['./format-form.component.scss'],
+})
+export class FormatFormComponent implements OnInit {
+
+  format: Format = new Format();
+  form: FormGroup;
+  title: string;
+
+  constructor(
+    private _formatService: FormatService,
+    private _route: ActivatedRoute,
+    private _router: Router,
+    private _fb: FormBuilder,
+  ) {
+  }
+
+  ngOnInit() {
+    this.title = this._route.snapshot.data.title;
+    this.initForm();
+
+    this._route.paramMap.pipe(
+      filter((paramMap: ParamMap) => (paramMap.get('id') !== null)),
+      switchMap((paramMap: ParamMap) => this._formatService.findById(paramMap.get('id'))))
+      .subscribe((format: Format) => {
+
+        this.format = format;
+
+        this.initForm();
+
+      });
+  }
+
+  initForm() {
+    this.form = this._fb.group({
+      id: [this.format.id],
+      name: [this.format.name, Validators.required],
+      mapServerType: [this.format.mapServerType, Validators.required],
+    });
+  }
+
+  onSubmit() {
+    if (!this.formInvalid) {
+      this.format = new Format(this.form.value);
+      this._formatService.replaceOrCreate(this.format)
+        .subscribe(
+          (formatCreated) => {
+            this._router.navigate(['/formats', formatCreated.id]);
+          },
+          (err) => {
+            alert(err.message);
+          },
+        );
+    }
+  }
+
+  // Getters for each property
+  get name() {
+    return this.form.controls['name'];
+  }
+
+  get mapServerType() {
+    return this.form.controls['mapServerType'];
+  }
+
+  get formInvalid() {
+    return this.form.invalid;
+  }
+}
diff --git a/src/app/components/formats/list/formats.component.html b/src/app/components/formats/list/formats.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..9bb68d7be561e6f54b47659456ac6e85f63b8a16
--- /dev/null
+++ b/src/app/components/formats/list/formats.component.html
@@ -0,0 +1,59 @@
+<ng-container *ngIf="formats">
+  <div>
+    <div class="section">
+      <div class="columns is-centered is-marginless">
+        <div class="column has-text-centered">
+          <h2>{{ totalElement }} formats trouvés</h2>
+        </div>
+      </div>
+      <div class="add-item has-text-right">
+        <a class="button button-gl" [routerLink]="['new']">
+          Ajouter
+        </a>
+      </div>
+      <div class="table">
+        <div class="header columns is-marginless">
+          <div class="column is-2 has-text-centered">
+            <span (click)="sortBy('name')" class="is-sortable">
+              <span class="column-title" [ngClass]="{'active': sortOptions.value === name}">Name</span>
+              <span *ngIf="sortOptions.value  === 'name'" class="has-text-danger">
+                <i class="fas sort-order-icon"
+                  [ngClass]="{'fa-arrow-up': sortOptions.order === 'asc', 'fa-arrow-down': sortOptions.order === 'desc'}"></i>
+              </span>
+            </span>
+          </div>
+          <div class="column is-2 has-text-centered">
+            <span class="column-title">Type MapServer</span>
+          </div>
+          <div class="column is-offset-7 is-1 has-text-centered">
+              <span class="column-title">Actions</span>
+            </div>
+        </div>
+        <div class="data-list">
+          <div class="data columns is-multiline is-vcentered is-marginless"
+            *ngFor="let format of formats; let i=index; let odd=odd; let even=even;"
+            [ngClass]="{ odd: odd, even: even }">
+            <div class="column is-2 has-text-centered">
+              {{ format.name}}
+            </div>
+            <div class="column is-2 has-text-centered">
+              {{ format.mapServerType}}
+            </div>
+            <div class="column is-offset-7 is-1 has-text-centered actions"> 
+                <app-crud-buttons [id]="format.id" (delete)="displayDeletePopup($event)"></app-crud-buttons>
+            </div>
+          </div>
+        </div>
+        <div class="columns is-marginless">
+          <div class="column">
+            <app-paginator *ngIf="paginator.length > 0" [length]="paginator.length" [pageSize]="paginator.limit"
+              [pageSizeOptions]="paginator.pageSizeOptions" [pageIndex]="paginator.pageIndex" [pagesToShow]="5"
+              [showFirstLastButtons]="true" (page)="changePagination($event)"
+              (pageSizeChanged)="changePageSize($event)">
+            </app-paginator>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</ng-container>
diff --git a/src/app/components/formats/list/formats.component.scss b/src/app/components/formats/list/formats.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..087d2f4242ed39d8f3505d06012bf823f015572e
--- /dev/null
+++ b/src/app/components/formats/list/formats.component.scss
@@ -0,0 +1,53 @@
+section {
+  padding: 20px;
+}
+.section {
+  padding-top: 0;
+}
+
+.table {
+  background-color: white;
+  border: 1px solid lightgray;
+}
+
+.center {
+  text-align: center;
+}
+
+img {
+  max-width: 100px;
+}
+
+.header {
+  border-bottom: 1px solid lightgray;
+  background-color: #fafafa;
+  span {
+    color: #999;
+
+  }
+}
+
+.is-sortable .column-title {
+  cursor: pointer;
+}
+
+.table .columns {
+  border-bottom: 1px solid lightgray
+}
+
+i {
+
+  &.title-icon {
+    margin-right: 0.75rem;
+  }
+
+  &.sort-order-icon {
+    padding-left: 0.75rem;
+    cursor: pointer;
+  }
+}
+
+
+.add-item {
+  margin-bottom: 20px;
+}
diff --git a/src/app/components/formats/list/formats.component.ts b/src/app/components/formats/list/formats.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0efba29653deeaa91189cc967d4cfe9a8edea5bb
--- /dev/null
+++ b/src/app/components/formats/list/formats.component.ts
@@ -0,0 +1,99 @@
+import { Component, OnInit } from '@angular/core';
+import { FormatService } from 'src/app/services/format.service';
+import { Subscription } from 'rxjs';
+import { PaginatorOptions } from 'src/app/models/paginator-options.model';
+import { Format, FormatRO } from 'src/app/models/format.model';
+
+@Component({
+  selector: 'app-formats',
+  templateUrl: './formats.component.html',
+  styleUrls: ['./formats.component.scss'],
+})
+export class FormatsComponent implements OnInit {
+
+  formats: Format[];
+  searchChangeSub: Subscription;
+
+  // Paginator options
+  paginator: PaginatorOptions;
+
+  sortValue: string;
+
+  totalElement: number;
+  pageSize = 10;
+  pageSizeOptions = [5, 10, 25, 100];
+  filters = {
+    name: '',
+  };
+  where = {};
+
+  constructor(
+    private formatsService: FormatService,
+  ) {
+    this.paginator = {
+      pageIndex: this.formatsService.pageNumber,
+      length: 0,
+      limit: this.formatsService.limit,
+      pageSizeOptions: [5, 10, 20],
+    };
+  }
+
+  ngOnInit(): void {
+    this.formatsService.sortOptions = {
+      value: 'name',
+      order: 'asc',
+    };
+    this.search();
+
+    this.searchChangeSub = this.formatsService.searchChange$.subscribe(
+      () => {
+        this.search();
+      },
+    );
+  }
+
+  private search() {
+    this.formatsService.getFormats()
+      .subscribe((items: FormatRO) => {
+        this.formats = items.formats;
+        this.totalElement = items.totalCount;
+
+        this.paginator.limit = this.formatsService.limit;
+        this.paginator.pageIndex = this.formatsService.pageNumber;
+        this.paginator.length = items.totalCount;
+      });
+  }
+
+  // When pagination is changed by user, we update datasetList with new pagination options
+  changePagination(pageIndex) {
+    this.formatsService.paginationChanged(this.paginator.limit, pageIndex);
+  }
+
+  changePageSize(pageSize) {
+    this.formatsService.paginationChanged(pageSize, 1);
+  }
+
+  sortBy(key: string) {
+    if (this.formatsService.sortOptions.value === key) {
+      this.formatsService.reverseSortOrder();
+    } else {
+      this.formatsService.sortOptions.value = key;
+      this.formatsService.sortOptions.order = 'asc';
+    }
+    this.search();
+  }
+
+  get sortOptions() {
+    return this.formatsService.sortOptions;
+  }
+
+  displayDeletePopup(formatId) {
+    const pop = confirm('Etes vous sûr de vouloir supprimer ce format ?');
+    if (pop) {
+      this.formatsService.delete(formatId).subscribe(() => {
+        this.formatsService.pageNumber = 1;
+        this.search();
+      });
+    }
+  }
+}
diff --git a/src/app/components/index.ts b/src/app/components/index.ts
index 82b8a02c961a116605d337102075886e519301ef..89665a7ff83dd6f5194d383a3563407781116bbd 100644
--- a/src/app/components/index.ts
+++ b/src/app/components/index.ts
@@ -9,6 +9,9 @@ import { ResourcesComponent } from './resources/list/resources.component';
 import { WelcomeComponent } from './welcome/welcome.component';
 import { BackButtonComponent } from './back-button/back-button.component';
 import { CrudButtonsComponent } from './crud-buttons/crud-buttons.component';
+import { FormatsComponent } from './formats/list/formats.component';
+import { FormatDetailComponent } from './formats/detail/format-detail.component';
+import { FormatFormComponent } from './formats/edit/format-form.component';
 
 export {
   MenuComponent,
@@ -22,6 +25,9 @@ export {
   WelcomeComponent,
   BackButtonComponent,
   CrudButtonsComponent,
+  FormatsComponent,
+  FormatDetailComponent,
+  FormatFormComponent,
 };
 
 // tslint:disable-next-line:variable-name
@@ -37,4 +43,7 @@ export const AppComponents = [
   WelcomeComponent,
   BackButtonComponent,
   CrudButtonsComponent,
+  FormatsComponent,
+  FormatDetailComponent,
+  FormatFormComponent,
 ];
diff --git a/src/app/components/menu/menu.component.html b/src/app/components/menu/menu.component.html
index 63c9727b0315c031bea447c498e166b48b913e8a..5652d6a7c9467e4a64f59bbcf700726943dbb027 100644
--- a/src/app/components/menu/menu.component.html
+++ b/src/app/components/menu/menu.component.html
@@ -22,5 +22,12 @@
       <span class="label-menu">Ressources</span> 
       </a>
     </li>
+    <li><a [routerLink]="['/', 'formats']" routerLinkActive="active-link">
+      <span class="icon">
+          <i class="far fa-file"></i>
+        </span>
+      <span class="label-menu">Formats</span> 
+      </a>
+    </li>
   </ul>
 </aside>
diff --git a/src/app/components/organizations/edit/organization-form.component.ts b/src/app/components/organizations/edit/organization-form.component.ts
index 3c2ce77e6618f345bdf34710f8783202e94f06bc..7c8e5e506f175a320dfb65e0d0e3c9011827a992 100644
--- a/src/app/components/organizations/edit/organization-form.component.ts
+++ b/src/app/components/organizations/edit/organization-form.component.ts
@@ -36,7 +36,7 @@ export class OrganizationFormComponent implements OnInit {
         this.organization = organization;
 
         const arr = new FormArray([]);
-        this.organization.links.forEach(y => {
+        this.organization.links.forEach((y) => {
           arr.push(this._fb.group({
             url: y.url,
             organizationId: y.organizationId,
@@ -83,9 +83,12 @@ export class OrganizationFormComponent implements OnInit {
       this.organization.links = [];
     }
     (this.form.controls.links as FormArray).push(this._fb.group(
-      { id: null, name: '',
-      url: ['', Validators.required],
-      organizationId: this.organization.id }));
+      {
+        id: null, name: '',
+        url: ['', Validators.required],
+        organizationId: this.organization.id,
+      }),
+    );
   }
 
   removeLink(index) {
@@ -97,7 +100,7 @@ export class OrganizationFormComponent implements OnInit {
   }
 
   onSubmit() {
-    if (! this.formInvalid) {
+    if (!this.formInvalid) {
       this.organization = new Organization(this.form.value);
       this.organizationService.replaceOrCreate(this.organization)
         .subscribe(
diff --git a/src/app/components/organizations/list/organizations.component.ts b/src/app/components/organizations/list/organizations.component.ts
index 1446082e05c3a420538d0087156f94c5bb0421bb..60020afb5dd4c14df58fccfe84cb081347bc9620 100644
--- a/src/app/components/organizations/list/organizations.component.ts
+++ b/src/app/components/organizations/list/organizations.component.ts
@@ -13,7 +13,6 @@ export class OrganizationsComponent implements OnInit {
 
   organizations: Organization[];
   searchChangeSub: Subscription;
-  displayedColumns = ['name', 'logo', 'description', 'liens', 'actions'];
 
   // Paginator options
   paginator: PaginatorOptions;
@@ -42,7 +41,7 @@ export class OrganizationsComponent implements OnInit {
   ngOnInit(): void {
     this.organizationsService.sortOptions = {
       value: 'name',
-      order: 'asc'
+      order: 'asc',
     };
     this.search();
 
@@ -65,7 +64,6 @@ export class OrganizationsComponent implements OnInit {
       });
   }
 
-
   // When pagination is changed by user, we update datasetList with new pagination options
   changePagination(pageIndex) {
     this.organizationsService.paginationChanged(this.paginator.limit, pageIndex);
@@ -91,7 +89,7 @@ export class OrganizationsComponent implements OnInit {
 
   displayDeletePopup(organizationId) {
     const pop = confirm('Etes vous sûr de vouloir supprimer cette organisation ?');
-    if (pop === true) {
+    if (pop) {
       this.organizationsService.delete(organizationId).subscribe(() => {
         this.organizationsService.pageNumber = 1;
         this.search();
diff --git a/src/app/components/resources/edit/resource-form.component.ts b/src/app/components/resources/edit/resource-form.component.ts
index 0f118dd0a45c970fa997816d66c4724af676030e..2448c74d4f952a4d018b58754d381a14ccd7c022 100644
--- a/src/app/components/resources/edit/resource-form.component.ts
+++ b/src/app/components/resources/edit/resource-form.component.ts
@@ -73,11 +73,11 @@ export class ResourceFormComponent implements OnInit {
   }
 
   arrayToString(array: string[]) {
+    let val = '';
     if (array && array.length) {
-      return array.join(',');
-    } else {
-      return '';
+      val = array.join(',');
     }
+    return val;
   }
 
   // Getters for each property
diff --git a/src/app/components/resources/list/resources.component.ts b/src/app/components/resources/list/resources.component.ts
index 7519c0f0196bbe48af9f9d3705f46c942fc94040..a56ed6ddeeaf05512edcd33cddbfa12247c45bb7 100644
--- a/src/app/components/resources/list/resources.component.ts
+++ b/src/app/components/resources/list/resources.component.ts
@@ -41,7 +41,7 @@ export class ResourcesComponent implements OnInit {
   ngOnInit(): void {
     this.resourcesService.sortOptions = {
       value: 'name',
-      order: 'asc'
+      order: 'asc',
     };
     this.search();
 
@@ -64,7 +64,6 @@ export class ResourcesComponent implements OnInit {
       });
   }
 
-
   // When pagination is changed by user, we update datasetList with new pagination options
   changePagination(pageIndex) {
     this.resourcesService.paginationChanged(this.paginator.limit, pageIndex);
@@ -90,7 +89,7 @@ export class ResourcesComponent implements OnInit {
 
   displayDeletePopup(resourceId) {
     const pop = confirm('Etes vous sûr de vouloir supprimer cette ressource ?');
-    if (pop === true) {
+    if (pop) {
       this.resourcesService.delete(resourceId).subscribe(() => {
         this.resourcesService.pageNumber = 1;
         this.search();
diff --git a/src/app/models/format.model.ts b/src/app/models/format.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..ebef0b2408621fcc803d6c67e724cf9c3ec13748
--- /dev/null
+++ b/src/app/models/format.model.ts
@@ -0,0 +1,34 @@
+export class Format {
+  id?: number;
+  name: string;
+  mapServerType: string;
+
+  constructor(format?: IFormat) {
+    if (format) {
+      if (format.id) {
+        this.id = format.id;
+      }
+      this.name = format.name;
+      this.mapServerType = format.mapServerType;
+    } else {
+      this.name = '';
+      this.mapServerType = '';
+    }
+  }
+}
+
+export class FormatRO {
+  formats: Format[];
+  totalCount: number;
+
+  constructor(formats, totalCount) {
+    this.formats = formats;
+    this.totalCount = totalCount;
+  }
+}
+
+export interface IFormat {
+  id: number;
+  name: string;
+  mapServerType: string;
+}
diff --git a/src/app/services/format.service.ts b/src/app/services/format.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b6186961049a0818ffee9dd07cc21045c48ce63d
--- /dev/null
+++ b/src/app/services/format.service.ts
@@ -0,0 +1,91 @@
+import { Injectable } from '@angular/core';
+import { Observable, Subject } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { HttpClient } from '@angular/common/http';
+import { APP_CONFIG } from './app-config.service';
+import { FormatRO, IFormat, Format } from '../models/format.model';
+
+@Injectable()
+export class FormatService {
+
+  formatServiceUrl: string;
+  limit: number;
+  pageNumber: number;
+  sortOptions: {
+    value: string,
+    order: string,
+  };
+
+  private _searchChangeSubject: Subject<any>;
+
+  constructor(
+    private _httpClient: HttpClient) {
+    this.formatServiceUrl = `${APP_CONFIG.resources.url}formats/`;
+    this._searchChangeSubject = new Subject<any>();
+    this.limit = 10;
+    this.pageNumber = 1;
+  }
+
+  getFormats(options?): Observable<FormatRO> {
+    let query = '?';
+    query += `limit=${(this.limit ? this.limit : 20)}`;
+    query += `&offset=${(this.pageNumber ? (this.pageNumber - 1) * this.limit : 0)}`;
+    query += `&sort_by=${this.sortOptions.value}.${this.sortOptions.order}`;
+
+    return this._httpClient.get<IFormat[]>(this.formatServiceUrl + query, { observe: 'response' }).pipe(
+      map((response) => {
+        const totalCount = response.headers.get('Content-Range');
+        const formats = [];
+        response.body.forEach((format) => {
+          formats.push(new Format(format));
+        });
+        return new FormatRO(formats, parseInt(totalCount, 10));
+      }));
+  }
+
+  findById(id): Observable<Format> {
+    return this._httpClient.get<IFormat>(this.formatServiceUrl + id).pipe(
+      map((response) => {
+        return new Format(response);
+      }),
+    );
+  }
+
+  delete(id) {
+    return this._httpClient.delete(this.formatServiceUrl + id);
+  }
+
+  replaceOrCreate(data): Observable<Format> {
+    if (data.id) {
+      return this._httpClient.put<IFormat>(this.formatServiceUrl + data.id, data).pipe(
+        map((response) => {
+          return new Format(response);
+        }),
+      );
+    }
+    return this._httpClient.post<IFormat>(this.formatServiceUrl, data).pipe(
+      map((response) => {
+        return new Format(response);
+      }),
+    );
+  }
+
+  /* PAGINATION */
+  paginationChanged(limit: number, pageNumber: number) {
+    this.limit = limit;
+    this.pageNumber = pageNumber;
+    this._searchChangeSubject.next();
+  }
+
+  reverseSortOrder(): void {
+    if (this.sortOptions.order === 'asc') {
+      this.sortOptions.order = 'desc';
+    } else {
+      this.sortOptions.order = 'asc';
+    }
+  }
+
+  get searchChange$(): Observable<string> {
+    return this._searchChangeSubject.asObservable();
+  }
+}
diff --git a/src/app/services/index.ts b/src/app/services/index.ts
index 24455cc0269d221c37faf7bb2c66792a0ec257b8..b72aa77e756069957b67a0b00e1b20cd1a4a1f36 100644
--- a/src/app/services/index.ts
+++ b/src/app/services/index.ts
@@ -1,11 +1,13 @@
 import { AppConfigService } from './app-config.service';
 import { OrganizationService } from './organization.service';
 import { ResourceService } from './resource.service';
+import { FormatService } from './format.service';
 
 export {
   AppConfigService,
   OrganizationService,
   ResourceService,
+  FormatService,
 };
 
 // tslint:disable-next-line:variable-name
@@ -13,4 +15,5 @@ export const AppServices = [
   AppConfigService,
   OrganizationService,
   ResourceService,
+  FormatService,
 ];
diff --git a/src/app/services/organization.service.ts b/src/app/services/organization.service.ts
index c5360560f0a3ef99269166b974109ef92beef31d..138d0bc91698fc2cfb13a3577609f7871dc6bb8c 100644
--- a/src/app/services/organization.service.ts
+++ b/src/app/services/organization.service.ts
@@ -1,11 +1,10 @@
 import { Injectable } from '@angular/core';
-import { Observable ,  Subject } from 'rxjs';
+import { Observable, Subject } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { HttpClient } from '@angular/common/http';
 import { Organization, IOrganization, OrganizationRO } from '../models/organization.model';
 import { APP_CONFIG } from './app-config.service';
 
-
 @Injectable()
 export class OrganizationService {
 
@@ -20,16 +19,16 @@ export class OrganizationService {
 
   constructor(
     private _httpClient: HttpClient) {
-      this._searchChangeSubject = new Subject<any>();
-      this.limit = 10;
-      this.pageNumber = 1;
+    this._searchChangeSubject = new Subject<any>();
+    this.limit = 10;
+    this.pageNumber = 1;
   }
 
   getOrganizations(options?): Observable<OrganizationRO> {
     let query = '?';
-    query += 'limit=' + (this.limit ? this.limit : 20);
-    query += '&offset=' + (this.pageNumber ? (this.pageNumber - 1) * this.limit : 0);
-    query += '&sort_by=' + this.sortOptions.value + '.' + this.sortOptions.order;
+    query += `limit=${(this.limit ? this.limit : 20)}`;
+    query += `&offset=${(this.pageNumber ? (this.pageNumber - 1) * this.limit : 0)}`;
+    query += `&sort_by=${this.sortOptions.value}.${this.sortOptions.order}`;
 
     return this._httpClient.get<IOrganization[]>(APP_CONFIG.organizations.url + query, { observe: 'response' }).pipe(
       map((response) => {
@@ -46,8 +45,8 @@ export class OrganizationService {
     return this._httpClient.get<IOrganization>(APP_CONFIG.organizations.url + id).pipe(
       map((response) => {
         return new Organization(response);
-      }
-      ));
+      }),
+    );
   }
 
   delete(id) {
@@ -59,8 +58,8 @@ export class OrganizationService {
       return this._httpClient.put<IOrganization>(APP_CONFIG.organizations.url + data.id, data).pipe(
         map((response) => {
           return new Organization(response);
-        }
-        ));
+        }),
+      );
     }
     delete data.id;
     data.links.forEach((link) => {
@@ -69,26 +68,26 @@ export class OrganizationService {
     return this._httpClient.post<IOrganization>(APP_CONFIG.organizations.url, data).pipe(
       map((response) => {
         return new Organization(response);
-      }
-      ));
+      }),
+    );
   }
 
-    /* PAGINATION */
-    paginationChanged(limit: number, pageNumber: number) {
-      this.limit = limit;
-      this.pageNumber = pageNumber;
-      this._searchChangeSubject.next();
-    }
+  /* PAGINATION */
+  paginationChanged(limit: number, pageNumber: number) {
+    this.limit = limit;
+    this.pageNumber = pageNumber;
+    this._searchChangeSubject.next();
+  }
 
-    reverseSortOrder(): void {
-      if (this.sortOptions.order === 'asc') {
-        this.sortOptions.order = 'desc';
-      } else {
-        this.sortOptions.order = 'asc';
-      }
+  reverseSortOrder(): void {
+    if (this.sortOptions.order === 'asc') {
+      this.sortOptions.order = 'desc';
+    } else {
+      this.sortOptions.order = 'asc';
     }
+  }
 
-    get searchChange$(): Observable<string> {
-      return this._searchChangeSubject.asObservable();
-    }
+  get searchChange$(): Observable<string> {
+    return this._searchChangeSubject.asObservable();
+  }
 }
diff --git a/src/app/services/resource.service.ts b/src/app/services/resource.service.ts
index d1b0d38d309beb7f3763e593c08a352f987e4737..aa1f84743918583023c4ad43acc9ecdb5a80a936 100644
--- a/src/app/services/resource.service.ts
+++ b/src/app/services/resource.service.ts
@@ -1,5 +1,5 @@
 import { Injectable } from '@angular/core';
-import { Observable ,  Subject } from 'rxjs';
+import { Observable, Subject } from 'rxjs';
 import { map } from 'rxjs/operators';
 import { HttpClient } from '@angular/common/http';
 import { Resource, IResource, ResourceRO } from '../models/resource.model';
@@ -8,6 +8,7 @@ import { APP_CONFIG } from './app-config.service';
 @Injectable()
 export class ResourceService {
 
+  resourceServiceUrl: string;
   limit: number;
   pageNumber: number;
   sortOptions: {
@@ -19,18 +20,19 @@ export class ResourceService {
 
   constructor(
     private _httpClient: HttpClient) {
-      this._searchChangeSubject = new Subject<any>();
-      this.limit = 10;
-      this.pageNumber = 1;
+    this.resourceServiceUrl = `${APP_CONFIG.resources.url}resources/`;
+    this._searchChangeSubject = new Subject<any>();
+    this.limit = 10;
+    this.pageNumber = 1;
   }
 
   getResources(options?): Observable<ResourceRO> {
     let query = '?';
-    query += 'limit=' + (this.limit ? this.limit : 20);
-    query += '&offset=' + (this.pageNumber ? (this.pageNumber - 1) * this.limit : 0);
-    query += '&sort_by=' + this.sortOptions.value + '.' + this.sortOptions.order;
+    query += `limit=${(this.limit ? this.limit : 20)}`;
+    query += `&offset=${(this.pageNumber ? (this.pageNumber - 1) * this.limit : 0)}`;
+    query += `&sort_by=${this.sortOptions.value}.${this.sortOptions.order}`;
 
-    return this._httpClient.get<IResource[]>(APP_CONFIG.resources.url + query, { observe: 'response' }).pipe(
+    return this._httpClient.get<IResource[]>(this.resourceServiceUrl + query, { observe: 'response' }).pipe(
       map((response) => {
         const totalCount = response.headers.get('Content-Range');
         const resources = [];
@@ -42,48 +44,48 @@ export class ResourceService {
   }
 
   findById(id): Observable<Resource> {
-    return this._httpClient.get<IResource>(APP_CONFIG.resources.url + id).pipe(
+    return this._httpClient.get<IResource>(this.resourceServiceUrl + id).pipe(
       map((response) => {
         return new Resource(response);
-      }
-      ));
+      }),
+    );
   }
 
   delete(id) {
-    return this._httpClient.delete(APP_CONFIG.resources.url + id);
+    return this._httpClient.delete(this.resourceServiceUrl + id);
   }
 
   replaceOrCreate(data): Observable<Resource> {
     if (data.id) {
-      return this._httpClient.put<IResource>(APP_CONFIG.resources.url + data.id, data).pipe(
+      return this._httpClient.put<IResource>(this.resourceServiceUrl + data.id, data).pipe(
         map((response) => {
           return new Resource(response);
-        }
-        ));
+        }),
+      );
     }
-    return this._httpClient.post<IResource>(APP_CONFIG.resources.url, data).pipe(
+    return this._httpClient.post<IResource>(this.resourceServiceUrl, data).pipe(
       map((response) => {
         return new Resource(response);
-      }
-      ));
+      }),
+    );
   }
 
-    /* PAGINATION */
-    paginationChanged(limit: number, pageNumber: number) {
-      this.limit = limit;
-      this.pageNumber = pageNumber;
-      this._searchChangeSubject.next();
-    }
+  /* PAGINATION */
+  paginationChanged(limit: number, pageNumber: number) {
+    this.limit = limit;
+    this.pageNumber = pageNumber;
+    this._searchChangeSubject.next();
+  }
 
-    reverseSortOrder(): void {
-      if (this.sortOptions.order === 'asc') {
-        this.sortOptions.order = 'desc';
-      } else {
-        this.sortOptions.order = 'asc';
-      }
+  reverseSortOrder(): void {
+    if (this.sortOptions.order === 'asc') {
+      this.sortOptions.order = 'desc';
+    } else {
+      this.sortOptions.order = 'asc';
     }
+  }
 
-    get searchChange$(): Observable<string> {
-      return this._searchChangeSubject.asObservable();
-    }
+  get searchChange$(): Observable<string> {
+    return this._searchChangeSubject.asObservable();
+  }
 }
diff --git a/src/assets/config/config.json b/src/assets/config/config.json
index 3320942c82b8a0ff6ae8e347c87e619f1ab91685..9308ae9e42a106a4b7a21fa2ffb36f679f8f4ea6 100644
--- a/src/assets/config/config.json
+++ b/src/assets/config/config.json
@@ -3,6 +3,6 @@
     "url": "https://kong-dev.alpha.grandlyon.com/organizations/"
   },
   "resources": {
-    "url": "https://kong-dev.alpha.grandlyon.com/resources/resources/"
+    "url": "https://kong-dev.alpha.grandlyon.com/resources/"
   }
 }
\ No newline at end of file
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index 0fe39f17326a0e65121c41612229dc0e808aed3d..da5ad8529bfb0812320aa37a2fc27e382d0dc913 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -5,4 +5,3 @@
 export const environment = {
   production: false,
 };
-
diff --git a/src/polyfills.ts b/src/polyfills.ts
index d310405a6817a4b84bb6117fb709e2c6ea11ef55..749bf310dfa5e49e016fa56a864a22924bbde19d 100644
--- a/src/polyfills.ts
+++ b/src/polyfills.ts
@@ -40,12 +40,10 @@
 /** IE10 and IE11 requires the following for the Reflect API. */
 // import 'core-js/es6/reflect';
 
-
 /** Evergreen browsers require these. **/
 // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
 import 'core-js/es7/reflect';
 
-
 /**
  * Web Animations `@angular/platform-browser/animations`
  * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
@@ -73,8 +71,6 @@ import 'core-js/es7/reflect';
  */
 import 'zone.js/dist/zone';  // Included with Angular CLI.
 
-
-
 /***************************************************************************************************
  * APPLICATION IMPORTS
  */
diff --git a/src/test.ts b/src/test.ts
index 16317897b1c50a3a71bc775a8d6429f2b4c6cf98..b6d614daa243e0869709092a8276dc9d81e7c085 100644
--- a/src/test.ts
+++ b/src/test.ts
@@ -4,7 +4,7 @@ import 'zone.js/dist/zone-testing';
 import { getTestBed } from '@angular/core/testing';
 import {
   BrowserDynamicTestingModule,
-  platformBrowserDynamicTesting
+  platformBrowserDynamicTesting,
 } from '@angular/platform-browser-dynamic/testing';
 
 declare const require: any;
@@ -12,7 +12,7 @@ declare const require: any;
 // First, initialize the Angular testing environment.
 getTestBed().initTestEnvironment(
   BrowserDynamicTestingModule,
-  platformBrowserDynamicTesting()
+  platformBrowserDynamicTesting(),
 );
 // Then we find all the tests.
 const context = require.context('./', true, /\.spec\.ts$/);
diff --git a/src/tslint.json b/src/tslint.json
deleted file mode 100644
index 52e2c1a5a74ce268bec92d34cd3bca751624adb3..0000000000000000000000000000000000000000
--- a/src/tslint.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
-    "extends": "../tslint.json",
-    "rules": {
-        "directive-selector": [
-            true,
-            "attribute",
-            "app",
-            "camelCase"
-        ],
-        "component-selector": [
-            true,
-            "element",
-            "app",
-            "kebab-case"
-        ]
-    }
-}
diff --git a/tslint.json b/tslint.json
index 3ea984c776ef691c92b37ddf933df452cdc3d8bc..e43c8b8df38cc4c2463dd75196bd1715abead658 100644
--- a/tslint.json
+++ b/tslint.json
@@ -1,130 +1,17 @@
 {
+  "extends": [
+    "tslint-config-airbnb"
+  ],
   "rulesDirectory": [
-    "node_modules/codelyzer"
+    "node_modules/rxjs-tslint"
   ],
   "rules": {
-    "arrow-return-shorthand": true,
-    "callable-types": true,
-    "class-name": true,
-    "comment-format": [
-      true,
-      "check-space"
-    ],
-    "curly": true,
-    "deprecation": {
-      "severity": "warn"
-    },
-    "eofline": true,
-    "forin": true,
-    "import-blacklist": [
-      true,
-      "rxjs/Rx"
-    ],
-    "import-spacing": true,
-    "indent": [
-      true,
-      "spaces"
-    ],
-    "interface-over-type-literal": true,
-    "label-position": true,
-    "max-line-length": [
-      true,
-      140
-    ],
-    "member-access": false,
-    "member-ordering": [
-      true,
-      {
-        "order": [
-          "static-field",
-          "instance-field",
-          "static-method",
-          "instance-method"
-        ]
-      }
-    ],
-    "no-arg": true,
-    "no-bitwise": true,
-    "no-console": [
-      true,
-      "debug",
-      "info",
-      "time",
-      "timeEnd",
-      "trace"
-    ],
-    "no-construct": true,
-    "no-debugger": true,
-    "no-duplicate-super": true,
-    "no-empty": false,
-    "no-empty-interface": true,
-    "no-eval": true,
-    "no-inferrable-types": [
-      true,
-      "ignore-params"
-    ],
-    "no-misused-new": true,
-    "no-non-null-assertion": true,
-    "no-shadowed-variable": true,
-    "no-string-literal": false,
-    "no-string-throw": true,
-    "no-switch-case-fall-through": true,
-    "no-trailing-whitespace": true,
-    "no-unnecessary-initializer": true,
-    "no-unused-expression": true,
-    "no-use-before-declare": true,
-    "no-var-keyword": true,
-    "object-literal-sort-keys": false,
-    "one-line": [
-      true,
-      "check-open-brace",
-      "check-catch",
-      "check-else",
-      "check-whitespace"
-    ],
-    "prefer-const": true,
-    "quotemark": [
-      true,
-      "single"
-    ],
-    "radix": true,
-    "semicolon": [
-      true,
-      "always"
-    ],
-    "triple-equals": [
-      true,
-      "allow-null-check"
-    ],
-    "typedef-whitespace": [
-      true,
-      {
-        "call-signature": "nospace",
-        "index-signature": "nospace",
-        "parameter": "nospace",
-        "property-declaration": "nospace",
-        "variable-declaration": "nospace"
-      }
-    ],
-    "unified-signatures": true,
-    "variable-name": false,
-    "whitespace": [
-      true,
-      "check-branch",
-      "check-decl",
-      "check-operator",
-      "check-separator",
-      "check-type"
-    ],
-    "no-output-on-prefix": true,
-    "use-input-property-decorator": true,
-    "use-output-property-decorator": true,
-    "use-host-property-decorator": true,
-    "no-input-rename": true,
-    "no-output-rename": true,
-    "use-life-cycle-interface": true,
-    "use-pipe-transform-interface": true,
-    "component-class-suffix": true,
-    "directive-class-suffix": true
+    "variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"],
+    "strict-boolean-expressions": [false],
+    "max-line-length": [true, 140],
+    "rxjs-collapse-imports": true,
+    "rxjs-pipeable-operators-only": true,
+    "rxjs-no-static-observable-methods": true,
+    "rxjs-proper-imports": true
   }
-}
+}
\ No newline at end of file