Skip to content

Commit

Permalink
0.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
keenondrums committed Jan 27, 2019
1 parent 329fa2c commit 5f3be78
Show file tree
Hide file tree
Showing 31 changed files with 5,527 additions and 2,859 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@
node_modules
*.log*
/dist
*.tgz
*.tgz
/coverage
5 changes: 5 additions & 0 deletions .huskyrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"hooks": {
"pre-commit": "npx lint-staged"
}
}
11 changes: 11 additions & 0 deletions .lintstagedrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"*.{js,ts,tsx,json,css,less,yml}": [
"npx prettier --write",
"git add"
],
"*.md": [
"npx doctoc",
"npx prettier --write",
"git add"
]
}
4 changes: 2 additions & 2 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
*.idea
node_modules
*.log*
/src
Expand All @@ -9,4 +8,5 @@ node_modules
.prettierignore
.vscode
*.tgz
*.md
*.md
/coverage
2 changes: 0 additions & 2 deletions .prettierignore

This file was deleted.

7 changes: 7 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"trailingComma": "all",
"semi": false,
"singleQuote": true,
"arrowParens": "always",
"printWidth": 120
}
5 changes: 0 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
language: node_js
node_js:
- 'lts/*'
before_install:
- npm i -g [email protected]
install:
- npm ci
- npm i axios
script:
- npm run lint
- npm test
Expand Down
6 changes: 4 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"tslint.nodePath": "node_modules"
}
"tslint.nodePath": "node_modules",
"spellright.language": ["en"],
"spellright.documentTypes": ["markdown", "latex", "plaintext"]
}
163 changes: 64 additions & 99 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# axios-rest-resource [![Build Status](https://travis-ci.org/keenondrums/axios-rest-resource.svg?branch=master)](https://travis-ci.org/keenondrums/axios-rest-resource)

Small library that creates a pre-configured instance of axios to make HTTP requests to REST resources. Written in Typescript. Heavily inspired by AngularJS' $resource.
Schema-based HTTP client powered by axios. Built with Typescript. Heavily inspired by AngularJS' `$resource`.

