-
Notifications
You must be signed in to change notification settings - Fork 0
API Implementation
Concerning the API communication implementation, a 'data layer' was created. All the API implementation methods, adapter, mock data and constants are under /data
of the project scaffolding.
The API implementation is done around a singleton, the API Adapter (can be found in /data/api/index.js
).
The instanceof this object has:
-
Client - The axios client that creates all the API connection using HTTP standards and returning
Promises
(can be found indata/api/api.client.js
) -
Endpoints - Where all the endpoints are defined with 2 parameters,
url
andmethod
, to be used on the API Client (can be found indata/api/api.endpoints.js
) -
Services - A service is a set of functions to serve a certain domain of the application (
documents
,billing
...). Each function is responsible for one API connection (can be found indata/api/services
)
In order to keep the consistency of keys across the application (every key on store is on camelCase
), the API models file was created to map all the keys naming was created on data/api/api.models.js
.
There are 2 types of models in the API Models file:
- DOMAIN_REQUEST_KEYS - Transforms the keys received from the API into the application's keys
- DOMAIN_RESPONSE_KEYS - Transforms the keys from the application into the ones the API need
A more efficient way used on more complex objects, is to use a function to transpile the whole object and map the keys. Example:
export const parseCompaniesDetailsResponse = function (object) {
return {
'name': object.name,
'address': object.address,
'date': object.date,
'taxClassification': object.tax_classification,
'entityType': object.entity_type,
'businessType': object.business_type,
'stateFormation': object.state_formation,
'contact': {
'name': object.contact.name,
'phone': object.contact.phone,
'email': object.contact.email
},
'agent': {
'name': object.agent.name,
'address': object.agent.address
}
}
}
Each endpoint must have the name of the function that will be invoked as key. The url
and method
will be used by Axios to create the connection.
The base URL is defined depending on the env:
let baseUrl
if (getEnv().match(/^(development|testing)$/)) {
baseUrl = apiConstants.default.DEV_BASE_URL
} else {
baseUrl = getDomain()
}
This allows the API Client to always make requests to the current URL on production and to http://localhost:3001/vapi
on development.
Example:
fetchUserData: {
url: '/profile',
method: 'get'
}
This mean that a certain function inside a service will be named fetchUserData
. The connection to API will be done using BASE_URL/profile
and the method will be a GET
.
The service will be implemented on the data/api/services/api.auth.js
and looks like this:
/**
* Fetched the userData from the API
* @param {any} [axiosInstance=client]
* @returns {Promise}
*/
fetchUserData (axiosInstance = client) {
return axiosInstance[endpoints.fetchUserData.method](endpoints.fetchUserData.url, {})
.then((response) => {
response.data = _.mapKeys(response.data, (value, key) => {
return USER_RESPONSE_KEYS[key]
})
return Promise.resolve(response.data)
}).catch((error) => {
return Promise.reject(error)
})
}
Every time a request or response is done, the lodash mapKeys
function should be ran with the required model.
After the request / response is done, a chain of Promises is activated.
All the needed endpoints by now for the application to behave as intended are mocked except the initial request, fetchUserData
. All the mocked endpoints are implemented using fake Promises with setTimeout
.
Example:
/**
* Cancel User's subscription plan
* @param {any} [axiosInstance=client]
* @returns {Promise}
*/
cancelPlan (axiosInstance = client) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 2500)
})
}
For new endpoints implementation, just change the fake Promise to a Axios instance API call. Check the example using the fetchUserData
service:
Mock
fetchUserData (axiosInstance = client) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const response = _.mapKeys(userDataMock, (value, key) => {
return USER_RESPONSE_KEYS[key]
})
resolve(response)
}, 1000)
})
}
Final
fetchUserData (axiosInstance = client) {
return axiosInstance[endpoints.fetchUserData.method](endpoints.fetchUserData.url, {})
.then((response) => {
response.data = _.mapKeys(response.data, (value, key) => {
return USER_RESPONSE_KEYS[key]
})
return Promise.resolve(response.data)
}).catch((error) => {
return Promise.reject(error)
})
}
By now, all the Documents & Account Details API services are already being called. For future reference, there is only 2 ways to correctly call this services:
- Actions - The API call request answer will be used to manipulate something on store
- Components - The API call request answer doesn't matter to the application's store and the service can be directly invoked inside a component
- Vue Router - Routing
- Vuex - State management
- Vue Form - Form Handling
- Axios - API communication