Merge pull request #5946 from tkqubo/restful.js

Add restful.js
This commit is contained in:
Masahiro Wakame
2015-09-27 12:00:42 +09:00
2 changed files with 443 additions and 0 deletions
+198
View File
@@ -0,0 +1,198 @@
/// <reference path="restful.js.d.ts" />
import restful, {
Api, MemberResponse, CollectionResponse, ResponseBody, CollectionEndpoint, MemberEndpoint,
} from 'restful.js';
class Article {
title: string;
body: string;
}
class Comment {
body: string;
}
class Author {
name: string;
}
var api: Api;
api = restful('api.example.com');
//
// Usage
//
api = restful('api.example.com')
.header('AuthToken', 'test') // set global header
.prefixUrl('v1')
.protocol('https')
.port(8080);
// resource now targets `https://api.example.com:8080/v1`
var articlesCollection = api.all('articles'); // http://api.example.com/articles
var articleMember = api.one('articles', 1); // http://api.example.com/articles/1
var articleMember = api.one('articles', 1); // http://api.example.com/articles/1
var commentsCollection = articleMember.all('comments'); // http://api.example.com/articles/1/comments
var articleMember = api.oneUrl('articles', 'http://custom.url/article?id=1'); // http://custom.url/article?id=1
var articlesCollection = api.allUrl('articles', 'http://custom.url/article/list'); // http://custom.url/article/list
articleMember = api.one('articles', 1); // http://api.example.com/articles/1
articleMember.get().then((response: MemberResponse<Article>) => {
var articleEntity = response.body();
var article = articleEntity.data();
console.log(article.title); // hello, world!
});
commentsCollection = articleMember.all('comments'); // http://api.example.com/articles/1/comments
commentsCollection.getAll().then((response: CollectionResponse<Comment>) => {
var commentEntities = response.body();
commentEntities.forEach((commentEntity: ResponseBody<Comment>) => {
var comment = commentEntity.data();
console.log(comment.body);
})
});
// fetch http://api.example.com/articles/1/comments/4
articleMember = api.one('articles', 1);
let commentMember = articleMember.one('comments', 4);
commentMember.get().then((response) => {
//
});
// equivalent to
commentsCollection = articleMember.all('comments');
commentsCollection.get(4).then((response) => {
//
});
//
// Entity Data
//
var articleCollection = api.all('articles'); // http://api.example.com/articles
// http://api.example.com/articles/1
api.one('articles', 1).get().then((response: MemberResponse<Article>) => {
var articleEntity = response.body();
// if the server response was { id: 1, title: 'test', body: 'hello' }
var article = articleEntity.data();
article.title; // returns `test`
article.body; // returns `hello`
// You can also edit it
article.title = 'test2';
// Finally you can easily update it or delete it
articleEntity.save(); // will perform a PUT request
articleEntity.remove(); // will perform a DELETE request
}, (response: any) => {
// The reponse code is not >= 200 and < 400
throw new Error('Invalid response');
});
articleMember = api.one('articles', 1); // http://api.example.com/articles/1
commentMember = articleMember.one('comments', 3); // http://api.example.com/articles/1/comments/3
commentMember.get()
.then((response: MemberResponse<Comment>) => {
var commentEntity = response.body();
// You can also call `all` and `one` on an entity
return commentEntity.all('authors').getAll(); // http://api.example.com/articles/1/comments/3/authors
}).then((response: CollectionResponse<Author>) => {
var authorEntities = response.body();
authorEntities.forEach((authorEntity: ResponseBody<Author>) => {
var author = authorEntity.data();
console.log(author.name);
});
});
// configure the api
api.header('AuthToken', 'test');
articlesCollection = api.all('articles');
articlesCollection.get(1); // will send the `AuthToken` header
// You can configure articlesCollection, too
articlesCollection.header('foo', 'bar');
//TODO: The line below was written in README.md but actually incorrect invocation, hence commented out
//articlesCollection.one('comments', 1).get(); // will send both the AuthToken and foo headers
// http://api.example.com/articles/1/comments/2/authors
let authorsCollection = api.one('articles', 1).one('comments', 2).all('authors');
authorsCollection.getAll().then(function(authorEntities) { /* */ });
authorsCollection.get(1).then(function(authorEntity) { /* */ });
//
// Interceptors
//
var resource: Api;
resource.addRequestInterceptor((data: any, headers: any, method: string, url: string) => {
// to edit the headers, just edit the headers object
// You always must return the data object
return data;
});
resource.addFullRequestInterceptor(function(params, headers, data, method, url) {
//...
// all args had been modified
return {
params: params,
headers: headers,
data: data,
method: method,
url: url
};
// just return modified arguments
return {
headers: headers,
data: data
};
});
resource.addFullResponseInterceptor(function(data, headers, method, url) {
// all args had been modified (method and url is read only)
return {
headers: headers,
data: data
};
// just return modified arguments
return {
headers: headers
};
});
//
// Response methods
//
// http://api.example.com/articles/1/comments/2
commentMember = api.one('articles', 1).one('comments', 2);
commentMember.get().then(function(response) {
let commentEntity = response.body();
commentEntity.save();
commentEntity.remove();
});
//
// Error Handling
//
commentMember = resource.one('articles', 1).one('comments', 2);
commentMember
.get()
.then(function(commentEntity) { /* */ })
.catch(function(err) {
// deal with the error
});
+245
View File
@@ -0,0 +1,245 @@
// Type definitions for restful.js 0.6.2
// Project: https://github.com/marmelab/restful.js
// Definitions by: Qubo <https://github.com/tkqubo>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
/// <reference path="../es6-promise/es6-promise.d.ts" />
declare module "restful.js" {
export interface Headers {
[key: string]: any
}
export interface Api extends Endpoint<Api> {
all(name: string): CollectionEndpoint;
allUrl(name: string, url: string): CollectionEndpoint;
one(name: string, id: any): MemberEndpoint;
oneUrl(name: string, url: string): MemberEndpoint;
protocol(protocol: string): Api;
protocol(): string;
baseUrl(protocol: string): Api;
baseUrl(): string;
port(port: number): Api;
port(): number;
prefixUrl(prefix: string): Api;
prefixUrl(): string;
customUrl(url: string): Api;
customUrl(): string;
}
export interface MemberEndpoint extends Endpoint<MemberEndpoint> {
/**
* Target a child collection name.
* @param name
*/
all(name: string): CollectionEndpoint;
allUrl(name: string, url: string): CollectionEndpoint;
/**
* Target a child member in a collection name.
* @param name
* @param id
*/
one(name: string, id: any): MemberEndpoint;
oneUrl(name: string, url: string): MemberEndpoint;
/**
* Get a member. Returns a promise with an entity.
* @param params
* @param headers
*/
get<T>(params?: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Update a member. Returns a promise with the response.
* @param data
* @param headers
*/
put<T>(data: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Delete a member. Returns a promise with the response.
* @param data
* @param headers
*/
delete<T>(data?: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Patch a member. Returns a promise with the response.
* @param data
* @param headers
*/
patch<T>(data: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Perform a HEAD request on a member. Returns a promise with the response.
* @param headers
*/
head<T>(headers?: any): Promise<MemberResponse<T>>;
customUrl(url: string): MemberEndpoint;
customUrl(): string;
}
export interface CollectionEndpoint extends Endpoint<CollectionEndpoint> {
/**
* Get a member in a collection. Returns a promise with an entity.
* @param id
*/
get<T>(id: any, params?: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Get a full collection. Returns a promise with an array of entities.
*/
getAll<T>(params?: any, headers?: Headers): Promise<CollectionResponse<T>>;
/**
* Create a member in a collection. Returns a promise with the response.
*/
post<T>(data: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Update a member in a collection. Returns a promise with the response.
* @param id
* @param data
* @param headers
*/
put<T>(id: any, data: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Delete a member in a collection. Returns a promise with the response.
* @param id
* @param data
* @param headers
*/
delete<T>(id: any, data?: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Patch a member in a collection. Returns a promise with the response.
* @param id
* @param data
* @param headers
*/
patch<T>(id: any, data: any, headers?: Headers): Promise<MemberResponse<T>>;
/**
* Perform a HEAD request on a member in a collection. Returns a promise with the response.
* @param id
* @param headers
*/
head<T>(id: any, headers?: Headers): Promise<MemberResponse<T>>;
}
export interface Endpoint<Self> {
/**
* Get the url.
*/
url(): string;
/**
* Add a response interceptor. You can only alter data and headers.
*/
addResponseInterceptor(interceptor: ResponseInterceptor): Self;
responseInterceptors(): ResponseInterceptor[];
/**
* Add a request interceptor.
*/
addRequestInterceptor(interceptor: RequestInterceptor): Self;
requestInterceptors(): RequestInterceptor[];
/**
* Add a full response interceptor. You can alter data and headers.
*/
addFullResponseInterceptor(interceptor: ResponseInterceptor): Self;
fullResponseInterceptors(): ResponseInterceptor[];
/**
* Add a full request interceptor. You can alter params, headers, data, method and url.
*/
addFullRequestInterceptor(interceptor: FullRequestInterceptor): Self;
fullRequestInterceptors(): FullRequestInterceptor[];
/**
* Add a header.
* @param name
* @param value
*/
header(name: string, value: any): Self;
headers(): Headers;
}
export interface MemberResponse<T> extends ResponseBase {
(): {
data: T;
headers: Headers;
status: number;
statusText: string;
}
body(): ResponseBody<T>;
}
export interface CollectionResponse<T> extends ResponseBase {
(): {
data: T[];
headers: Headers;
status: number;
statusText: string;
}
body(): ResponseBody<T>[];
}
export interface ResponseBase {
status(): number;
headers(): Headers;
config(): any;
}
export interface ResponseBody<T> {
/**
* Get the JS object unserialized from the response body (which must be in JSON)
*/
data(): T;
(): T;
/**
* Query a collection child of the entity.
* @param entity
*/
all(entity: string): CollectionEndpoint;
/**
* Query a member child of the entity.
* @param entity
* @param id
*/
one(entity: string, id: any): MemberEndpoint;
/**
* Update the member link to the entity. Returns a promise with the response.
* @param headers
*/
save(headers?: Headers): void;
/**
* Delete the member link to the entity. Returns a promise with the response.
*/
remove(headers?: Headers): void;
/**
* Get the entity url.
*/
url(): string;
/**
* Get the id of the entity.
*/
id(): any;
}
export interface RequestInterceptor {
(data: any, headers: Headers, method: string, url: string): any;
}
export interface FullRequestInterceptor {
(params: any, headers: Headers, data: any, method: string, url: string): FullRequestInterceptorReturnValue;
}
export interface FullRequestInterceptorReturnValue {
params?: any;
headers?: Headers;
data?: any;
method?: string;
url?: string;
}
export interface ResponseInterceptor {
(data: any, headers: Headers, method: string, url: string): ResponseInterceptorReturnValue;
}
export interface ResponseInterceptorReturnValue {
headers?: Headers;
data?: any;
method?: string;
url?: string;
}
export default function restful(endpoint: string): Api;
}