<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
Expand All @@ -9,8 +9,7 @@ Small library that creates a pre-configured instance of axios to make HTTP reque
- [Quick start](#quick-start)
- [URL token substituion](#url-token-substituion)
- [Custom resource schema](#custom-resource-schema)
- [Adavanced usage](#adavanced-usage)
- [API](#api)
- [In depth](#in-depth)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand All @@ -26,20 +25,20 @@ npm i axios-rest-resource axios

```ts
// utils/resource.ts
import { ResourceBuilder } from "axios-rest-resource";
import { ResourceBuilder } from 'axios-rest-resource'

export const resourceBuilder = new ResourceBuilder({
baseURL: "http://localhost:3000"
});
baseURL: 'http://localhost:3000',
})
```

- Using a newly created resource builder create an actual resource

```ts
// api/entity1.js
import { resourceBuilder } from "utils/resource";
import { resourceBuilder } from 'utils/resource'
export const entity1Resource = resourceBuilder.build({ url: "/entity1" });
export const entity1Resource = resourceBuilder.build({ url: '/entity1' })
// exports an object
// {
// create: (requestConfig) => axiosPromise // sends POST http://localhost:3000/entity1,
Expand All @@ -53,72 +52,67 @@ npm i axios-rest-resource axios
- Use your resource whenever you want to make an AJAX call

```ts
import { entity1Resource } from "api/entity1";
import { entity1Resource } from 'api/entity1'
const resRead = entity1Resource.read();
const resRead = entity1Resource.read()
// sends GET http://localhost:3000/entity1
// resRead is a Promise of data received from the server
const resReadOne = entity1Resource.readOne({ params: { id } });
const resReadOne = entity1Resource.readOne({ params: { id } })
// for id = '123'
// sends GET http://localhost:3000/entity1/123
// resReadOne is a Promise of data received from the server
const resCreate = entity1Resource.create({ data });
const resCreate = entity1Resource.create({ data })
// for data = { field1: 'test' }
// sends POST http://localhost:3000/entity1 with body { field1: 'test' }
// resCreate is a Promise of data received from the server
const resUpdate = entity1Resource.update({ data, params: { id } });
const resUpdate = entity1Resource.update({ data, params: { id } })
// for data = { field1: 'test' } and id = '123'
// sends PUT http://localhost:3000/entity1/123 with body { field1: 'test' }
// resUpdate is a Promise of data received from the server
const resRemove = entity1Resource.remove({ params: { id } });
const resRemove = entity1Resource.remove({ params: { id } })
// for id = '123'
// sends DELETE http://localhost:3000/entity1/123
// resRemove is a Promise of data received from the server
```

## URL token substituion

axios-rest-resource applies [interceptorUrlFormatter](docs/api/README.md#interceptorurlformatter) interceptor by default. It handles {token} substituin in URLs.
axios-rest-resource applies [interceptorUrlFormatter](src/url-formatter.ts) interceptor by default. It handles {token} substitution in URLs.

## Custom resource schema

- Create resource module in your utils folder

```ts
// utils/resource.ts
import { ResourceBuilder } from "axios-rest-resource";
import { ResourceBuilder } from 'axios-rest-resource'
export const resourceBuilder = new ResourceBuilder({
baseURL: "http://localhost:3000"
});
baseURL: 'http://localhost:3000',
})
```

- Using a newly created resource builder create an actual resource

```ts
// api/entity2.js
import {
IResourceSchemaKeysDefault,
resourceSchemaDefault
} from "axios-rest-resource";
import { resourceBuilder } from "utils/resource";
export const entity2Resource = resourceBuilder.build<
IResourceSchemaKeysDefault | "doSomething"
>({
import { resourceSchemaDefault } from 'axios-rest-resource'
import { resourceBuilder } from 'utils/resource'
export const entity2Resource = resourceBuilder.build({
schema: {
...resourceSchemaDefault,
doSomething: {
method: "post",
url: "/do-something"
}
method: 'post',
url: '/do-something',
},
},
url: "/entity2"
});
url: '/entity2',
})
// exports an object
// {
// create: (requestConfig) => axiosPromise // sends POST http://localhost:3000/entity2,
Expand All @@ -133,33 +127,33 @@ axios-rest-resource applies [interceptorUrlFormatter](docs/api/README.md#interce
- Use your resource whenever you want to make an AJAX call

```ts
import { entity2Resource } from "api/entity2";
import { entity2Resource } from 'api/entity2'
const resRead = entity2Resource.read();
const resRead = entity2Resource.read()
// sends GET http://localhost:3000/entity2
// resRead is a Promise of data received from the server
const resReadOne = entity2Resource.readOne({ params: { id } });
const resReadOne = entity2Resource.readOne({ params: { id } })
// for id = '123'
// sends GET http://localhost:3000/entity2/123
// resReadOne is a Promise of data received from the server
const resCreate = entity2Resource.create({ data });
const resCreate = entity2Resource.create({ data })
// for data = { field1: 'test' }
// sends POST http://localhost:3000/entity2 with body { field1: 'test' }
// resCreate is a Promise of data received from the server
const resUpdate = entity2Resource.update({ data, params: { id } });
const resUpdate = entity2Resource.update({ data, params: { id } })
// for data = { field1: 'test' } and id = '123'
// sends PUT http://localhost:3000/entity2/123 with body { field1: 'test' }
// resUpdate is a Promise of data received from the server
const resRemove = entity2Resource.remove({ params: { id } });
const resRemove = entity2Resource.remove({ params: { id } })
// for id = '123'
// sends DELETE http://localhost:3000/entity2/123
// resRemove is a Promise of data received from the server
const resDoSomething = entity2Resource.doSomething();
const resDoSomething = entity2Resource.doSomething()
// sends POST http://localhost:3000/entity2/do-something
// resDoSomething is a Promise of data received from the server
```
Expand All @@ -168,17 +162,17 @@ You custom schema does not need to extend default schema if you do not want that

```ts
// api/entity.js
import { resourceBuilder } from "utils/resource";
import { resourceBuilder } from 'utils/resource'
export const entityResource = resourceBuilder.build<"doSomething">({
export const entityResource = resourceBuilder.build({
schema: {
doSomething: {
method: "post",
url: "/do-something"
}
method: 'post',
url: '/do-something',
},
},
url: "/entity"
});
url: '/entity',
})
// exports an object
// {
// doSomething: (requestConfig) => axiosPromise // sends POST http://localhost:3000/entity/do-something
Expand All @@ -189,75 +183,46 @@ Alternatively you can use a partial of a default schema

```ts
// api/entity.js
import { resourceSchemaDefault } from "axios-rest-resource";
import { resourceBuilder } from "utils/resource";
import { resourceSchemaDefault } from 'axios-rest-resource'
import { resourceBuilder } from 'utils/resource'
const { read, readOne } = resourceSchemaDefault;
const { read, readOne } = resourceSchemaDefault
export const entityResource = resourceBuilder.build<"read" | "readOne">({
export const entityResource = resourceBuilder.build({
schema: {
read,
readOne
readOne,
},
url: "/entity"
});
url: '/entity',
})
// exports an object
// {
// read: (requestConfig) => axiosPromise // sends GET http://localhost:3000/entity,
// readOne: (requestConfig) => axiosPromise // sends GET http://localhost:3000/entity/{id},
// }
```

## Adavanced usage
## In depth

You can pass a custom axios instance factory to ResourceBuilder. It's useful if you want to do something more with your axios instance like add an interceptor.
What does `ResourceBuilder` do exactly upon creation?

```ts
import { ResourceBuilder } from "axios-rest-resource";
import axios, { AxiosInstance } from "axios";
const createAxiosInstanceFromUrl = (resourceUrl: string): AxiosInstance => {
const axiosInstance = axios.create({
// Don't forget to append resourceUrl to baseURL
baseURL: `http://localshot:3000${resourceUrl}`,
// It might be a good idea to tell your server what data you expect in return
headers: {
Accept: "application/json"
}
});
// This time we want to add response interceptors
axiosInstance.interceptors.response.use(myResponeInterceptor);
// Don't forget to add interceptorUrlFormatter if you want to keep {token} replacement in urls
axiosInstance.interceptors.request.use(interceptorUrlFormatter);
return axiosInstance;
};

export const resourceBuilder = new ResourceBuilder(createAxiosInstanceFromUrl);
```
When you call `new ResourceBuilder(axiosConfig)`

As you can see there's a lot you have to remember. Not to keep all those things in mind you can utilize [createAxiosResourceFactory](docs/api/README.md#createaxiosresourcefactory).
1. If your `axiosConfig` doesn't have `headers.Accept` property it sets it to 'application/json'.
1. It creates a new instance of axios passing `axiosConfig` to `axios.create`.
1. It adds `interceptorUrlFormatter` to request interceptors of the newly created instance of axios.
1. It exposes the newly created instance of axios for further modifications at `axiosInstance`.

Each instance of ResourceBuilder has its own `axiosInstance`. It's useful if you want to do something more with your axios instance like adding an interceptor.

```ts
import {
ResourceBuilder,
createAxiosResourceFactory
} from "axios-rest-resource";
import { AxiosInstance } from "axios";

const createAxiosResource = createAxiosResourceFactory({
baseURL: "http://localshot:3000"
});
const createAxiosInstanceFromUrl = (resourceUrl: string): AxiosInstance => {
// Creates an axios instance with appended resourceUrl and applied interceptorUrlFormatter. You can pass an additional array of request interceptors just like with ResourceBuilder. In fact ResourceBuilder uses this very function uner the hood.
const axiosInstance = createAxiosResource(resourceUrl);
// Add that response interceptor
axiosInstance.interceptors.response.use(myResponeInterceptor);
return axiosInstance;
};

export const resourceBuilder = new ResourceBuilder(createAxiosInstanceFromUrl);
```
import { ResourceBuilder } from 'axios-rest-resource'
import axios, { AxiosInstance } from 'axios'
## API
const resourceBuilder = new ResourceBuilder({
baseURL: 'http://localhost:3000',
})
resourceBuilder.axiosInstance.interceptors.response.use(myCustomResponeInterceptor)
[API reference](docs/api/README.md)
export resourceBuilder
```
Loading

0 comments on commit 5f3be78

Please sign in to comment.