diff --git a/restful.js/restful.js-tests.ts b/restful.js/restful.js-tests.ts new file mode 100644 index 000000000..80f3bd187 --- /dev/null +++ b/restful.js/restful.js-tests.ts @@ -0,0 +1,198 @@ +/// + +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
) => { + 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) => { + var commentEntities = response.body(); + + commentEntities.forEach((commentEntity: ResponseBody) => { + 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
) => { + 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) => { + 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) => { + var authorEntities = response.body(); + + authorEntities.forEach((authorEntity: ResponseBody) => { + 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 +}); diff --git a/restful.js/restful.js.d.ts b/restful.js/restful.js.d.ts new file mode 100644 index 000000000..2d62f113c --- /dev/null +++ b/restful.js/restful.js.d.ts @@ -0,0 +1,245 @@ +// Type definitions for restful.js 0.6.2 +// Project: https://github.com/marmelab/restful.js +// Definitions by: Qubo +// Definitions: https://github.com/borisyankov/DefinitelyTyped + +/// + +declare module "restful.js" { + export interface Headers { + [key: string]: any + } + + export interface Api extends Endpoint { + 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 { + /** + * 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(params?: any, headers?: Headers): Promise>; + /** + * Update a member. Returns a promise with the response. + * @param data + * @param headers + */ + put(data: any, headers?: Headers): Promise>; + /** + * Delete a member. Returns a promise with the response. + * @param data + * @param headers + */ + delete(data?: any, headers?: Headers): Promise>; + /** + * Patch a member. Returns a promise with the response. + * @param data + * @param headers + */ + patch(data: any, headers?: Headers): Promise>; + /** + * Perform a HEAD request on a member. Returns a promise with the response. + * @param headers + */ + head(headers?: any): Promise>; + customUrl(url: string): MemberEndpoint; + customUrl(): string; + } + + export interface CollectionEndpoint extends Endpoint { + /** + * Get a member in a collection. Returns a promise with an entity. + * @param id + */ + get(id: any, params?: any, headers?: Headers): Promise>; + /** + * Get a full collection. Returns a promise with an array of entities. + */ + getAll(params?: any, headers?: Headers): Promise>; + /** + * Create a member in a collection. Returns a promise with the response. + */ + post(data: any, headers?: Headers): Promise>; + /** + * Update a member in a collection. Returns a promise with the response. + * @param id + * @param data + * @param headers + */ + put(id: any, data: any, headers?: Headers): Promise>; + /** + * Delete a member in a collection. Returns a promise with the response. + * @param id + * @param data + * @param headers + */ + delete(id: any, data?: any, headers?: Headers): Promise>; + /** + * Patch a member in a collection. Returns a promise with the response. + * @param id + * @param data + * @param headers + */ + patch(id: any, data: any, headers?: Headers): Promise>; + /** + * Perform a HEAD request on a member in a collection. Returns a promise with the response. + * @param id + * @param headers + */ + head(id: any, headers?: Headers): Promise>; + } + + export interface Endpoint { + /** + * 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 extends ResponseBase { + (): { + data: T; + headers: Headers; + status: number; + statusText: string; + } + body(): ResponseBody; + } + + export interface CollectionResponse extends ResponseBase { + (): { + data: T[]; + headers: Headers; + status: number; + statusText: string; + } + body(): ResponseBody[]; + } + + export interface ResponseBase { + status(): number; + headers(): Headers; + config(): any; + } + + export interface ResponseBody { + /** + * 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; +} +