Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/779 add remove parameter option #780

Merged
merged 10 commits into from
May 18, 2023
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
node-version: [16]
os: [ubuntu-latest, macOS-latest]
node-version: [18]
os: [ubuntu-latest]

steps:
- uses: actions/checkout@v3.5.2
Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ classes. Keep your code clean and elegant.
Wouldn't it be great if you could just use your back end to validate forms on the front end? This package provides a
`BaseService` class that does exactly that. It can post itself to a configured endpoint and manage errors. The class is
meant to be used with a Laravel back end, and it doesn't limit that you need only to work with laravel, Ruby on Rail,
NodeJs, ExpressJs, or any other languages.
Node.js, Express.js, or any other languages.

Take a look at the [usage section](#usage) to view a detailed example on how to use it.

Expand Down Expand Up @@ -47,16 +47,16 @@ export default {
// simple usage
'vue-axios-http/nuxt',
// With options
['vue-axios-http/nuxt', { errorProperty: 'errors' }],
['vue-axios-http/nuxt', { errorProperty: 'errors', resetParameter: true }],
'@nuxtjs/axios',
],
axiosHttp: { errorProperty: 'errors' },
axiosHttp: { errorProperty: 'errors', resetParameter: true },
}
```

### Options

you can overwrite it, by adding in config above.
you can overwrite it by adding in the config above.

### Note:

Expand Down Expand Up @@ -94,7 +94,7 @@ Vue.use(AxiosHttp)

### Note

Error response must look like: or base on **errorProperty** from config
Error response must look like: or based on **errorProperty** from config

```json
{
Expand Down Expand Up @@ -137,7 +137,7 @@ $errors.first(['name[0]']) // return object like
$errors.first(['name[0].kh']) // return string like
```

## Using with Vuex
## Using it with Vuex

1.Create **proxies** folder or your prefer folder name for this

Expand Down Expand Up @@ -296,7 +296,7 @@ export default {

You can set or remove any parameters you like.

## Service's methods are available
## Service methods are available

| Method | Description |
| ----------------------------------------------- | --------------------------- |
Expand All @@ -310,7 +310,7 @@ You can set or remove any parameters you like.

Set parameters with key/value.

**Note**: If you to pass query string as object that can be response like object format at api side.
**Note**: If you to pass query string, as an object that can be response like object format at api side.

#### Example

Expand All @@ -335,13 +335,13 @@ const { data } = service.setParameters(parameters).all()
this.data = data
```

**Note**: Query object above will transform into query string like:
**Note**: A query object above will transform into query string like:

```text
https://my-web-url.com?search[first_name]=Sek&search[last_name]=Chantouch&page[limit]=10&page[offset]=1&order[first_name]=asc&order[last_name]=desc&category_id=6
```

if setParameter that value is empty or null it will remove that param for query string
if setParameter that value is empty or null, it will remove that param for query string

#### setParameter()

Expand Down Expand Up @@ -426,7 +426,7 @@ It can be called by `this.$errors.**`
| **has(attributes)** | To check multiple attributes given have any errors |
| **first(attribute)** | To get errors message by an attribute |

## How to use in vue component
## How to use in a vue component

```vue
<template>
Expand Down
27 changes: 27 additions & 0 deletions src/__tests__/base-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ describe('BaseService', () => {
]
mockAdapter.onGet('/posts?id=1&first_name=Dara').reply(200, { data: items })
const { data } = await service.setParameter('id', 1).setParameters({ first_name: 'Dara' }).all()

expect(data).toEqual(items)
})

Expand Down Expand Up @@ -341,6 +342,32 @@ describe('BaseService', () => {
expect(service.$http.defaults.baseURL).toBe(undefined)
})
})
describe('BaseService -> Remove parameters', () => {
beforeEach(() => {
validator = Validator
const axios = Axios.create({ baseURL: 'https://mock-api.test' })
BaseService.$http = axios
BaseService.$resetParameter = true
BaseService.$errorProperty = 'message'

service = new PostService()
mockAdapter = new MockAdapter(axios)
mockAdapter.reset()
})

it('should clear the parameters, if the option `resetParameter` is true', async () => {
const items = [
{ first_name: 'Dara', last_name: 'Hok', id: 1 },
{ first_name: 'Chantouch', last_name: 'Sek', id: 2 },
]
mockAdapter.onGet('/posts?id=1&first_name=Dara').reply(200, { data: items })
const parameters = { first_name: 'Dara', id: 1 }
const { data } = await service.setParameter('id', 1).setParameters(parameters).all()

expect(data).toEqual(items)
expect(service.parameters).toEqual({})
})
})

function getFormDataKeys(formData: any) {
// This is because the FormData.keys() is missing from the jsdom implementations.
Expand Down
49 changes: 23 additions & 26 deletions src/core/BaseService.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { ValidatorType } from './Validator'
import type { AxiosError, AxiosInstance, Method, AxiosRequestConfig, AxiosResponse } from 'axios'
import type { IParseOptions } from 'qs'
import { isObject, isArray } from 'lodash'
Expand All @@ -13,23 +12,18 @@ interface AxiosResponseData {
[key: string | number]: any
}

class BaseService {
errors: ValidatorType
parameters: Record<string, any>
endpoint: string
export default class BaseService {
public errors = Validator
static $http: AxiosInstance
static $errorProperty = 'errors'
static $resetParameter? = false
static $parsedQs: IParseOptions = {
comma: true,
allowDots: true,
ignoreQueryPrefix: true,
}

constructor(endpoint: string, parameters: Record<string, any>) {
this.endpoint = endpoint
this.parameters = parameters
this.errors = Validator
}
constructor(readonly endpoint: string, public parameters: Record<string, any> = {}) {}

get $http() {
return BaseService.$http
Expand All @@ -39,6 +33,10 @@ class BaseService {
return BaseService.$errorProperty
}

get $resetParameter() {
return BaseService.$resetParameter
}

get $parsedQs() {
return BaseService.$parsedQs
}
Expand Down Expand Up @@ -85,15 +83,7 @@ class BaseService {
return this.delete<T>(id)
}

submit<T = any>(method: Method, url?: string | number, form?: any, config?: AxiosRequestConfig) {
return new Promise<T>((resolve, reject) => {
this.$submit<T>(method, url, form, config)
.then(({ data }) => resolve(data))
.catch((err) => reject(err))
})
}

$submit<T = any>(method: Method, param?: string | number, form?: any, config?: AxiosRequestConfig) {
$submit<T = any, F = any>(method: Method, param?: string | number, form?: F, config?: AxiosRequestConfig) {
this.beforeSubmit()
return new Promise<AxiosResponse<T>>((resolve, reject) => {
const data = hasFiles(form) ? objectToFormData(form) : form
Expand All @@ -117,6 +107,15 @@ class BaseService {
}
reject(error)
})
if (this.$resetParameter) this.removeParameters()
})
}

submit<T = any, F = any>(method: Method, url?: string | number, form?: F, config?: AxiosRequestConfig) {
return new Promise<T>((resolve, reject) => {
this.$submit<T>(method, url, form, config)
.then(({ data }) => resolve(data))
.catch((err) => reject(err))
})
}

Expand All @@ -125,14 +124,14 @@ class BaseService {
return `${url}${query}`
}

setParameters(parameters: Record<string, any>): this {
setParameters(parameters: Record<string, any>) {
Object.keys(parameters).forEach((key) => {
this.parameters[key] = parameters[key]
})
return this
}

setParameter(parameter: string, value?: any): this {
setParameter(parameter: string, value?: any) {
if (!value) {
const options: IParseOptions = Object.assign({}, this.$parsedQs, {
comma: true,
Expand All @@ -146,16 +145,16 @@ class BaseService {
return this
}

removeParameters(parameters = [] as any[]): this {
removeParameters(parameters: string[] = []) {
if (!parameters || !parameters.length) {
this.parameters = []
this.parameters = {}
} else if (isArray(parameters)) {
for (const parameter of parameters) delete this.parameters[parameter]
}
return this
}

removeParameter(parameter: string): this {
removeParameter(parameter: string) {
delete this.parameters[parameter]
return this
}
Expand All @@ -182,5 +181,3 @@ class BaseService {
validator.successful = true
}
}

export default BaseService
4 changes: 1 addition & 3 deletions src/core/Validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import { cloneDeep, get, has, omit } from 'lodash'
import { is, toCamelCase, toSnakeCase } from '../util'

class Validator {
public errors: Record<string, any>
public successful: boolean
public processing: boolean

constructor(errors: Record<string, any> = {}) {
constructor(public errors: Record<string, any> = {}) {
this.processing = false
this.successful = false
this.errors = errors
}

add(field: string, message: string, forceUpdate?: boolean) {
Expand Down
31 changes: 21 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,32 @@ import Validator from './core/Validator'
// augment typings of Vue.js
import './vue'

class AxiosHttp {
installed = false
parsedQs: IParseOptions = {
interface ModuleOptions {
resetParameter?: boolean
parsedQs: IParseOptions
errorProperty?: string | 'errors' | 'message'
}
const optionDefault: ModuleOptions = {
resetParameter: false,
parsedQs: {
comma: true,
allowDots: true,
ignoreQueryPrefix: true,
}
install(Vue: typeof _Vue, options: Record<string, any> = {}) {
},
errorProperty: 'errors',
}

class AxiosHttp {
installed = false
install(Vue: typeof _Vue, options: Partial<ModuleOptions> = {}) {
if (this.installed) return

this.installed = true
const defaultOption = merge({ parsedQs: this.parsedQs, errorProperty: 'errors' }, options)
const { $axios, errorProperty, parsedQs } = defaultOption
BaseService.$http = $axios
BaseService.$errorProperty = errorProperty || 'errors'
const { errorProperty, parsedQs, resetParameter } = merge(optionDefault, options)

BaseService.$parsedQs = parsedQs
BaseService.$resetParameter = resetParameter
BaseService.$errorProperty = errorProperty || 'errors'
Vue.mixin({
beforeCreate() {
this.$options.$errors = {} as never
Expand All @@ -41,6 +52,6 @@ class AxiosHttp {
}

export * from './util'
export type { ValidatorType }
export type { ValidatorType, ModuleOptions }
export { Validator, BaseService }
export default new AxiosHttp()