@hosoft/restful-api-framework
Version:
Base framework of the headless cms HoServer provided by http://helloreact.cn
260 lines (232 loc) • 8.16 kB
JavaScript
/**
* HoServer API Server Ver 2.0
* Copyright http://hos.helloreact.cn
*
* create: 2018/11/18
**/
const _ = require('lodash')
const { Api, Dictionary } = require('../../../models')
const { BaseHelper } = require('../../../base/helpers')
const { ErrorCodes } = require('../../../base')
/**
* system api services
*/
class ApiService {
/**
* get API list
*/
async getApiList(args, getAll) {
let allApis = await BaseHelper.getContainer().getRouteList(!getAll, getAll)
if (args.category_name !== undefined) {
allApis = allApis.filter((api) => api.category_name === args.category_name)
}
if (args.method) {
allApis = allApis.filter((api) => args.method.indexOf(api.method) > -1)
}
if (args.dis_name) {
allApis = allApis.filter((api) => api.dis_name.indexOf(args.dis_name) > -1)
}
if (args.path) {
allApis = allApis.filter((api) => api.path.indexOf(args.path) > -1)
}
if (args.description) {
allApis = allApis.filter((api) => api.description && api.description.indexOf(args.description) > -1)
}
allApis = _.sortBy(allApis, ['type', 'main_cat', 'second_cat'])
let preMainCat = {}
for (const api of allApis) {
if (api.main_cat !== preMainCat.main_cat) {
preMainCat = api
preMainCat.count = 1
} else {
preMainCat.count++
}
}
const page = args.page || 1
const pageSize = args.page_size || 30
const result = []
const start = (page - 1) * pageSize
const end = Math.min((page - 1) * pageSize + pageSize, allApis.length)
for (let i = start; i < end; i++) {
// api count to display in admin site
if (i === start && allApis[i].count === undefined) {
for (let j = start - 1; j >= 0; j--) {
if (allApis[j].count) {
allApis[i].count = allApis[j].count
break
}
}
}
const api = allApis[i]
if (args.select_all) {
result.push(api)
} else {
const simpleApi = { ...api }
delete simpleApi.in_params
delete simpleApi.out_fields
delete simpleApi.input_example
delete simpleApi.output_example
result.push(simpleApi)
}
}
return {
list: result,
pagination: {
total: allApis.length,
pageSize: pageSize,
current: page,
pages: parseInt(allApis / pageSize)
}
}
}
/**
* get api detail
* @param id
* @returns {Promise<void>}
*/
async getApiDetailt(id) {
return BaseHelper.getContainer().getRouteById(id)
}
/**
* update api,only the fields which allow to modify were updated
*/
async updateApi(id, apiInfo) {
const api = await BaseHelper.getContainer().getRouteById(id)
if (!api) {
return Promise.reject({ message: `Api not found: ${id}`, code: ErrorCodes.GENERAL_ERR_PARAM })
}
const existRecord = await Api.findOne({ id }, { lean: false }, { __v: 0 })
const apiEditableFields = BaseHelper.getContainer().getApiEditableFields()
for (const field of apiEditableFields) {
if (apiInfo[field] !== undefined) {
api[field] = apiInfo[field]
if (existRecord) {
existRecord[field] = apiInfo[field]
}
}
}
// persis
try {
if (!existRecord) {
await Api.create({
id: id,
path: api.path,
method: api.method,
...apiInfo
})
} else {
await existRecord.save()
}
} catch (e) {
logger.error('update api failed: ', e)
}
// next time when get Api will auto generate
delete api.main_cat
return 'success'
}
/**
* get system dict categories
*/
async getDictCategories() {
const categories = await Dictionary.find({}, { distinct: 'category_name' })
return categories.map((c) => (c && typeof c === 'object' ? c.category_name : c)) // compatible with mysql
}
/**
* modify category name for service, model, api
*/
async setSysCategoryName(args) {
const { key, value } = args
const dictItem = await Dictionary.nativeModel.findOne({ name: 'sys_category' })
if (!dictItem) {
const newRecord = await Dictionary.create({
values: [
{
key: key,
value: value,
order: 1,
enabled: 1
}
],
name: 'sys_category',
dis_name: tf('sysCategory'),
category_name: tf('sysDictionary'),
created_at: Date.now(),
updated_at: Date.now()
})
return newRecord.id
}
const existItem = dictItem.values.find((v) => v.key === key)
if (existItem) {
existItem.value = value
existItem.enabled = true
} else {
const maxOrder = _.reduce(dictItem.values, (max, r) => Math.max(max, r.order || 0), 0)
dictItem.values.push({
key: key,
value: value,
order: maxOrder + 1,
enabled: 1
})
}
dictItem.changed('values', true)
await dictItem.save()
await BaseHelper.clearCache('Dictionary', 'sys_category')
return 'success'
}
/**
* get service list
*/
async getServiceList(args) {
const serviceList = await BaseHelper.getContainer().getAllServices()
const categoryNameDict = await BaseHelper.getSystemDict('sys_category')
let allServices = []
for (const key in serviceList) {
const service = serviceList[key]
const funcList = Object.getPrototypeOf(service.instance)
const funcNames = Object.getOwnPropertyNames(funcList).filter((f) => f !== 'constructor')
if (service.category_name.indexOf('default/') < 0) {
allServices.push({
name: service.name + 'Service',
description: service.description,
category_name: service.category_name,
category_disname: categoryNameDict[service.category_name],
file: service.file,
functions: funcNames
})
}
}
allServices = _.sortBy(allServices, ['category_name', 'name'])
return {
list: allServices,
pagination: {
total: allServices.length,
pageSize: allServices.length,
current: 1,
pages: 1
}
}
}
/**
* fill category name
*/
async fillCategoryInfo(dataList) {
if (!(dataList && dataList instanceof Array)) {
return
}
const categoryNameDict = await BaseHelper.getSystemDict('sys_category')
for (const model of dataList) {
const modelObj = model._doc || model
if (modelObj.category_name === undefined) {
modelObj.category_name = '_default'
modelObj.category_disname = tf('defaultCategory')
} else {
const disName = categoryNameDict[modelObj.category_name]
if (disName) {
modelObj.category_disname = disName
}
}
}
}
/// /////////// private functions /////////////
}
module.exports = new ApiService()