Common MobX abstract base Class & Decorator utilities for RESTful API.
Just define your Data models & Client HTTP methods, then leave rest of things to MobX!
SemVer | status | ES decorator | MobX |
---|---|---|---|
>=0.7.0 |
✅developing | stage-3 | >=6.11 |
<0.7.0 |
❌deprecated | stage-2 | >=4 <6.11 |
package.json
{
"dependencies": {
"koajax": "^3.0.0",
"mobx": "^6.13.1",
"mobx-restful": "^1.0.1"
},
"resolutions": {
"native-file-system-adapter": "npm:@tech_query/native-file-system-adapter@^3.0.1"
}
}
This
resolutions
configuration is used for Node.js, such Back-end API or Server-side Rendering.You should install your project with Yarn or PNPM to support this feature.
It can be removed after
require('esm')
shipped formally.
tsconfig.json
{
"compilerOptions": {
"target": "ES6",
"moduleResolution": "Node",
"useDefineForClassFields": true,
"experimentalDecorators": false,
"jsx": "react-jsx"
}
}
model/client.ts
import { HTTPClient } from 'koajax';
export const client = new HTTPClient({
baseURI: 'https://api.github.com/',
responseType: 'json'
});
model/Repository.ts
import { buildURLData } from 'web-utility';
import { Filter, ListModel } from 'mobx-restful';
import { components } from '@octokit/openapi-types';
import { client } from './client';
export type Organization = components['schemas']['organization-full'];
export type Repository = components['schemas']['minimal-repository'];
export class RepositoryModel<
D extends Repository = Repository,
F extends Filter<D> = Filter<D>
> extends ListModel<D, F> {
client = client;
baseURI = 'orgs/idea2app/repos';
async loadPage(page: number, per_page: number) {
const { body } = await this.client.get<D[]>(
`${this.baseURI}?${buildURLData({ page, per_page })}`
);
const [_, organization] = this.baseURI.split('/');
const {
body: { public_repos }
} = await this.client.get<Organization>(`orgs/${organization}`);
return { pageData: body, totalCount: public_repos };
}
}
export default new RepositoryModel();
page/Repository.tsx
Use WebCell as an Example
import { component, observer } from 'web-cell';
import repositoryStore from '../model/Repository';
@component({ tagName: 'repository-page' })
@observer
export class RepositoryPage extends HTMLElement {
connectedCallback() {
repositoryStore.getList();
}
disconnectedCallback() {
repositoryStore.clear();
}
render() {
const { currentPage } = repositoryStore;
return (
<ul>
{currentPage.map(({ full_name, html_url }) => (
<li key={full_name}>
<a target="_blank" href={html_url}>
{full_name}
</a>
</li>
))}
</ul>
);
}
}
model/PreloadRepository.ts
import { buildURLData } from 'web-utility';
import { Buffer } from 'mobx-restful';
import { client } from './client';
import { Repository, RepositoryModel } from './Repository';
export class PreloadRepositoryModel extends Buffer<Repository>(
RepositoryModel
) {
client = client;
baseURI = 'orgs/idea2app/repos';
loadPage = RepositoryModel.prototype.loadPage;
}
export default new PreloadRepositoryModel();
model/MultipleRepository.ts
import { buildURLData, mergeStream } from 'web-utility';
import { Stream } from 'mobx-restful';
import { components } from '@octokit/openapi-types';
import { client } from './client';
import { Repository, RepositoryModel } from './Repository';
export type User = components['schemas']['public-user'];
export class MultipleRepository extends Stream<Repository>(RepositoryModel) {
declare baseURI: string;
client = client;
async *getOrgRepos() {
const {
body: { public_repos }
} = await this.client.get<Organization>('orgs/idea2app');
this.totalCount = public_repos;
for (let i = 1; ; i++) {
const { body } = await this.client.get<Repository[]>(
'orgs/idea2app/repos?page=' + i
);
if (!body[0]) break;
yield* body;
}
}
async *getUserRepos() {
const {
body: { public_repos }
} = await this.client.get<User>('users/TechQuery');
this.totalCount = public_repos;
for (let i = 1; ; i++) {
const { body } = await this.client.get<Repository[]>(
'users/TechQuery/repos?page=' + i
);
if (!body[0]) break;
yield* body;
}
}
openStream() {
return mergeStream(
this.getOrgRepos.bind(this),
this.getUserRepos.bind(this)
);
}
}
export default new MultipleRepository();
Here is an example: