• Stars
    star
    209
  • Rank 188,325 (Top 4 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 8 years ago
  • Updated about 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

πŸ”΄ Rest API provider for angular 2.

ng2-rest-api

Ng2-rest-api - is a rest api provider for angular 2 for http actions request to server and instantiate models.

  • Describe api to define endpoints and actions
  • Improves code-reusability by separating configuration from code that does actual work.
  • That simplifies common GET, POST, DELETE, and UPDATE requests.
  • Use a parameterized URLs.
  • Easy headers read.
  • Cache requests (todo)

If you need - you can get plain text response (It is sometimes convenient, but do not overdo it)

For Angular 1: https://github.com/zaqqaz/ng-rest-api

directive

Installation

To install this library, run:

$ npm install ng2-rest-api --save

NEXT STEPS

  1. Describe models
  2. Create config
  3. Add to @NgModule and execute static method configure.
  4. Advice: use ApiProvider only in managers/services not from controllers.
  5. Enjoy!

Config

You should describe endpoints and http Actions. Ng2-rest-api already had config for popular actions (get(GET),query(GET, array), update(PUT), patch(PATCH), remove(DELETE)). But if you need you can override them and add any others.

directive

Let's look at the interfaces for config:

ApiConfig

interface ApiConfig {
  baseUrl: string,  // e.g. http://example.com:8080/api
  endpoints: Endpoint[]
}

Endpoint

interface Endpoint {
  name: OpaqueToken; // The name of emdpoint.
  route: string; // A parameterized part of URL
  model?: any; // {Object} - model on which will be mapped response, if no - return JSON object.
  actions?: Action[]; // Hash with declaration of custom actions that will be available in addition to the default set of default actions.
}

route - A parameterized part of URL template with parameters prefixed by : as in /user/:username. If you are using a url with a suffix, just add the suffix, like this: '/resource.json' or '/:id.json' or even '/resource/:resource_id.:format' If the parameter before the suffix is empty, :resource_id in this case, then the /. will be collapsed down to a single .. If you need this sequence to appear and not collapse then you can escape it with /\..

Action

interface Action {
   name: string, // The name of action.
   method: string, // Case insensitive HTTP method (e.g. GET, POST, PUT, DELETE, JSONP, etc).
   instantiateModel?: boolean, // need do instatiate model ? default - true; if no - return plain text response.
   isArray?: boolean, // If true then the returned object for this action is an array,
   headersForReading?: Array<string>, // Headers which need read
   params?: any, // Optional set of pre-bound parameters for this action
   cache?: any // todo
 }

params - Default values for url parameters. These can be overridden in actions methods. If a parameter value is a function, it will be called every time a param value needs to be obtained for a request (unless the param was overridden). The function will be passed the current data value as an argument. Each key value in the parameter object is first bound to url template if present and then any excess keys are appended to the url search query after the ?. Given a template /path/:verb and parameter {verb:'greet', salutation:'Hello'} results in URL /path/greet?salutation=Hello. If the parameter value is prefixed with @, then the value for that parameter will be extracted from the corresponding property on the data object (provided when calling a "non-GET" action method). For example, if the defaultParam object is {someParam: '@someProp'} then the value of someParam will be data.someProp. Note that the parameter will be ignored, when calling a "GET" action method (i.e. an action method that does not accept a request body)

How to use

// api: ApiProvider
// endpointName: {OpaqueToken} - endpoint name from config.
// actionName: {string} - default action name or any from config.
// body: {object} - body data for POST request. If is GET request body use as params
// params: {object} - additional params which will be mixed with pre-bound parameters for this action and override them if will has the same key.
this.api.endpoint(endpointName).action(actionName', body, params);

Examples:

Model

import {Image} from 'api/models/Image';

export class Post {
  id?: number;
  title: string;
  description: string;
  content: string;
  image: Image | any;

  constructor({id, title, description, content, image}:
              {id?: number, title: string, description: string, content: string, image: Image|any}) {
    this.id = id;
    this.title = title;
    this.description = description;
    this.content = content;
    this.image = new Image(image);
  }

  beforeSave() {
    if (this.image) {
      this.image = this.image.id;
    }
  }
}

Config:

import {OpaqueToken} from "@angular/core";
import {Post} from "api/models/Post";

// endpoints
export const POSTS = new OpaqueToken('POSTS');

// config
export const apiConfig = {
  baseUrl: 'http://localhost:3000',
  endpoints: [
    {
      name: POSTS,
      model: Post,
      route: '/posts/:id',
      actions: [
        {
          name: 'query',
          method: 'GET',
          isArray: true,
          headersForReading: ['X-Total-Count'],
          params: {limit: 10}
        }
      ]
    }
  ]
};

@NgModule

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';

import {AppComponent} from './app.component';
import {MainComponent} from './endpoints/main/main.component';
import {RouterModule} from '@angular/router';
import {routes} from './app.routes'
import {TypingCarouselDirective} from "./endpoints/main/typing-carousel.directive";
import {LoaderComponent} from './shared/loader/loader.component';
import {Ng2RestApiModule, ApiProvider} from "ng2-rest-api";
import {apiConfig} from "api/config";

import {PostsManager} from './api/services/PostsManager';
import { PostsComponent } from './endpoints/posts/posts.component';

@NgModule({
  declarations: [
    AppComponent,
    MainComponent,
    TypingCarouselDirective,
    LoaderComponent,
    PostsComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule.forRoot(routes),
    Ng2RestApiModule.configure(apiConfig)
  ],
  providers: [ApiProvider, PostsManager],
  bootstrap: [AppComponent]
})
export class AppModule {
}

Service

import {ApiProvider} from "ng2-rest-api";
import {POSTS} from "api/config";
import {Injectable} from "@angular/core";
import {Post} from "api/models/Post";

@Injectable()
export class PostsManager {
  constructor(private api: ApiProvider) {
  }

  getPost(id: number) {
    return this.api.endpoint(POSTS).action('get', {id});
  }

  queryPosts(query: string, offset: number) {
    return this.api.endpoint(POSTS).action('query', {query, offset});
  }

  savePost(post: Post) {
    return post.id ? this.api.endpoint(POSTS).action('update', post) : this.api.endpoint(POSTS).action('save', post);
  }
}

Controller

import {Component, OnInit} from '@angular/core';
import {PostsManager} from 'api/services/PostsManager';
import {Post} from 'api/models/Post';
import {Image} from 'api/models/Image';

@Component({
  selector: 'app-post',
  templateUrl: './post.component.html',
  styleUrls: ['./post.component.scss']
})
export class PostComponent implements OnInit {

  constructor(private postsManager: PostsManager) {}

  example() {
    // search 'evolution' posts with offset = 0
    this.postsManager.queryPosts('evolution', 0).subscribe(([posts, headers]) => {
      this.total = headers['X-Total-Count'];
      this.posts = posts;
      console.log('Response', this.posts, 'X-Total-Count', this.total);
    });

    // get post with id 1
    this.postsManager.getPost(1).subscribe(post => {
      console.log('SINGLE', post);

      // update post
      post.content = 'updated content';
      this.postsManager.savePost(post).subscribe(p => console.log('updated'));
    });

    // create new post
    this.postsManager.savePost(new Post({
      title: 'test',
      description: "test",
      content: 'test',
      image: new Image({id: 1, src: ''})
    })).subscribe(p => console.log('saved'));
  }
}

To Do

  • Improve documentation.
  • Cache
  • Add tests
  • Method to set headers for all actions, and for specific. (Authorization token etc.)

Cache

Will be implemented soon.

More Repositories

1

ng-rest-api

🀘 Rest API provider for angular.
JavaScript
133
star
2

jest-allure

Generate Allure Report for jest. Allure Report, a flexible lightweight multi-language test report tool with the possibility to add steps, attachments, parameters and so on.
TypeScript
113
star
3

visual-unit-tests

🏞Example how to implement visual unit tests for React application with jest and puppeteer plus allure report
TypeScript
54
star
4

ng2-typing-carousel

πŸ“ Simple typing carousel directive for angular2.
JavaScript
11
star
5

wspr

WebSocket proxy for post http requests. Perfect for testing purposes/mocks πŸš€
TypeScript
10
star
6

terraform-typescript-frontend-infrastructure

AWS frontend infrastructure managed by terraform written with typescript
TypeScript
8
star
7

iac-talk-demo-project

Infrastructure As Code for JS applications on AWS with TypeScript
TypeScript
7
star
8

jest-environment-puppeteer-jsdom

JavaScript
3
star
9

Angular2-starter-kit

πŸš€ Seed project for Angular 2 with typescript and es6 features (Typescript, Babel, Webpack, Gulp).
JavaScript
3
star
10

uptoversion

Raise a pull request to update the dependency to the specific version in any project
TypeScript
3
star
11

transformCssClassNames

Convert your css/scss/pcss/less class names
CSS
2
star
12

SimpleGallery

πŸ“· Angular 1.5, Symfony 2.8, vagrant, postgreSql
PHP
1
star
13

jest-image

πŸŒ‡vs πŸŒ†Custom jest matchers to test the visual regression
TypeScript
1
star
14

jest-allure-image-snapshot

JavaScript
1
star
15

recoil-experiments

TypeScript
1
star
16

demoRN

TypeScript
1
star
17

js-inline-css-webpack-plugin

Simple webpack plugin for convert external stylesheet to embedded into js stylesheet
JavaScript
1
star
18

dynamicPixelmatch

Exclude some areas from image before comparison using pixelmatch
JavaScript
1
star