Elodo
Communicate with any REST API in an elegant and object oriented way.
TOC
Quick preview
Installation
Setup
Fetching resources
Persisting resources
Relationships
Cancel requests
Cast attributes
File uploads
Options
Quick preview
const post = Post.$create({
title: 'What is Elodo?',
body: 'Elodo is an easy way to use resource models in front-end applications!',
});
await post.$store();
post.title = 'What is Elodo? Amazing!';
await post.$update();
const posts = await Post
.$request()
.$include('comments', 'author')
.$index();
const post = posts[0];
await post.$update();
Installation
npm install elodo
npm install axios
Setup
Structure
/src
├── /api
| ├── /resources
| | ├── post.js
| | └── comment.js
| └── client.js
| └── resource.js
| └── router.js
├── ...
└── app.js
Resource
api/resource.js
import { createResource } from 'elodo';
import { client } from './client';
import { router } from './router';
export const Resource = createResource({
client,
router,
});
api/router.js
import { createRouter } from 'elodo';
export const router = createRouter();
router.prefix('http://api.com/api/v1/', function (router) {
router.index('posts', () => `posts`);
router.store('posts', () => `posts`);
router.show('posts', (post) => `posts/${post.id}`);
router.update('posts', (post) => `posts/${post.id}`);
router.destroy('posts', (post) => `posts/${post.id}`);
router.resource('posts');
});
api/client.js
import Axios from 'axios';
export const client = function () {
return Axios.create();
};
api/resources/post.js
import { Resource } from '../resource';
export class Post extends Resource {
get _attributes () {
return {
id: null,
title: null,
body: null,
};
}
get _route () {
return 'posts';
}
}
Now you can use the post resource in app.js
or any other file
import { Post } from './api/resources/post';
const posts = await Post.$index();
const post = await Post.$find(1);
await post.$show();
await post.$store();
await post.$update();
await post.$destroy();
Fetching resources
Fetch list of resources
Fetch single resource
Fetch filtered list of resources
Fetch list of resources sorted by an attribute
Fetch list of resources with relationships
Fetch list of resources with selected fields
Fetch list of resources with appended fields
Fetch list of resources with specific params
Fetch paginated list of resources
Fetch list of resources
const posts = await Post.$index();
Fetch single resource
Find a resource by primary id
const post = await Post.$find(1);
Show a resource by its attributes
const post = Post.$create({ id: 1 });
await post.$show();
You can also use the $refresh
alias
const post = Post.$create({ id: 1 });
await post.$refresh();
Fetch filtered list of resources
const posts = await Post
.$request()
.$filter('title', 'Hello')
.$index();
You can also use the where
alias
const posts = await Post
.$request()
.$where('title', 'Hello')
.$index();
Fetch list of resources sorted by an attribute
const posts = await Post
.$request()
.$sort('title')
.$index();
Sort descending
const posts = await Post
.$request()
.$sortDesc('title')
.$index();
Combine multiple sorts
const posts = await Post
.$request()
.$sort('id')
.$sortDesc('name')
.$index();
Fetch list of resources with relationships
const posts = await Post
.$request()
.$include('comments', 'author')
.$index();
Fetch list of resources with selected fields
const posts = await Post
.$request()
.$fields({ 'posts': ['id', 'title'] })
.$index();
Fetch list of resources with appended fields
const posts = await Post
.$request()
.$append('published_at')
.$index();
Fetch list of resources with limited resultes
const posts = await Post
.$request()
.$limit(15)
.$index();
Fetch list of resources with specific params
const posts = await Post
.$request()
.$param('param', 'value')
.$index();
Fetch paginated list of resources
const pagination = await Post
.$request()
.$page({
size: 15,
number: 1,
})
.$index();
const post = pagination.data[0];
await post.$update();
Set the page directly
await Post
.$request()
.$page(1)
.$index();
Use with the limit param
await Post
.$request()
.$page(1)
.$limit(15)
.$index();
Persisting resources
Store resource
Update resource
Delete resource
Store resource
const post = Post.$create({ title: 'Hello' });
await post.$store();
Or use the $save
alias
const post = Post.$create({ title: 'Hello' });
await post.$save();
Update resource
const post = await Post.$find(1);
post.title = 'Updated title';
await post.$update();
Delete resource
const post = await Post.$find(1);
await post.$destroy();
Or use the $delete
alias
const post = await Post.$find(1);
await post.$delete();
Relationships
Start with defining your relationship routes
import { createRouter } from 'elodo';
export const router = createRouter();
router.prefix('http://api.com/api/v1/', function (router) {
router.resource('posts');
router.resource('posts.comments');
});
const post = Post.$find(1);
const comment = Comment.$create({ body: 'Hello' });
await comment.$parent(post).$store();
await comment.$store();
Cancel requests
import { Post } from './resources/post';
import { createSource, isCancel } from 'elodo';
const source = createSource();
Post.$source(source)
.$index()
.then((posts) => {
...
})
.catch((error) => {
if (isCancel(error)) {
}
});
source.cancel();
Cancel any crud action
import { Post } from './resources/post';
import { createSource, isCancel } from 'elodo';
const source = createSource();
const post = Post.$create();
post.$source(source)
.$store()
.then((posts) => {
})
.catch((error) => {
if (isCancel(error)) {
}
});
source.cancel();
Cast attributes
Cast nested properties
Custom cast
Cast to relationship
The cast property allows you to convert attributes coming from the server.
Build in cast types are: number
, float
, int
, bigint
, boolean
, string
, date
, json
, and json.parse
.
import { Resource } from '../resource';
export class Post extends Resource {
get _attributes () {
return {
id: null,
title: null,
published_at: null,
};
}
get _casts () {
return {
id: 'int',
published_at: 'date',
};
}
get _route () {
return 'posts';
}
}
Cast nested properties
import { Resource } from '../resource';
export class Post extends Resource {
get _attributes () {
return {
object: {
prop: null,
},
};
}
get _casts () {
return {
'object.prop': 'boolean',
};
}
get _route () {
return 'posts';
}
}
Custom cast
Add a function to that returns the transformed value.
import { Resource } from '../resource';
export class Post extends Resource {
get _attributes () {
return {
id: null,
title: null,
published_at: null,
};
}
get _casts () {
return {
published_at: (value) => new Date(value),
};
}
get _route () {
return 'posts';
}
}
Cast to relationship
import { Resource } from '../resource';
import { Comment } from './comment';
export class Post extends Resource {
get _attributes () {
return {
id: null,
title: null,
comments: null,
};
}
get _casts () {
return {
comments: (value) => Comment.$create(value),
};
}
get _route () {
return 'posts';
}
}
File uploads
Change the content type of the resource to formdata
./api/resources/post.js
import { Resource } from '../resource';
export class Post extends Resource {
get _attributes () {
return {
id: null,
thumbnail: null,
};
}
get _contentType () {
return 'formdata';
}
get _route () {
return 'posts';
}
}
In ./app.js
or any other file
import { Post } from './api/resources/post';
const fileInput = document.querySelector('#fileInput');
const file = fileInput.files[0];
const post = Post.$create({ file });
await post.$store();
Options
To add or override options you can create a base resource
import { createResource } from 'elodo';
import { client } from './client';
import { router } from './router';
const BaseResource = createResource({
client,
router,
});
export class Resource extends BaseResource {
get _attributes () {
return {
id: null,
};
}
get _route () {
return 'default.route';
}
get _primaryKey () {
return 'id';
}
get _casts () {
return {};
}
get _contentType () {
return 'json';
}
static $latest () {
return this.$request()
.$limit(5)
.$sortDesc('created_at')
.$index()
;
}
}