Make all api fields snake_case (#105)
Change all snake/camelCase mix and match to camelCase everywhere Fix conversion to not interfer with service interceptors Add dynamic conversion between camelCase and snake_case to services Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/105
This commit is contained in:
@ -1,5 +1,7 @@
|
||||
import axios from 'axios'
|
||||
import {reduce, replace} from 'lodash'
|
||||
import {camelCase} from 'camel-case'
|
||||
import {snakeCase} from 'snake-case'
|
||||
|
||||
let config = require('../../public/config.json')
|
||||
|
||||
@ -40,19 +42,25 @@ export default class AbstractService {
|
||||
|
||||
// Set the interceptors to process every request
|
||||
let self = this
|
||||
this.http.interceptors.request.use( (config) => {
|
||||
this.http.interceptors.request.use((config) => {
|
||||
switch (config.method) {
|
||||
case 'post':
|
||||
if(this.useUpdateInterceptor())
|
||||
config.data = JSON.stringify(self.beforeUpdate(config.data))
|
||||
if (this.useUpdateInterceptor()) {
|
||||
config.data = self.beforeUpdate(config.data)
|
||||
}
|
||||
config.data = JSON.stringify(this.modelToSnakeCase(config.data))
|
||||
break
|
||||
case 'put':
|
||||
if(this.useCreateInterceptor())
|
||||
config.data = JSON.stringify(self.beforeCreate(config.data))
|
||||
if (this.useCreateInterceptor()) {
|
||||
config.data = self.beforeCreate(config.data)
|
||||
}
|
||||
config.data = JSON.stringify(this.modelToSnakeCase(config.data))
|
||||
break
|
||||
case 'delete':
|
||||
if(this.useDeleteInterceptor())
|
||||
config.data = JSON.stringify(self.beforeDelete(config.data))
|
||||
if (this.useDeleteInterceptor()) {
|
||||
config.data = self.beforeDelete(config.data)
|
||||
}
|
||||
config.data = JSON.stringify(this.modelToSnakeCase(config.data))
|
||||
break
|
||||
}
|
||||
return config
|
||||
@ -66,7 +74,7 @@ export default class AbstractService {
|
||||
) {
|
||||
this.http.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token')
|
||||
}
|
||||
|
||||
|
||||
this.paths = {
|
||||
create: paths.create !== undefined ? paths.create : '',
|
||||
get: paths.get !== undefined ? paths.get : '',
|
||||
@ -112,7 +120,7 @@ export default class AbstractService {
|
||||
errorHandler(error) {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
|
||||
|
||||
/////////////////
|
||||
// Helper functions
|
||||
///////////////
|
||||
@ -231,6 +239,32 @@ export default class AbstractService {
|
||||
// Preprocessors
|
||||
////////////
|
||||
|
||||
/**
|
||||
* Transforms field names to camel case.
|
||||
* @param model
|
||||
* @returns {*}
|
||||
*/
|
||||
modelToCamelCase(model) {
|
||||
let parsedModel = {}
|
||||
for (const m in model) {
|
||||
parsedModel[camelCase(m)] = model[m]
|
||||
}
|
||||
return parsedModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms field names to snake case - used before making an api request.
|
||||
* @param model
|
||||
* @returns {*}
|
||||
*/
|
||||
modelToSnakeCase(model) {
|
||||
let parsedModel = {}
|
||||
for (const m in model) {
|
||||
parsedModel[snakeCase(m)] = model[m]
|
||||
}
|
||||
return parsedModel
|
||||
}
|
||||
|
||||
/**
|
||||
* Default preprocessor for get requests
|
||||
* @param model
|
||||
@ -295,12 +329,16 @@ export default class AbstractService {
|
||||
*/
|
||||
getM(url, model = {}, params = {}) {
|
||||
const cancel = this.setLoading()
|
||||
|
||||
model = this.beforeGet(model)
|
||||
return this.http.get(this.getReplacedRoute(url, model), {params: params})
|
||||
const finalUrl = this.getReplacedRoute(url, model)
|
||||
|
||||
return this.http.get(finalUrl, {params: params})
|
||||
.catch(error => {
|
||||
return this.errorHandler(error)
|
||||
})
|
||||
.then(response => {
|
||||
response.data = this.modelToCamelCase(response.data)
|
||||
return Promise.resolve(this.modelGetFactory(response.data))
|
||||
})
|
||||
.finally(() => {
|
||||
@ -325,7 +363,9 @@ export default class AbstractService {
|
||||
|
||||
const cancel = this.setLoading()
|
||||
model = this.beforeGet(model)
|
||||
return this.http.get(this.getReplacedRoute(this.paths.getAll, model), {params: params})
|
||||
const finalUrl = this.getReplacedRoute(this.paths.getAll, model)
|
||||
|
||||
return this.http.get(finalUrl, {params: params})
|
||||
.catch(error => {
|
||||
return this.errorHandler(error)
|
||||
})
|
||||
@ -338,16 +378,17 @@ export default class AbstractService {
|
||||
return this.modelGetAllFactory(entry)
|
||||
}))
|
||||
}
|
||||
if(response.data === null) {
|
||||
if (response.data === null) {
|
||||
return Promise.resolve([])
|
||||
}
|
||||
response.data = this.modelToCamelCase(response.data)
|
||||
return Promise.resolve(this.modelGetAllFactory(response.data))
|
||||
})
|
||||
.finally(() => {
|
||||
cancel()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a put request to the url specified before
|
||||
* @param model
|
||||
@ -359,18 +400,21 @@ export default class AbstractService {
|
||||
}
|
||||
|
||||
const cancel = this.setLoading()
|
||||
return this.http.put(this.getReplacedRoute(this.paths.create, model), model)
|
||||
const finalUrl = this.getReplacedRoute(this.paths.create, model)
|
||||
|
||||
return this.http.put(finalUrl, model)
|
||||
.catch(error => {
|
||||
return this.errorHandler(error)
|
||||
})
|
||||
.then(response => {
|
||||
response.data = this.modelToCamelCase(response.data)
|
||||
return Promise.resolve(this.modelCreateFactory(response.data))
|
||||
})
|
||||
.finally(() => {
|
||||
cancel()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Performs a post request to the update url
|
||||
* @param model
|
||||
@ -382,11 +426,14 @@ export default class AbstractService {
|
||||
}
|
||||
|
||||
const cancel = this.setLoading()
|
||||
return this.http.post(this.getReplacedRoute(this.paths.update, model), model)
|
||||
const finalUrl = this.getReplacedRoute(this.paths.update, model)
|
||||
|
||||
return this.http.post(finalUrl, model)
|
||||
.catch(error => {
|
||||
return this.errorHandler(error)
|
||||
})
|
||||
.then(response => {
|
||||
response.data = this.modelToCamelCase(response.data)
|
||||
return Promise.resolve(this.modelUpdateFactory(response.data))
|
||||
})
|
||||
.finally(() => {
|
||||
@ -405,11 +452,14 @@ export default class AbstractService {
|
||||
}
|
||||
|
||||
const cancel = this.setLoading()
|
||||
return this.http.delete(this.getReplacedRoute(this.paths.delete, model), model)
|
||||
const finalUrl = this.getReplacedRoute(this.paths.delete, model)
|
||||
|
||||
return this.http.delete(finalUrl, model)
|
||||
.catch(error => {
|
||||
return this.errorHandler(error)
|
||||
})
|
||||
.then(response => {
|
||||
response.data = this.modelToCamelCase(response.data)
|
||||
return Promise.resolve(response.data)
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -5,9 +5,9 @@ import {formatISO} from 'date-fns'
|
||||
export default class AttachmentService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/tasks/{task_id}/attachments',
|
||||
getAll: '/tasks/{task_id}/attachments',
|
||||
delete: '/tasks/{task_id}/attachments/{id}',
|
||||
create: '/tasks/{taskId}/attachments',
|
||||
getAll: '/tasks/{taskId}/attachments',
|
||||
delete: '/tasks/{taskId}/attachments/{id}',
|
||||
})
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ export default class AttachmentService extends AbstractService {
|
||||
|
||||
download(model) {
|
||||
this.http({
|
||||
url: '/tasks/' + model.task_id + '/attachments/' + model.id,
|
||||
url: '/tasks/' + model.taskId + '/attachments/' + model.id,
|
||||
method: 'GET',
|
||||
responseType: 'blob',
|
||||
}).then((response) => {
|
||||
|
@ -24,12 +24,12 @@ export default class LabelService extends AbstractService {
|
||||
}
|
||||
|
||||
beforeUpdate(label) {
|
||||
label.hex_color = label.hex_color.substring(1, 7)
|
||||
label.hexColor = label.hexColor.substring(1, 7)
|
||||
return label
|
||||
}
|
||||
|
||||
beforeCreate(label) {
|
||||
label.hex_color = label.hex_color.substring(1, 7)
|
||||
label.hexColor = label.hexColor.substring(1, 7)
|
||||
return label
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ export default class LabelTaskService extends AbstractService {
|
||||
super({
|
||||
create: '/tasks/{taskID}/labels',
|
||||
getAll: '/tasks/{taskID}/labels',
|
||||
delete: '/tasks/{taskID}/labels/{label_id}',
|
||||
delete: '/tasks/{taskID}/labels/{labelId}',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -5,10 +5,10 @@ import {formatISO} from 'date-fns'
|
||||
export default class ListService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
getAll: '/lists/{listID}/shares',
|
||||
get: '/lists/{listID}/shares/{id}',
|
||||
create: '/lists/{listID}/shares',
|
||||
delete: '/lists/{listID}/shares/{id}',
|
||||
getAll: '/lists/{listId}/shares',
|
||||
get: '/lists/{listId}/shares/{id}',
|
||||
create: '/lists/{listId}/shares',
|
||||
delete: '/lists/{listId}/shares/{id}',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -28,12 +28,12 @@ export default class ListService extends AbstractService {
|
||||
model.tasks = model.tasks.map(task => {
|
||||
return taskService.beforeUpdate(task)
|
||||
})
|
||||
model.hex_color = model.hex_color.substring(1, 7)
|
||||
model.hexColor = model.hexColor.substring(1, 7)
|
||||
return model
|
||||
}
|
||||
|
||||
beforeCreate(list) {
|
||||
list.hex_color = list.hex_color.substring(1, 7)
|
||||
list.hexColor = list.hexColor.substring(1, 7)
|
||||
return list
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import {formatISO} from 'date-fns'
|
||||
export default class ListUserService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
getAll: '/lists/{listID}/listusers'
|
||||
getAll: '/lists/{listId}/listusers'
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,12 @@ export default class NamespaceService extends AbstractService {
|
||||
}
|
||||
|
||||
beforeUpdate(namespace) {
|
||||
namespace.hex_color = namespace.hex_color.substring(1, 7)
|
||||
namespace.hexColor = namespace.hexColor.substring(1, 7)
|
||||
return namespace
|
||||
}
|
||||
|
||||
beforeCreate(namespace) {
|
||||
namespace.hex_color = namespace.hex_color.substring(1, 7)
|
||||
namespace.hexColor = namespace.hexColor.substring(1, 7)
|
||||
return namespace
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import {formatISO} from 'date-fns'
|
||||
export default class TaskService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/lists/{listID}',
|
||||
create: '/lists/{listId}',
|
||||
getAll: '/tasks/all',
|
||||
get: '/tasks/{id}',
|
||||
update: '/tasks/{id}',
|
||||
@ -27,8 +27,11 @@ export default class TaskService extends AbstractService {
|
||||
}
|
||||
|
||||
processModel(model) {
|
||||
// Ensure the listID is an int
|
||||
model.listID = Number(model.listID)
|
||||
|
||||
console.log(model)
|
||||
|
||||
// Ensure that listId is an int
|
||||
model.listId = Number(model.listId)
|
||||
|
||||
// Convert dates into an iso string
|
||||
model.dueDate = model.dueDate === null ? null : formatISO(new Date(model.dueDate))
|
||||
@ -79,8 +82,8 @@ export default class TaskService extends AbstractService {
|
||||
}
|
||||
|
||||
// Do the same for all related tasks
|
||||
Object.keys(model.related_tasks).forEach(relationKind => {
|
||||
model.related_tasks[relationKind] = model.related_tasks[relationKind].map(t => {
|
||||
Object.keys(model.relatedTasks).forEach(relationKind => {
|
||||
model.relatedTasks[relationKind] = model.relatedTasks[relationKind].map(t => {
|
||||
return this.processModel(t)
|
||||
})
|
||||
})
|
||||
|
@ -5,8 +5,8 @@ import {formatISO} from 'date-fns'
|
||||
export default class TaskAssigneeService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/tasks/{task_id}/assignees',
|
||||
delete: '/tasks/{task_id}/assignees/{user_id}',
|
||||
create: '/tasks/{taskId}/assignees',
|
||||
delete: '/tasks/{taskId}/assignees/{userId}',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import {formatISO} from 'date-fns'
|
||||
export default class TaskCollectionService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
getAll: '/lists/{listID}/tasks',
|
||||
getAll: '/lists/{listId}/tasks',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,11 @@ import {formatISO} from 'date-fns'
|
||||
export default class TaskCommentService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/tasks/{task_id}/comments',
|
||||
getAll: '/tasks/{task_id}/comments',
|
||||
get: '/tasks/{task_id}/comments/{id}',
|
||||
update: '/tasks/{task_id}/comments/{id}',
|
||||
delete: '/tasks/{task_id}/comments/{id}',
|
||||
create: '/tasks/{taskId}/comments',
|
||||
getAll: '/tasks/{taskId}/comments',
|
||||
get: '/tasks/{taskId}/comments/{id}',
|
||||
update: '/tasks/{taskId}/comments/{id}',
|
||||
delete: '/tasks/{taskId}/comments/{id}',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,8 @@ import {formatISO} from 'date-fns'
|
||||
export default class TaskRelationService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/tasks/{task_id}/relations',
|
||||
delete: '/tasks/{task_id}/relations',
|
||||
create: '/tasks/{taskId}/relations',
|
||||
delete: '/tasks/{taskId}/relations',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,10 @@ import {formatISO} from 'date-fns'
|
||||
export default class TeamListService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/lists/{listID}/teams',
|
||||
getAll: '/lists/{listID}/teams',
|
||||
update: '/lists/{listID}/teams/{teamID}',
|
||||
delete: '/lists/{listID}/teams/{teamID}',
|
||||
create: '/lists/{listId}/teams',
|
||||
getAll: '/lists/{listId}/teams',
|
||||
update: '/lists/{listId}/teams/{teamId}',
|
||||
delete: '/lists/{listId}/teams/{teamId}',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,8 @@ import {formatISO} from 'date-fns'
|
||||
export default class TeamMemberService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/teams/{teamID}/members',
|
||||
delete: '/teams/{teamID}/members/{id}', // "id" is the user id because we're intheriting from a normal user
|
||||
create: '/teams/{teamId}/members',
|
||||
delete: '/teams/{teamId}/members/{id}', // "id" is the user id because we're intheriting from a normal user
|
||||
});
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ export default class TeamMemberService extends AbstractService {
|
||||
}
|
||||
|
||||
beforeCreate(model) {
|
||||
model.userID = model.id // The api wants to get the user id as userID
|
||||
model.userId = model.id // The api wants to get the user id as user_ID
|
||||
model.admin = model.admin === null ? false : model.admin
|
||||
return model
|
||||
}
|
||||
|
@ -8,8 +8,8 @@ export default class TeamNamespaceService extends AbstractService {
|
||||
super({
|
||||
create: '/namespaces/{namespaceID}/teams',
|
||||
getAll: '/namespaces/{namespaceID}/teams',
|
||||
update: '/namespaces/{namespaceID}/teams/{teamID}',
|
||||
delete: '/namespaces/{namespaceID}/teams/{teamID}',
|
||||
update: '/namespaces/{namespaceID}/teams/{teamId}',
|
||||
delete: '/namespaces/{namespaceID}/teams/{teamId}',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,10 @@ import {formatISO} from 'date-fns'
|
||||
export default class UserListService extends AbstractService {
|
||||
constructor() {
|
||||
super({
|
||||
create: '/lists/{listID}/users',
|
||||
getAll: '/lists/{listID}/users',
|
||||
update: '/lists/{listID}/users/{userID}',
|
||||
delete: '/lists/{listID}/users/{userID}',
|
||||
create: '/lists/{listId}/users',
|
||||
getAll: '/lists/{listId}/users',
|
||||
update: '/lists/{listId}/users/{userId}',
|
||||
delete: '/lists/{listId}/users/{userId}',
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -8,8 +8,8 @@ export default class UserNamespaceService extends AbstractService {
|
||||
super({
|
||||
create: '/namespaces/{namespaceID}/users',
|
||||
getAll: '/namespaces/{namespaceID}/users',
|
||||
update: '/namespaces/{namespaceID}/users/{userID}',
|
||||
delete: '/namespaces/{namespaceID}/users/{userID}',
|
||||
update: '/namespaces/{namespaceID}/users/{userId}',
|
||||
delete: '/namespaces/{namespaceID}/users/{userId}',
|
||||
})
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user