# rest-annotations

[![version](https://img.shields.io/npm/v/rest-annotations.svg?style=flat)](https://www.npmjs.com/package/rest-annotations) [![Build Status](https://img.shields.io/bitbucket/pipelines/dkhang97/rest-annotations.svg)](https://bitbucket.org/dkhang97/rest-annotations/addon/pipelines/home) [![Coverage Status](https://coveralls.io/repos/bitbucket/dkhang97/rest-annotations/badge.svg)](https://coveralls.io/bitbucket/dkhang97/rest-annotations) [![npm](https://img.shields.io/npm/l/rest-annotations.svg)](https://opensource.org/licenses/MIT)

## Installation

```bash
npm i rest-annotations --save
```

## Example

```ts
import { Inject, Injectable, Injector } from '@angular/core';
import {
    RESTClient, GenerateBody, BaseUrl,
    GET, POST, PUT, PATCH, DELETE,
    Headers, Paths, Queries, Fields,
    Header, Path, Query, Field, Body
} from 'rest-annotations';
// import { AxiosRESTClient } from 'rest-annotations/axios';
// import { NodeRESTClient } from 'rest-annotations/node';
import { AngularRESTClient } from 'rest-annotations/angular';
import { Observable } from 'rxjs';

import { Todo } from './models';

@Injectable()
@BaseUrl('http://localhost:4200/api/')
// @Headers({
//     'Content-Type': 'application/x-www-form-urlencoded',
// })
// export class ApiClient extends AxiosRESTClient {
// export class ApiClient extends NodeRESTClient {
export class ApiClient extends AngularRESTClient {

    constructor(injector: Injector) {
        super(injector);
    }

    protected getDefaultHeaders() {
        return {
            'Content-Type': 'application/x-www-form-urlencoded',
            'X-Auth-Token': 'abc12356asd'
        };
    }

    @GET("todo")
    @Headers({ 'X-Auth-Token': null })
    @Queries({ pageSize: 20 })
    getTodoList(
        @Query("sort") sort?: string
    ): Promise<Todo[]> { return; }

    @GET("todo/{id}")
    getTodo(
        @Path("id") id: string
    ): Promise<Todo> { return; }

    @POST("todo")
    @Fields({ active: 1 })
    createTodo(
        @Body todo: Todo
    ): Promise<Todo> { return; }

    @PUT("todo", { generateBody: GenerateBody.Json })
    editTodo(
        @Field("id") id: string,
        @Body todo: Todo
    ): Promise<Todo> { return; }

    @DELETE("todo/{id}", { responseStrategy: 'httpResponse' })
    deleteTodo(
        @Path("id") id: string
    ): Observable<Todo> { return; }

}
```

### For Angular

#### Import to your module

``` ts
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    // ...
    HttpClientModule,
  ],
  providers: [ApiClient],
})
export class AppModule { }
```

#### Using it in your component

``` ts
@Component({
  selector: 'app-to-do',
  templateUrl: './to-do.component.html',
})
export class ToDoComponent {

  constructor(
    private api: ApiClient
  ) {  }
  
  // Use API
}
```

---

## API Docs

### RESTClient

#### Methods

>- **`getBaseUrl(): string | Promise<string>`**: returns the base url of RESTClient
>- **`getDefaultHeaders(metaHeaders?: Record<string, string | string[] | number>): Record<string, string | string[] | number> | Promise<Record<string, string | string[] | number>>`**: returns the default headers of RESTClient in a key-value pair
>- **`getAuthenticationHeader(action?: string, args?: any[]): Record<string, string | string[] | number> | Promise<Record<string, string | string[] | number>>`**: return authentication header for `@Authentication`
>- **`requestInterceptor(req: HttpRequest<any>): void`**: intercept api request
>- **`responseInterceptor(response: HttpResponse<any>, responseStrategy: string): any`**: intercept api response
>- **`_noop()`**: typing the consumer

#### Class decorators

>- **`@BaseUrl(url: string)`**: will replace `getBaseUrl()` of the service
>- ~~**`@DefaultHeaders(headers: Record<string, string | string[] | number>, overlap?: boolean)`**: set default value for  `getDefaultHeaders()`~~
>
>##### SERVICE DEFAULT PARAMS
>
>- **`@Headers(values: Record<string, string | string[] | number>, overlap?: boolean)`**
>- **`@Queries(values: Record<string, any>, overlap?: boolean)`**
>- **`@Paths(values: Record<string, string | number | { value: string | number, preserve?: boolean }>, overlap?: boolean)`**
>- **`@Fields(values: Record<string, any>, overlap?: boolean)`**
>
>##### SERVICE HEADER CUSTOMIZATION
>
>- **`@HFormUrlEncoded()`**: set **Content-Type** in default headers to **application/x-www-form-urlencoded**
>- **`@HJson()`**: set **Content-Type** in default headers to **application/json**
>- **`@Authentication(requireAuthentication?: boolean)`**

#### Method decorators

>##### HTTP METHOD
>
>- **`@GET(url: String, opts?: RestMethodOptions)`**
>- **`@POST(url: String, opts?: RestMethodOptions)`**
>- **`@PUT(url: String, opts?: RestMethodOptions)`**
>- **`@PATCH(url: String, opts?: RestMethodOptions)`**
>- **`@DELETE(url: String, opts?: RestMethodOptions)`**
>
>##### DEFAULT PARAMS
>
>- **`@Headers(values: Record<string, string | string[] | number>)`**
>- **`@Queries(values: Record<string, any>)`**
>- **`@Paths(values: Record<string, string | number | { value: string | number, preserve?: boolean }>)`**
>- **`@Fields(values: Record<string, any>)`**
>
>##### HEADER CUSTOMIZATION
>
>- **`@HFormUrlEncoded()`**
>- **`@HJson()`**
>- **`@Authentication(requireAuthentication?: boolean)`**
>
#### Parameter decorators
>
>- **`@Path(key: string)`**
>- **`@Query(key: string)`**
>- **`@Header(key: string)`**
>- **`@Field(key: string)`**
>- **`@QueryObject`**
>- **`@Body`**

### RestMethodOptions

>- **`generateBody`**: specify the function to generate the body of a request
>- **`responseStrategy`**: strategy of response type, if using Angular, specify one of 'promise', 'httpResponse', 'observable', 'raw'

---

## License

MIT
