diff --git a/src/app/app.component.scss b/src/app/app.component.scss
index e88db96820f572b128d6900e0b8290a631430028..1a210dec5e7022c73ccbebeb50d1a4bf7684c66a 100644
--- a/src/app/app.component.scss
+++ b/src/app/app.component.scss
@@ -44,7 +44,6 @@
 .main-nav{
   grid-row: 2;
   grid-column: 1 / span 1;
-  width: 50px;
   z-index: 200; 
   transition: all .2s linear;
   background-color: #333745;
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index dae310cdf7818a05bfd15bbada78b3fcfc82a10e..bf6c2f06590bcb12c23137cf188f00f3f6741264 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -17,6 +17,7 @@ import { ResourcesComponent } from './components/resources/list/resources.compon
 import { ResourceService } from './services/resource.service';
 import { ResourceFormComponent } from './components/resources/edit/resource-form.component';
 import { ResourceDetailComponent } from './components/resources/detail/resource-detail.component';
+import { PaginationService } from './services/pagination.service';
 
 @NgModule({
   declarations: [
diff --git a/src/app/components/menu/menu.component.html b/src/app/components/menu/menu.component.html
index 63c9727b0315c031bea447c498e166b48b913e8a..378c1b9028d21b31a9c21d956058ed4798a27e81 100644
--- a/src/app/components/menu/menu.component.html
+++ b/src/app/components/menu/menu.component.html
@@ -17,7 +17,7 @@
     </li>
     <li><a [routerLink]="['/', 'resources']" routerLinkActive="active-link">
       <span class="icon">
-          <i class="fas fa-tint"></i>
+          <i class="fas fa-hat-wizard"></i>
         </span>
       <span class="label-menu">Ressources</span> 
       </a>
diff --git a/src/app/components/organizations/edit/organization-form.component.ts b/src/app/components/organizations/edit/organization-form.component.ts
index 5ccb1db9212bf79e46970d4300c2a6843167f26a..30fb058e6473d86d80d4e83a9f6c1bfbdeb63484 100644
--- a/src/app/components/organizations/edit/organization-form.component.ts
+++ b/src/app/components/organizations/edit/organization-form.component.ts
@@ -81,9 +81,11 @@ 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 +99,7 @@ export class OrganizationFormComponent implements OnInit {
   onSubmit() {
     if (! this.formInvalid) {
       this.organization = new Organization(this.form.value);
-      this.organizationService.replaceOrCreate(this.organization)
+      this.organizationService.updateOrCreate(this.organization)
         .subscribe(
           (organizationCreated) => {
             this.router.navigate(['/organizations', organizationCreated.id])
diff --git a/src/app/components/organizations/list/organizations.component.ts b/src/app/components/organizations/list/organizations.component.ts
index a0299af9f17fdcfac3917c6d8d0358d475be4ce7..644b3cc062617d5a2dec62fdd224d7c6b7958fd1 100644
--- a/src/app/components/organizations/list/organizations.component.ts
+++ b/src/app/components/organizations/list/organizations.component.ts
@@ -1,13 +1,15 @@
 import { Component, OnInit, ViewChild } from '@angular/core';
-import { Organization, OrganizationRO } from 'src/app/models/organization.model';
+import { Organization } from 'src/app/models/organization.model';
 import { OrganizationService } from 'src/app/services/organization.service';
 import { BehaviorSubject, Subscription } from 'rxjs';
 import { PaginatorOptions } from 'src/app/models/paginator-options.model';
+import { PaginationService } from 'src/app/services/pagination.service';
 
 @Component({
   selector: 'app-organizations',
   templateUrl: './organizations.component.html',
   styleUrls: ['./organizations.component.scss'],
+  providers: [PaginationService],
 })
 export class OrganizationsComponent implements OnInit {
 
@@ -30,23 +32,24 @@ export class OrganizationsComponent implements OnInit {
 
   constructor(
     private organizationsService: OrganizationService,
+    private paginationService: PaginationService,
   ) {
     this.paginator = {
-      pageIndex: this.organizationsService.pageNumber,
+      pageIndex: this.paginationService.pageNumber,
       length: 0,
-      limit: this.organizationsService.limit,
+      limit: this.paginationService.limit,
       pageSizeOptions: [5, 10, 20],
     };
   }
 
   ngOnInit(): void {
-    this.organizationsService.sortOptions = {
+    this.paginationService.sortOptions = {
       value: 'name',
       order: 'asc'
     };
     this.search();
 
-    this.searchChangeSub = this.organizationsService.searchChange$.subscribe(
+    this.searchChangeSub = this.paginationService.searchChange$.subscribe(
       () => {
         this.search();
       },
@@ -54,46 +57,51 @@ export class OrganizationsComponent implements OnInit {
   }
 
   private search() {
-    this.organizationsService.getOrganizations()
-      .subscribe((items: OrganizationRO) => {
-        this.organizations = items.organizations;
-        this.totalElement = items.totalCount;
-
-        this.paginator.limit = this.organizationsService.limit;
-        this.paginator.pageIndex = this.organizationsService.pageNumber;
-        this.paginator.length = items.totalCount;
+    const options = {
+      limit: this.paginationService.limit,
+      pageNumber: this.paginationService.pageNumber,
+      sortOptions: this.paginationService.sortOptions,
+    };
+    this.organizationsService.getAll(options)
+      .subscribe((items: Organization[]) => {
+        this.organizations = items;
+        this.totalElement = this.organizationsService.totalItems;
+
+        this.paginator.limit = this.paginationService.limit;
+        this.paginator.pageIndex = this.paginationService.pageNumber;
+        this.paginator.length = this.organizationsService.totalItems;
       });
   }
 
 
-  // When pagination is changed by user, we update datasetList with new pagination options
+  // When pagination is changed by user, we update pagination options
   changePagination(pageIndex) {
-    this.organizationsService.paginationChanged(this.paginator.limit, pageIndex);
+    this.paginationService.paginationChanged(this.paginator.limit, pageIndex);
   }
 
   changePageSize(pageSize) {
-    this.organizationsService.paginationChanged(pageSize, 1);
+    this.paginationService.paginationChanged(pageSize, 1);
   }
 
   sortBy(key: string) {
-    if (this.organizationsService.sortOptions.value === key) {
-      this.organizationsService.reverseSortOrder();
+    if (this.paginationService.sortOptions.value === key) {
+      this.paginationService.reverseSortOrder();
     } else {
-      this.organizationsService.sortOptions.value = key;
-      this.organizationsService.sortOptions.order = 'asc';
+      this.paginationService.sortOptions.value = key;
+      this.paginationService.sortOptions.order = 'asc';
     }
     this.search();
   }
 
   get sortOptions() {
-    return this.organizationsService.sortOptions;
+    return this.paginationService.sortOptions;
   }
 
   displayDeletePopup(organizationId) {
     const pop = confirm('Etes vous sûr de vouloir supprimer cette organisation ?');
     if (pop === true) {
       this.organizationsService.delete(organizationId).subscribe(() => {
-        this.organizationsService.pageNumber = 1;
+        this.paginationService.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 d8adb34a86852fa6f2edd3d83de0cfc6096410e4..1ec215ae12ccae2ea1352fcf973ab02aa57b9610 100644
--- a/src/app/components/resources/edit/resource-form.component.ts
+++ b/src/app/components/resources/edit/resource-form.component.ts
@@ -68,7 +68,7 @@ export class ResourceFormComponent implements OnInit {
     if (!this.formInvalid) {
       this.resource = new Resource(this.form.value);
       this.resource.outputFormats = this.form.value.outputFormats.split(',');
-      this.resourceService.replaceOrCreate(this.resource)
+      this.resourceService.updateOrCreate(this.resource)
         .subscribe(
           (resourceCreated) => {
             this.router.navigate(['/resources', resourceCreated.id])
diff --git a/src/app/components/resources/list/resources.component.ts b/src/app/components/resources/list/resources.component.ts
index a8d9357aa537cee3e71e6f1b72186adf159138f8..073c0127400a2fc71b1c903b21836480ef33d478 100644
--- a/src/app/components/resources/list/resources.component.ts
+++ b/src/app/components/resources/list/resources.component.ts
@@ -1,13 +1,15 @@
-import { Component, OnInit, ViewChild } from '@angular/core';
-import { Resource, ResourceRO } from 'src/app/models/resource.model';
+import { Component, OnInit } from '@angular/core';
+import { Resource } from 'src/app/models/resource.model';
 import { ResourceService } from 'src/app/services/resource.service';
 import { Subscription } from 'rxjs';
 import { PaginatorOptions } from 'src/app/models/paginator-options.model';
+import { PaginationService } from 'src/app/services/pagination.service';
 
 @Component({
   selector: 'app-resources',
   templateUrl: './resources.component.html',
   styleUrls: ['./resources.component.scss'],
+  providers: [PaginationService],
 })
 export class ResourcesComponent implements OnInit {
 
@@ -29,23 +31,24 @@ export class ResourcesComponent implements OnInit {
 
   constructor(
     private resourcesService: ResourceService,
+    private paginationService: PaginationService,
   ) {
     this.paginator = {
-      pageIndex: this.resourcesService.pageNumber,
+      pageIndex: this.paginationService.pageNumber,
       length: 0,
-      limit: this.resourcesService.limit,
+      limit: this.paginationService.limit,
       pageSizeOptions: [5, 10, 20],
     };
   }
 
   ngOnInit(): void {
-    this.resourcesService.sortOptions = {
+    this.paginationService.sortOptions = {
       value: 'name',
       order: 'asc'
     };
     this.search();
 
-    this.searchChangeSub = this.resourcesService.searchChange$.subscribe(
+    this.searchChangeSub = this.paginationService.searchChange$.subscribe(
       () => {
         this.search();
       },
@@ -53,46 +56,51 @@ export class ResourcesComponent implements OnInit {
   }
 
   private search() {
-    this.resourcesService.getResources()
-      .subscribe((items: ResourceRO) => {
-        this.resources = items.resources;
-        this.totalElement = items.totalCount;
-
-        this.paginator.limit = this.resourcesService.limit;
-        this.paginator.pageIndex = this.resourcesService.pageNumber;
-        this.paginator.length = items.totalCount;
+    const options = {
+      limit: this.paginationService.limit,
+      pageNumber: this.paginationService.pageNumber,
+      sortOptions: this.paginationService.sortOptions,
+    };
+    this.resourcesService.getAll(options)
+      .subscribe((items: Resource[]) => {
+        this.resources = items;
+        this.totalElement = this.resourcesService.totalItems;
+
+        this.paginator.limit = this.paginationService.limit;
+        this.paginator.pageIndex = this.paginationService.pageNumber;
+        this.paginator.length = this.resourcesService.totalItems;
       });
   }
 
 
   // When pagination is changed by user, we update datasetList with new pagination options
   changePagination(pageIndex) {
-    this.resourcesService.paginationChanged(this.paginator.limit, pageIndex);
+    this.paginationService.paginationChanged(this.paginator.limit, pageIndex);
   }
 
   changePageSize(pageSize) {
-    this.resourcesService.paginationChanged(pageSize, 1);
+    this.paginationService.paginationChanged(pageSize, 1);
   }
 
   sortBy(key: string) {
-    if (this.resourcesService.sortOptions.value === key) {
-      this.resourcesService.reverseSortOrder();
+    if (this.paginationService.sortOptions.value === key) {
+      this.paginationService.reverseSortOrder();
     } else {
-      this.resourcesService.sortOptions.value = key;
-      this.resourcesService.sortOptions.order = 'asc';
+      this.paginationService.sortOptions.value = key;
+      this.paginationService.sortOptions.order = 'asc';
     }
     this.search();
   }
 
   get sortOptions() {
-    return this.resourcesService.sortOptions;
+    return this.paginationService.sortOptions;
   }
 
   displayDeletePopup(resourceId) {
     const pop = confirm('Etes vous sûr de vouloir supprimer cette organisation ?');
     if (pop === true) {
       this.resourcesService.delete(resourceId).subscribe(() => {
-        this.resourcesService.pageNumber = 1;
+        this.paginationService.pageNumber = 1;
         this.search();
       });
     }
diff --git a/src/app/models/organization.model.ts b/src/app/models/organization.model.ts
index 1b3a7d2832ea82f2764d0d44ae12c8b44ca23382..fc1303182eb42f3155a2f776c3c15f1bcd99b93e 100644
--- a/src/app/models/organization.model.ts
+++ b/src/app/models/organization.model.ts
@@ -1,11 +1,14 @@
-export class Organization {
-  id: number;
+import { RestObject } from './rest.object.model';
+
+export class Organization extends RestObject {
   name: string;
   description: string;
   logo?: string;
   links?: ILink[];
 
   constructor(organization?: IOrganization) {
+    super();
+
     if (organization) {
       this.id = organization.id;
       this.name = organization.name;
@@ -21,16 +24,6 @@ export class Organization {
   }
 }
 
-export class OrganizationRO {
-  organizations: Organization[];
-  totalCount: number;
-
-  constructor(organizations, totalCount) {
-    this.organizations = organizations;
-    this.totalCount = totalCount;
-  }
-}
-
 export interface IOrganization {
   id: number;
   name: string;
diff --git a/src/app/models/resource.model.ts b/src/app/models/resource.model.ts
index 7fb24fa24833f9c6553c65955df1c017b10db4c2..b0848463a20cbe3631904938b3a234607e657e61 100644
--- a/src/app/models/resource.model.ts
+++ b/src/app/models/resource.model.ts
@@ -1,5 +1,6 @@
-export class Resource {
-  id: number;
+import { RestObject } from './rest.object.model';
+
+export class Resource extends RestObject {
   name: string;
   type: string;
   description?: string;
@@ -8,6 +9,8 @@ export class Resource {
   outputFormats: string[];
 
   constructor(resource?: IResource) {
+    super();
+
     if (resource) {
       this.id = resource.id;
       this.name = resource.name;
@@ -28,16 +31,6 @@ export class Resource {
   }
 }
 
-export class ResourceRO {
-  resources: Resource[];
-  totalCount: number;
-
-  constructor(resources, totalCount) {
-    this.resources = resources;
-    this.totalCount = totalCount;
-  }
-}
-
 export interface IResource {
   id: number;
   name: string;
@@ -47,10 +40,3 @@ export interface IResource {
   downloadable: number;
   outputFormats: string[];
 }
-
-interface ILink {
-  id?: number;
-  name: string;
-  url: string;
-  organizationId: number;
-}
diff --git a/src/app/models/rest.object.model.ts b/src/app/models/rest.object.model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..3e6845a6629224f722bb73a313641fc7351b4a84
--- /dev/null
+++ b/src/app/models/rest.object.model.ts
@@ -0,0 +1,3 @@
+export class RestObject {
+  id: number;
+}
diff --git a/src/app/models/serializers/organization.serializer.ts b/src/app/models/serializers/organization.serializer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..b3931358ae4462d8ecd02fdb21d7ba0775c74a2e
--- /dev/null
+++ b/src/app/models/serializers/organization.serializer.ts
@@ -0,0 +1,9 @@
+import { Serializer } from './serializer.interface';
+import { Organization } from '../organization.model';
+
+export class OrganizationSerializer implements Serializer {
+  fromJson(data: any): Organization {
+
+    return new Organization(data);
+  }
+}
diff --git a/src/app/models/serializers/resource.serializer.ts b/src/app/models/serializers/resource.serializer.ts
new file mode 100644
index 0000000000000000000000000000000000000000..71d74344cc4fe63361848567e354a192720c1a3b
--- /dev/null
+++ b/src/app/models/serializers/resource.serializer.ts
@@ -0,0 +1,9 @@
+import { Serializer } from './serializer.interface';
+import { Resource } from '../resource.model';
+
+export class ResourceSerializer implements Serializer {
+  fromJson(data: any): Resource {
+
+    return new Resource(data);
+  }
+}
diff --git a/src/app/models/serializers/serializer.interface.ts b/src/app/models/serializers/serializer.interface.ts
new file mode 100644
index 0000000000000000000000000000000000000000..30041df1801aba108ec5d8c0f44c82b744c42ac6
--- /dev/null
+++ b/src/app/models/serializers/serializer.interface.ts
@@ -0,0 +1,5 @@
+import { RestObject } from '../rest.object.model';
+
+export interface Serializer {
+  fromJson(json: any): RestObject;
+}
diff --git a/src/app/services/organization.service.ts b/src/app/services/organization.service.ts
index 954ed26edfeec27a01fc19c5b8d8e1483ebbe1c2..51c6f2e4a91e5fe6b75d4ac35b73ebf843a6a7fb 100644
--- a/src/app/services/organization.service.ts
+++ b/src/app/services/organization.service.ts
@@ -1,90 +1,19 @@
 import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import { Subject } from 'rxjs/Subject';
-import { map } from 'rxjs/operators';
 import { HttpClient } from '@angular/common/http';
-import { Organization, IOrganization, OrganizationRO } from '../models/organization.model';
+import { Organization } from '../models/organization.model';
 import { environment } from 'src/environments/environment';
+import { RESTService } from './rest.service';
+import { OrganizationSerializer } from '../models/serializers/organization.serializer';
 
 @Injectable()
-export class OrganizationService {
-
-  limit: number;
-  pageNumber: number;
-  sortOptions: {
-    value: string,
-    order: string,
-  };
-
-  private _searchChangeSubject: Subject<any>;
-
-  constructor(
-    private _httpClient: HttpClient) {
-      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;
-
-    return this._httpClient.get<IOrganization[]>(environment.organizations.url + query, { observe: 'response' }).pipe(
-      map((response) => {
-        const totalCount = response.headers.get('Content-Range');
-        const organizations = [];
-        response.body.forEach((organization) => {
-          organizations.push(new Organization(organization));
-        });
-        return new OrganizationRO(organizations, parseInt(totalCount, 10));
-      }));
-  }
-
-  findById(id): Observable<Organization> {
-    return this._httpClient.get<IOrganization>(environment.organizations.url + id).pipe(
-      map((response) => {
-        return new Organization(response);
-      }
-      ));
-  }
-
-  delete(id) {
-    return this._httpClient.delete(environment.organizations.url + id);
+export class OrganizationService extends RESTService<Organization> {
+
+  constructor(httpClient: HttpClient) {
+    super(
+      httpClient,
+      environment.organizations.url,
+      new OrganizationSerializer()
+    );
   }
 
-  replaceOrCreate(data): Observable<Organization> {
-    if (data.id) {
-      return this._httpClient.put<IOrganization>(environment.organizations.url + data.id, data).pipe(
-        map((response) => {
-          return new Organization(response);
-        }
-        ));
-    }
-    return this._httpClient.post<IOrganization>(environment.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();
-    }
-
-    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/pagination.service.ts b/src/app/services/pagination.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..04962d6ea6e5ae6679ad94f9437c3394152b6c5f
--- /dev/null
+++ b/src/app/services/pagination.service.ts
@@ -0,0 +1,40 @@
+import { Injectable } from '@angular/core';
+import { Subject, Observable } from 'rxjs';
+
+@Injectable()
+export class PaginationService {
+
+  limit: number;
+  pageNumber: number;
+  sortOptions: {
+    value: string,
+    order: string,
+  };
+  private _searchChangeSubject: Subject<any>;
+
+
+  constructor() {
+    this.limit = 10;
+    this.pageNumber = 1;
+    this._searchChangeSubject = new Subject<any>();
+  }
+
+  /* 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/resource.service.ts b/src/app/services/resource.service.ts
index c5045c1774a21ea9da0d93335e392b862926a2af..f5b4660bbc75b00b805793e19fb63bbe2fd712cc 100644
--- a/src/app/services/resource.service.ts
+++ b/src/app/services/resource.service.ts
@@ -1,90 +1,18 @@
 import { Injectable } from '@angular/core';
-import { Observable } from 'rxjs/Observable';
-import { Subject } from 'rxjs/Subject';
-import { map } from 'rxjs/operators';
 import { HttpClient } from '@angular/common/http';
-import { Resource, IResource, ResourceRO } from '../models/resource.model';
+import { Resource } from '../models/resource.model';
 import { environment } from 'src/environments/environment';
+import { RESTService } from './rest.service';
+import { ResourceSerializer } from '../models/serializers/resource.serializer';
 
 @Injectable()
-export class ResourceService {
-
-  limit: number;
-  pageNumber: number;
-  sortOptions: {
-    value: string,
-    order: string,
-  };
-
-  private _searchChangeSubject: Subject<any>;
-
-  constructor(
-    private _httpClient: HttpClient) {
-      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;
-
-    return this._httpClient.get<IResource[]>(environment.resources.url + query, { observe: 'response' }).pipe(
-      map((response) => {
-        const totalCount = response.headers.get('Content-Range');
-        const resources = [];
-        response.body.forEach((resource) => {
-          resources.push(new Resource(resource));
-        });
-        return new ResourceRO(resources, parseInt(totalCount, 10));
-      }));
-  }
-
-  findById(id): Observable<Resource> {
-    return this._httpClient.get<IResource>(environment.resources.url + id).pipe(
-      map((response) => {
-        return new Resource(response);
-      }
-      ));
-  }
-
-  delete(id) {
-    return this._httpClient.delete(environment.resources.url + id);
-  }
-
-  replaceOrCreate(data): Observable<Resource> {
-    if (data.id) {
-      return this._httpClient.put<IResource>(environment.resources.url + data.id, data).pipe(
-        map((response) => {
-          return new Resource(response);
-        }
-        ));
-    }
-    return this._httpClient.post<IResource>(environment.resources.url, data).pipe(
-      map((response) => {
-        return new Resource(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();
-    }
+export class ResourceService extends RESTService<Resource> {
+
+ constructor(httpClient: HttpClient) {
+   super(
+    httpClient,
+    environment.resources.url,
+    new ResourceSerializer,
+   );
+ }
 }
diff --git a/src/app/services/rest.service.ts b/src/app/services/rest.service.ts
new file mode 100644
index 0000000000000000000000000000000000000000..61a2aa81afdc5b12fd03da432f4b23287174c744
--- /dev/null
+++ b/src/app/services/rest.service.ts
@@ -0,0 +1,70 @@
+import { RestObject } from '../models/rest.object.model';
+import { Subject, Observable } from 'rxjs';
+import { HttpClient } from '@angular/common/http';
+import { Serializer } from '../models/serializers/serializer.interface';
+import { map } from 'rxjs/operators';
+
+export class RESTService<T extends RestObject> {
+
+  private _totalItems: number;
+
+  constructor(
+    private httpClient: HttpClient,
+    private endpoint: string,
+    private serializer: Serializer) {
+  }
+
+  getAll(options?): Observable<T[]> {
+    let query = '?';
+    if (options) {
+      query += 'limit=' + (options.limit ? options.limit : 20);
+      query += '&offset=' + (options.pageNumber ? (options.pageNumber - 1) * options.limit : 0);
+      query += '&sort_by=' + options.sortOptions.value + '.' + options.sortOptions.order;
+    }
+
+    return this.httpClient.get(this.endpoint + query, { observe: 'response' }).pipe(
+      map((response) => {
+        this._totalItems = parseInt(response.headers.get('Content-Range'), 10);
+        return this.convertData(response.body);
+      }));
+  }
+
+  findById(id): Observable<T> {
+    return this.httpClient.get(this.endpoint + id).pipe(
+      map((response) => {
+        return this.serializer.fromJson(response) as T;
+      }
+      ));
+  }
+
+  updateOrCreate(data): Observable<T> {
+    // Update an existing item
+    if (data.id) {
+      return this.httpClient.put<T>(this.endpoint + data.id, data).pipe(
+        map((response) => {
+          return this.serializer.fromJson(response) as T;
+        }
+        ));
+    }
+    // Create a new item
+    return this.httpClient.post<T>(this.endpoint, data).pipe(
+      map((response) => {
+        return this.serializer.fromJson(response) as T;
+      }
+      ));
+  }
+
+
+  delete(id) {
+    return this.httpClient.delete(this.endpoint + id);
+  }
+
+  private convertData(data: any): T[] {
+    return data.map(item => this.serializer.fromJson(item));
+  }
+
+  get totalItems() {
+    return this._totalItems;
+  }
+
+}