Ngx-restangular: RESTful API Angular Solution
In this article we’re going to go through the ngx-restangular solution and how it will help your project development.
Short description of the article
Background
Basic RESTful API concept implementation via the ngx-restangular
Why should you use the ngx-restangular?
Supports both - Promises and Observables
Send a request from/within an object - don’t create a new object for each request
Supports nested RESTful resources
Use meaningful names instead of URLs
Provides an ability to create your own HTTP methods
Send requests easily using different settings
Conclusion
👋 Ngx-restangular Background
To write your own models, interceptors, modules for handling errors, methods for writing needed headers and lots of other stuff - that’s rather exciting only if you aren’t doing it a third time in 2 months, right? Actually, that’s the reason why we’ve decided to port a Martin Gontovnikas’ “Restangular” on an Angular/TypeScript.
What is Ngx-restangular
Ngx-restangular is a custom-made Angular 2+ solution that simplifies common GET, POST, DELETE, and UPDATE requests with a minimum of client code. As a result, the configuration becomes more understandable and can be applied in several ways with different settings. It's a perfect fit for any WebApp that consumes data from a RESTful API.
As we mentioned above, Ngx-restangular is the follow-up of the Restangular project. While Restangular supports only AngularJS, Ngx-restangular was created for Angular 2+ versions.
What problem Ngx-restangular solves
Ngx-restangular is the best solution for complex projects with rich functionality. Applying RxJS under the hood and having a coherent structure the package is handy to use for comlex client-side tasks. As a result, you get:
Easy way to send multiple requests
Names instead of URLs
Support all HTTP methods
Uphold nested RESTful resources
No need to make a new Object to perform request
Maintain self-linking elements
Requests like GET/POST/PUT/DELETE become easier to make with Ngx-restangular. Due to simple configuration, you can send multiple requests in various ways while applying different settings.
There is no need to remember every single URL that you use. In order to access the resource you need, use names instead of URLs. Easy as that.
The package allows creating your individual HTTP methods. Following unique logic, it becomes easy to perform custom operations you need.
To perform the HTTP operation, you don’t need to be familiar with the path, the URL, etc. Ngx-restangular maintains nested RESTful resources and manages that without your help.
You have the capability to send requests within the chosen Object. As a result, it is not necessary to create new Objects and identify URLs for each request form.
Stop writing URLs by hand. Instead of contracting the links by yourself, the Ngx-restangular package allows using the item’s reverse link to query the server.
If you want to check out the official ngx-restangular’s documentation directly or view the source code on a Github, please click here.
🤓 Basic RESTful API concept implementation via the ngx-restangular
Some web applications aim to implement the REST design pattern - a set of principles that conform to a specific architectural style using the HTTP protocol and its methods. Check out the table with imaginary 2muchcoffee REST API endpoint:
REST API | Description |
https://2muchcoffee.com/users | Get all users |
https://2muchcoffee.com/user/123 | Get a specific user |
https://2muchcoffee.com/user/123/products | Get a products list of the specific user |
https://2muchcoffee.com/user/123/products/456 | Get a specific product of the selected user |
From the table above you can see how the data and its nested entities are organized by the REST concept. Let’s have a look at the ngx-restangular syntax for working with the RESTful API:
export class UserComponent implements OnInit {
allUsers: UserModel[] & Restangular;
selectedUser: UserModel & Restangular;
selectedUserProduct: ProductModel & Restangular;
selectedUserProducts: ProductModel[] & Restangular;
constructor(
private restangular: Restangular,
) {
}
ngOnInit() {
// A GET request to '/users' - returns a list of users
this.restangular.all('users').getList().subscribe(users =>
this.allUsers = users
);
// A GET request to '/users/123' - returns a specific user(considering 123
// is the id of the selected User)
this.restangular.one('users', 123).get().subscribe(user =>
this.selectedUser = user
);
// A GET request to '/users/123/products' - returns a products list
// of the specific user
this.restangular.one('users', 123).all('products').getList().subscribe(products =>
this.selectedUserProducts = products
);
// A GET request to '/users/123/products/456' - returns a specific product
// of the selected user
this.restangular.one('users', 123).all('products', 456).get().subscribe(product =>
this.selectedUserProduct = product
);
}
}
Besides, the path would be identical in case you want to add, edit and delete (POST, PUT, DELETE) a specific user or his product.
🤔 Why should you use the ngx-restangular?
The ngx-restangular can be an overkill if you're trying to implement something simple, but when we're talking about a complex web application with an army of requests to REST API - you should use it without any hesitation. It will help you easily to handle consuming data from the REST API of any complexity with a minimum of client code.
To make it short and straightforward, the main idea of the ngx-restangular is to give an Angular community a powerful but yet simple tool with all “Restangular” features:
1. Promises and Observables in Ngx-restagular
Nowadays one could state that Functional Reactive Programming via Observables is one of the most stable and handy ways for async data and events handling in the web application. However, there are still many developers who prefer to use another approach - Promises.
With the ngx-restangular you don’t have to give up the most relevant for you approach, because RxJS provides you with both options and you can choose the most suitable one.
export class UsersComponent implements OnInit {
allUsers: UserModel[] & Restangular;
constructor(
private restangular: Restangular,
) {
}
ngOnInit() {
// Creating a Restangular object - just specify the base URL
const baseUsers = this.restangular.all('users');
// A GET request to '/users' using an Observable
baseUsers.getList().subscribe(users => this.allUsers = users);
// A GET request to '/users' using a Promise
baseUsers.getList().toPromise().then(users => this.allUsers = users);
}
}
2. Send a request from/within an object in Ngx-restagular
Once you have got an object by specifying the base URL, you are able to send further server requests using that object. Thus, you don’t have to remember and specify the URL each time. Check out the code example below:
export class UsersComponent implements OnInit {
allUsers: UserModel[] & Restangular;
baseUsers: Restangular;
newUser: FormGroup<UserModel> = new FormGroup({
firstName: new FormControl('John'),
lastName: new FormControl('Silva'),
});
constructor(
private restangular: Restangular,
) {
}
ngOnInit() {
// Creating a Restangular object by specifying the base URL
this.baseUsers = this.restangular.all('users');
// A GET request to '/users' - returns a list of users
this.baseUsers.getList().subscribe(users => this.allUsers = users);
}
submitNewUser() {
// A POST request to '/users' - adds a new user
this.baseUsers.post(this.newUser.value);
}
}
3. Ngx-restangular supports nested RESTful resources
The ngx-restangular has built-in features to work with nested entities. Let’s imagine that the “UsersComponent” from the first example passes into the “UserComponent” the selected User data.
The “UserComponent” itself is responsible for displaying the data of the User, including the user’s products list that you have to request from the API first. Thanks to the ngx-restangular you don’t have to specify the URL again and in order to get the user’s products from the API, you can just use the “selectedUser” object. Isn’t that amazing? Especially if you have a quite deep nesting, e.g. you need to get the vendor of the first product that selected User has.
Have a look at the example below:
export class UserComponent implements OnInit
@Input('user')
selectedUser: UserModel & Restangular;
firstProduct: ProductModel & Restangular;
selectedUserProducts: ProductModel[] & Restangular;
ngOnInit() {
// A GET request to ‘/users/123/products considering 123 is the id of
// the selected User
Returns a products list of the specific user
this.selectedUser.getList('products').subscribe(products => {
this.selectedUserProducts = products;
this.firstProduct = products[0];
});
}
}
export class ProductComponent implements OnInit {
@Input('product')
selectedProduct: ProductModel & Restangular;
selectedProductVendors: VendorModel[] & Restangular;
ngOnInit() {
// A GET request to '/users/123/products/789/vendors considering 123 is the id of the
// selected User, 789 is the id of the selected first Product - returns
// a vendors list of the specific user
this.selectedProductVendors = this.selectedProduct.getList('vendors');
}
}
4. Ngx-restangular uses meaningful names instead of URLs
Once you receive an object from an URL you can use meaningful names to access the data next time. You don’t need to remember each URL you use.
export class UsersComponent implements OnInit {
constructor(
private restangular: Restangular,
) {
}
ngOnInit() {
// Creating a Restangular object by specifying the base URL
const baseUsers = this.restangular.all('users');
// A GET request to '/users' - returns a list of users
baseUsers.getList().subscribe(users => {
const firstUser = users[0];
firstUser.firstName = 'Sam';
// A PUT request to '/users/777' considering 777 is the id of the first User
firstUser.put();
});
}
}
5. Ngx-restangular allows to create your own HTTP methods
You can simply add custom HTTP methods with unique logic and receive what you need with a server response. The ngx-restangular’s “getList” and “get” methods, as an example, await a collection or an object respectively as a response by default. And in order to receive a response in a diverse format, e.g. as a string, or to specify additional parameters to the request, you can create a custom HTTP “GET” method. Let’s have a look at the first example:
// A GET request to '/users/123/messages?param=myParam'
this.selectedUser.customGET('messages', {param: 'myParam'});
OR here’s an example for sending files:
// A POST request to ‘/users’
baseUsers.customPOST(formData, undefined, undefined, {'Content-Type': undefined});
That basically tells the request to use the Content-Type: multipart/form-data as a header. Also, formData is the body of the request, you have to add all the params here, of course including the File you want to send.
6. Ngx-restangular sends requests using different settings
Most often you have only one API and one global configuration for that in the project. But let’s imagine that you have more than one API or you just need to make a bunch of requests with another configuration, e.g. diverse base URL, headers etc. And what a coincidence! You can also easily implement that with the ngx-restangular!
The ngx-restangular allows you to set a configuration with various settings and use it in different parts of your application. Thus, you can generate diverse requests for different APIs without any concerns. In such a case, you just need to create another Restangular service with its own particular configuration. In addition, this scoped configuration will inherit all defaults from the global one. Take a look at the example below:
// Function for setting the default Restangular configuration
export function RestangularConfigFactory (RestangularProvider) {
RestangularProvider.setBaseUrl('https://2muchcoffee.com');
}
//Restangular service that uses accounting
export const RESTANGULAR_ACCOUNTING = new InjectionToken<any>('RestangularAccounting');
export function RestangularAccountingFactory(restangular: Restangular) {
return restangular.withConfig((RestangularConfigurer) => {
RestangularConfigurer.setBaseUrl('https://accounting.2muchcoffee.com');
});
}
// AppModule is the main entry point into Angular bootstrapping process
@NgModule({
bootstrap: [ AppComponent ],
declarations: [ AppComponent ],
imports: [
// Global configuration
RestangularModule.forRoot(RestangularConfigFactory),
],
providers: [
{
provide: RESTANGULAR_ACCOUNTING,
useFactory: RestangularAccountingFactory,
deps: [Restangular]
},
]
})
export class AppModule {}
// Let's use it in the users component
@Component({
...
})
export class UsersComponent {
constructor(
@Inject(Restangular) private Restangular,
@Inject(RESTANGULAR_ACCOUNTING) private RestangularAccounting,
) {
}
ngOnInit() {
// A GET request to https://2muchcoffee.com/users
// Uses global configuration
Restangular.all('users').getList()
// A GET request to https://accounting.2muchcoffee.com/users
// Uses Accounting configuration which is based on Global one, therefore .json
// is added.
RestangularAccounting.all('users').getList()
}
};
Conclusion
The ngx-restangular is a custom Angular solution for any web application with an absolutely clear structure and many features that make the REST API much easier. It’s totally proved by hundreds of MVP and start-ups that have already used it in their Angular 2/4/5/6/7 based projects. Currently, our project has already got over 750 stars on a Github.
Welcome to the ngx-restangular family and don’t hesitate to reach us through the ngx-restangular contact form in case you have any questions or suggestions. We will be more than happy to assist you.