Angular Rest Http Module with Typescript Declarative Annotations, Guards, Handlers and more
- 1. Installation
- 2. Basic Example
- 3. API Docs
- 4. Aot Limitations
- 5. Contributors
- 6. License
yarn add @thalesrc/angular-rest
or
npm install @thalesrc/angular-rest --save
// app.module.ts
import { NgModule } from '@angular/core';
import { RestModule } from '@thalesrc/angular-rest';
import { TodoClient } from './todo.client';
import { TodoComponent } from './todo.component';
@NgModule({
imports: [
RestModule.forRoot({baseUrl: 'http://localhost:3000'})
],
providers: [
TodoClient
],
declarations: [
TodoComponent
]
})
export class AppModule {}
// todo.client.ts
import { HttpRequest } from '@angular/common/http';
import { Client, Get, Post, Body } from '@thalesrc/angular-rest';
@Injectable()
@Client()
export class TodoClient {
@Get()
public todos(): Promise<Todo> {
return null;
}
@Post('todos')
public insertTodo(@Body() todo: Todo): Promise<void> {
return null;
}
}
// todo.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-todo',
template: 'Hello World'
})
export class TodoComponent {
constructor(private client: TodoClient) {
this.client.todos().then(todos => {
// Make something with todos
});
}
async postTodo(todo: Todo): Promise<void> {
return await this.client.insertTodo(todo);
}
}
@Client()
decorator marks a class as RestClient and provides functionality to make Http calls with its marked methods.
It can be configured by defining a ClientOptions
object as a parameter
A ClientOptions
object configures base options for the rest methods declared inside a @Client()
class
interface ClientOptions<T> {
baseUrl?: string;
guards?: Guard<T>;
handlers?: HandlersOf<T>;
baseHeaders?: HeadersClientParam<T>;
}
@Injectable()
@Client({
baseUrl: 'http://localhost:3000',
baseHeaders: [{'Secret-Key': 'The best rest util is @thalesrc/angular-rest'}]
...
})
export class TodoClient {
...
}
All of these decorators marks a method in a @Client()
as a request builder. path
can be specified to define the endpoint path. Otherwise, the method name is going to be used as path.
The method return type should be defined as Promise
and function should be empty but only returning null
. Decorators will handle all the rest.
@Get(path?: string)
@Post(path?: string)
@Put(path?: string)
@Delete(path?: string)
@Patch(path?: string)
@Options(path?: string)
@Head(path?: string)
@Jsonp(path?: string)
Example:
@Injectable()
@Client()
export class TodoClient {
@Get()
public todos(): Promise<Todo> {
return null;
}
@Post('todos')
public postTodo(@Body() todo: Todo): Promise<Todo> {
return null;
}
}
Mark a parameter with @Body()
decorator to fill body object with it.
A FormData
instance can be used for image uploads etc.
Body
decorator can be used in only POST, PUT, PATCH requests
Example:
@Injectable()
@Client()
export class TodoClient {
@Post('todos')
public postTodo(@Body() todo: Todo): Promise<Todo> {
return null;
}
@Post('image')
public uploadImage(@Body() data: FormData): Promise<string> {
return null;
}
}
@Component({
...
})
export class AComponent {
constructor(private client: TodoClient) {}
public async postTodo(todo: Todo): Promise<Todo> {
return await this.client.postTodo(todo);
}
public async uploadImage(image: Blob): Promise<string> {
const data = new FormData();
data.append('image', image);
return await this.client.uploadImage(data);
}
}
Mark a parameter decorated with Path
to replace the specified key in the url
Example:
@Injectable()
@Client()
export class TodoClient {
@Patch('todos/:id')
public patchTodo(@Body() todo: Todo, @Path('id') id: string): Promise<Todo> {
return null;
}
}
@Component({
...
})
export class AComponent {
constructor(private client: TodoClient) {}
public async postTodo(todo: Todo, todoId: string): Promise<Todo> {
return await this.client.patchTodo(todo, todoId);
}
}
to be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
Guards run just before a request has been sent to check whether request should be sent or not
Guards can be a function, a method of a client or an injectable of RestGuard
Define an injectable as a rest guard and declare them as a guard (Base Guard, Client Guard, Method Guard) to check a request can be sent or not.
Don't forget to provide them in a module
Example:
@Injectable()
export class PostTodoGuard implements RestGuard {
constructor(private session: SessionService) {}
async canSend(req: HttpRequest<any>): Promise<boolean> {
return await this.session.loggedIn$.pipe(first()).toPromise()
}
}
@Injectable()
@Client()
export class TodoClient {
@Post('todos')
@Guards([PostTodoGuard])
public async postTodos(todo: Todo): Promise<void> {
return null;
}
}
@NgModule({
providers: [
TodoClient,
PostTodoGuard
]
})
export class TodoModule {}
A single function can be a rest guard if it accepts first param as HttpRequest<any>
and returns whether boolean
or Promise<boolean>
Example:
function postTodoGuard(req: HttpRequest<Todo>): boolean {
return req.body.canBeSent;
}
@Injectable()
@Client()
export class TodoClient {
@Post('todos')
@Guards([postTodoGuard])
public async postTodos(todo: Todo): Promise<void> {
return null;
}
}
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
To be determined
In client constructor functions, calling a rest call is forbidden. Because the client dependencies have not been set yet when the constructor function called.
To run some code when client instance created, @OnClientReady()
decorator can be used. It will mark a method of a client to be called right after construction.
Example:
import { Client, OnClientReady } from '@thalesrc/angular-rest';
import { TodoCacheService } from './todo-cache.service';
@Injectable()
@Client()
export class TodoClient {
constructor(
private todoCacheService: TodoCacheService
) {}
@OnClientReady()
private onReady() {
const todos = await this.todos();
this.todoCacheService.cacheTodos(todos);
}
@Get()
public todos(): Promise<Todo[]> {
return null;
}
}
Defines whether a request should be sent with outgoing credentials (cookies). Default true
It can be set in module config as base option. That would configure for all requests unless it is declared especially by other methods.
Example:
import { NgModule } from '@angular/core';
import { RestModule } from '@thalesrc/angular-rest';
@NgModule({
imports: [
RestModule.forRoot({withCredentials: false})
...
],
})
export class AppModule {}
It can be provided with the BASE_WITH_CREDENTIALS
token as base option. That would also configure for all requests like As Module Config unless it is declared especially by other methods.
Example:
import { NgModule } from '@angular/core';
import { RestModule, BASE_WITH_CREDENTIALS } from '@thalesrc/angular-rest';
@NgModule({
imports: [
RestModule
...
],
providers: [
{provide: BASE_WITH_CREDENTIALS, useValue: false},
...
]
})
export class AppModule {}
It can be set in @Client()
decorator as an option. That would configure withCredentials option for all the calls in that client.
Example:
import { Client } from '@thalesrc/angular-rest';
@Injectable()
@Client({
withCredentials: true
})
export class TodoClient {
...
}
It can be set by @WithCredentials()
decorator on top a rest call. That would configure withCredentials option for only that call.
Example:
import { Client, WithCredentials } from '@thalesrc/angular-rest';
@Injectable()
@Client()
export class TodoClient {
@Get()
@WithCredentials(true)
public todos(): Promise<Todo[]> {
return null;
}
}
to be developed
This package supports aot builds, however there are some limitations.
- Every
@Client
constructor should be defined as:
import { Injector } from '@angular/core';
import { Client } from '@thalesrc/angular-rest';
@Injectable()
@Client()
export class TodoClient {
constructor(injector: Injector) {}
}
- Injectables should be injected via
InjectToken
decorator
import { Injector } from '@angular/core';
import { Client, InjectToken } from '@thalesrc/angular-rest';
import { AuthService } from './auth.service';
@Client()
export class TodoClient {
@InjectToken(AuthService)
private authService: AuthService;
constructor(injector: Injector) {}
}
- Base handlers and base headers shouldn't be defined in
RestModule.forRoot
static method. All of these should be provided in module providers
import { NgModule } from '@angular/core';
import { RestModule, BASE_HEADERS, BASE_HANDLERS } from '@thalesrc/angular-rest';
import { BaseHeaders, BaseHandler } from './services';
@NgModule({
imports: [RestModule],
providers: [
BaseHeaders,
BaseHandler,
{provide: BASE_HEADERS, useValue: [BaseHeaders, {'Secret-Key': 'topsecret'}], multi: true},
{provide: BASE_HANDLERS, useValue: [BaseHandler], multi: true},
]
})
export class AppModule {}
Ali Şahin Özçelik
This repository is started as a fork of steven166/angular-rest-client and completely refactored now
MIT