Преобразуйте все идентификаторы MirageJS в целые числа
MirageJS предоставляет все идентификаторы моделей в виде строк. Наш бэкэнд использует целые числа, которые удобны для сортировки и так далее. После прочтения MirageJS не поддерживает целочисленные идентификаторы из коробки. Из разговоров, которые я читал, лучшим решением было бы преобразовать идентификаторы в сериализатор.
Output:
{
id: "1",
title: "Some title",
otherValue: "Some other value"
}
Но я хочу:
Expected Output:
{
id: 1,
title: "Some title",
otherValue: "Some other value"
}
Я действительно хочу преобразовать ВСЕ идентификаторы. Это будет включать вложенные объекты и сериализованные идентификаторы.
3 ответа
Я думаю, вы сможете использовать для этого собственный IdentityManager. Вот пример REPL. (Примечание: REPL находится в стадии разработки + в настоящее время работает только в Chrome).
Вот код:
import { Server, Model } from "miragejs";
class IntegerIDManager {
constructor() {
this.ids = new Set();
this.nextId = 1;
}
// Returns a new unused unique identifier.
fetch() {
let id = this.nextId++;
this.ids.add(id);
return id;
}
// Registers an identifier as used. Must throw if identifier is already used.
set(id) {
if (this.ids.has(id)) {
throw new Error('ID ' + id + 'has already been used.');
}
this.ids.add(id);
}
// Resets all used identifiers to unused.
reset() {
this.ids.clear();
}
}
export default new Server({
identityManagers: {
application: IntegerIDManager,
},
models: {
user: Model,
},
seeds(server) {
server.createList("user", 3);
},
routes() {
this.resource("user");
},
});
Когда я делаю запрос GET для / пользователей с этим сервером, я получаю обратно целые идентификаторы.
Мое решение - пройти данные и рекурсивно преобразовать все идентификаторы. Работает очень хорошо.
У меня есть ряд других требований, например удаление data
ключ и встраивание или сериализация идентификаторов.
const ApplicationSerializer = Serializer.extend({
root: true,
serialize(resource, request) {
// required to serializedIds
// handle removing root key
const json = Serializer.prototype.serialize.apply(this, arguments)
const root = resource.models
? this.keyForCollection(resource.modelName)
: this.keyForModel(resource.modelName)
const keyedItem = json[root]
// convert single string id to integer
const idToInt = id => Number(id)
// convert array of ids to integers
const idsToInt = ids => ids.map(id => idToInt(id))
// check if the data being passed is a collection or model
const isCollection = data => Array.isArray(data)
// check if data should be traversed
const shouldTraverse = entry =>
Array.isArray(entry) || entry instanceof Object
// check if the entry is an id
const isIdKey = key => key === 'id'
// check for serialized Ids
// don't be stupid and create an array of values with a key like `arachnIds`
const isIdArray = (key, value) =>
key.slice(key.length - 3, key.length) === 'Ids' && Array.isArray(value)
// traverse the passed model and update Ids where required, keeping other entries as is
const traverseModel = model =>
Object.entries(model).reduce(
(a, c) =>
isIdKey(c[0])
? // convert id to int
{ ...a, [c[0]]: idToInt(c[1]) }
: // convert id array to int
isIdArray(c[0], c[1])
? { ...a, [c[0]]: idsToInt(c[1]) }
: // traverse nested entries
shouldTraverse(c[1])
? { ...a, [c[0]]: applyFuncToModels(c[1]) }
: // keep regular entries
{ ...a, [c[0]]: c[1] },
{}
)
// start traversal of data
const applyFuncToModels = data =>
isCollection(data)
? data.map(model =>
// confirm we're working with a model, and not a value
model instance of Object ? traverseModel(model) : model)
: traverseModel(data)
return applyFuncToModels(keyedItem)
}
})
Мне также пришлось решить эту проблему (скрестив пальцы, чтобы это было включено в библиотеку), и мой вариант использования проще, чем первый ответ.
function convertIdsToNumbers(o) {
Object.keys(o).forEach((k) => {
const v = o[k]
if (Array.isArray(v) || v instanceof Object) convertIdsToNumbers(v)
if (k === 'id' || /.*Id$/.test(k)) {
o[k] = Number(v)
}
})
}
const ApplicationSerializer = RestSerializer.extend({
root: false,
embed: true,
serialize(object, request) {
let json = Serializer.prototype.serialize.apply(this, arguments)
convertIdsToNumbers(json)
return {
status: request.status,
payload: json,
}
},
})