-
Notifications
You must be signed in to change notification settings - Fork 0
Quickstart
This guide quickly explains the concepts required to get started with this package and automatically consume API's. If you want a more thorough, in-depth explanation, follow Home.
We will be querying an example API that returns blog posts, categories and users. Each of these items constitute a new Entity. The JSON-format returned for each of these entities, is shown below:
Post
{
"id": 1,
"title": "Example post",
"body": "Lorem ipsum dolor sit amet.",
"categories": [
{
"id": 1,
"name": "News"
},
{
"id": 2,
"name": "General"
}]
}Category
{
"id": 3,
"name": "Example"
}User
{
"id": 1,
"first_name": "John",
"last_name": "Doe",
"email": "john.doe@example.com"
}We will be creating a new class for each of these items. Every class needs to inherit from Entity, as these items form information that we will be retrieving from our API later on.
Post
import {Entity} from "typescript-rest-mapper";
export default class Post extends Entity {
private _title: string;
private _body: string;
private _categories: Category[];
public get title(): string {
return this._title;
}
public set title(title: string) {
this._title = title;
}
public get body(): string {
return this._body;
}
public set body(body: string) {
this._body = body;
}
public get categories(): Category[] {
return this._categories;
}
public set categories(categories: Category[]) {
this._categories = categories;
}
}Category
import {Entity} from "typescript-rest-mapper";
export default class Category extends Entity {
private _name: string;
public get name(): string {
return this._name;
}
public set name(name: string) {
this._name = name;
}
}User
import {Entity} from "typescript-rest-mapper";
export default class User extends Entity {
private _firstName: string;
private _lastName: string;
private _email: string;
public get firstName(): string {
return this._firstName;
}
public set firstName(firstName: string) {
this._firstName = firstName;
}
public get lastName(): string {
return this._lastName;
}
public set lastName(lastName: string) {
this._lastName = lastName;
}
public get email(): string {
return this._email;
}
public set email(email: string) {
this._email = email;
}
}HINT: Each of these classes can be very quickly generated using a good IDE, like IntelliJ.
TypeScript Rest Mapper requires you to follow some conventions in declaring the properties of an Entity. The field should be named the same as in the REST API, but with an underscore at the front. A set() and get() method should be provided for every field, but without the underscore.
Note that we don't include the id field explicitly in the entities. This is not needed as the Entity superclass already provides this field as the package assumes that every REST API resource should contain an id.
Now, at this point we know what values the API returns and we can start annotating the fields of our entities with the correct decorators. There are 3 important decorators available:
-
Read(): This decorator is used to annotate a field that must be read from your REST API responses. Every field of anEntityannotated withRead()will automatically be filled in when callingretrieve()orlist()on an associatedService. -
Store(): This decorator indicates that the associated field is used to store an entity through the REST API. It will be used when callingstore()on an associatedService. -
Update(): This decorator indicates that the associated field is used to update an entity through the REST API. It will be used when callingupdate()on an associatedService.
For each of these decorators, there is an array counterpart that should be used when the annotated field contains an array. A limitation currently posed by TypeScript, requires you to explicitly specify the type of objects stored in the array. The following three decorators should be used when working with arrays:
-
ReadArray(type): Treats the associated field of the received response from the API as an array and fill it in completely. Example:ReadArray(Post)when annotating a field_posts: Post[]. -
StoreArray(type): Array analogue of theStore()decorator. -
UpdateArray(type): Array analogue of theUpdate()decorator.
Now that we know which decorators exist, we can annotate each of our example entities with the correct decorators.
Post
Title, body and categories all need to be read from an API response. This is why we annotate them with the read() (and readArray() for categories) decorator. The entities stored by the backend REST server also need to be updated when a user creates or modifies a post. All fields should be updated accordingly and that's why we also need to annotate these fields with update() and store(). I'm only repeating the changes made to the fields of the class, the setters and getters remain the same:
export default class Post extends Entity {
@Read() @Update() @Store()
private _title: string;
@Read() @Update() @Store()
private _body: string;
@ReadArray(Category) @UpdateArray(Category) @StoreArray(Category)
private _categories: Category[];
}Category
The Category class can be annotated analogous to the Post class. A category's name should be read, stored and updated and thus we add all three decorators:
export default class Category extends Entity {
@Read() @Update() @Store()
private _name: string;
}User
Just like the two entities above, we can annotate the fields in the User class with all 3 decorators.
export default class User extends Entity {
@Read() @Update() @Store()
private _firstName: string;
@Read() @Update() @Store()
private _lastName: string;
@Read() @Update() @Store()
private _email: string;
}We're almost done. We can now simply communicate with the REST server by creating an instance of the Service class. This class needs one parameter: the Entity for which a Service needs to be constructed. To be able to retrieve the post with id 1, we can do this:
let postService: Service<Post> = new Service<Post>(Post, "http://localhost:8080");
let post: Post = postService.retrieve(1);
// post is now a true TypeScript-object with all API information stored inside of it.Storing a new post is just as easy:
let postService: Service<Post> = new Service<Post>(Post, "http://localhost:8080");
let post: Post = new Post();
post.title = "Lorem ipsum";
post.body = "Dolor sit amet.";
let categoryService: Service<Category> = new Service<Category>(Category, "http://localhost:8080");
let generalCategory = categoryService.retrieve(2);
post.categories = [generalCategory];
postService.store(post);HINT: You can extend the Service-class and automatically fill in the base URL, if this stays the same over different invocations of the API:
export default class CustomService<T extends Entity> extends Service<T> {
constructor(x: (new () => T)) {
// Automatically fill in the base URL here!
super(x, "http://localhost:8080");
}
}At this point, you are able to start consuming simple API's. For more advanced use cases and examples, visit the other pages in this wiki.