System Information
- Strapi Version: 4.0.2
- Operating System: Win10
- Database: PostgreSQL
Basically I’m rewriting my backend (Strapi) to work with v.4 and PostgreSQL (in v.3 I worked with MongoDB). In v.3 I defined a user API, which contained the following router, controller and services:
// api/user/config/routes.json
{
"routes": [
{
"method": "PUT",
"path": "/user/upload/avatar",
"handler": "User.uploadAvatar",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/user/upload/cover",
"handler": "User.uploadCover",
"config": {
"policies": []
}
},
{
"method": "PUT",
"path": "/user/update",
"handler": "User.updateUser",
"config": {
"policies": []
}
}
]
}
// api/user/controllers/User.js
const { parseMultipartData, sanitizeEntity } = require('strapi-utils');
const _ = require('lodash');
const { POINTS, SOCKET_TYPES } = require('../../../utils/settings')
module.exports = {
async uploadAvatar(ctx) {
let entity
const userId = ctx.state.user.id
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
entity = await strapi.services.user.updateUser(userId, {}, {files})
} else {
ctx.request.body.user = ctx.state.user.id;
entity = await strapi.services.user.updateUser(userId, ctx.request.body);
}
return sanitizeEntity(entity, { model: strapi.models.user });
},
async uploadCover(ctx) {
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
} else {
ctx.request.body.user = ctx.state.user.id;
}
return ctx.state.user
},
async updateUser(ctx) {
const userId = ctx.state.user.id
let entity
let points = ctx.state.user.points
switch (ctx.request.body.type) {
// ...lots of logics here
// in some cases calls to a service called points, to update user points - await strapi.services.points.updateUserPoints(userId, points)
}
return {success: true, user: entity}
}
}
const mergeSMProfileArrays = (incoming, existing) => {//...}
// api/user/services/user.js
module.exports = {
updateUser: async (id, data) => {
return await strapi.query('user', 'users-permissions').update({id}, data)
}
}
In v.3 that all worked just fine. Now I tried to change it to match all the new v.4 structure. I didn’t find anything regarding updating the user info in the docs. So I tried the following - first I created directory user in the api section. Then inside I created directories controllers, routes, services.
These are my router, user controller and user services:
//api/user/routes/router.js
module.exports = {
routes: [
{
method: "PUT",
path: "/user/upload/avatar",
handler: "user.uploadAvatar",
config: {
"policies": []
}
},
{
method: "PUT",
path: "/user/upload/cover",
handler: "user.uploadCover",
config: {
policies: []
}
},
{
method: "PUT",
path: "/user/update",
handler: "user.updateUser",
config: {
policies: []
}
}
]
}
//api/user/controllers/user.js
const { createCoreController } = require('@strapi/strapi').factories;
const { parseMultipartData, sanitizeEntity } = require('@strapi/utils');
const _ = require('lodash');
const { POINTS, SOCKET_TYPES } = require('../../../utils/settings')
module.exports = createCoreController('api::user.user', ({ strapi }) => ({
async uploadAvatar(ctx) {
let entity
const userId = ctx.state.user.id
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
entity = await strapi.services.user.updateUser(userId, {}, {files})
entity = await this.updateUser(userId, {}, {files})
} else {
ctx.request.body.user = ctx.state.user.id;
entity = await this.updateUser(userId, ctx.request.body);
}
return sanitizeEntity(entity, { model: strapi.models.user });*/
},
async uploadCover(ctx) {
if (ctx.is('multipart')) {
const { data, files } = parseMultipartData(ctx);
} else {
ctx.request.body.user = ctx.state.user.id;
}
return ctx.state.user
},
async updateUser(ctx) {
const userId = ctx.state.user.id
let entity
let points = ctx.state.user.points
switch (ctx.request.body.type) {
// same logic as above
return {success: true, user: entity}
}
}))
//api/user/services/user.js
const { createCoreService } = require('@strapi/strapi').factories;
module.exports = createCoreService('api::user.user', ({ strapi }) => ({
async updateUser(id, data) {
return await strapi.db.query('plugin::user-permissions.user').update({
where: {id},
data
})
}
}))
And my server crashed. I’m getting the following error:
error: Cannot read properties of undefined (reading 'kind')
TypeError: Cannot read properties of undefined (reading 'kind')
at Object.isSingleType (C:\work\Web\my-project\backend\node_modules\@strapi\utils\lib\content-types.js:90:25)
at createController (C:\work\Web\my-project\backend\node_modules\@strapi\strapi\lib\core-api\controller\index.js:36:20)
at C:\work\Web\my-project\backend\node_modules\@strapi\strapi\lib\factories.js:11:28
at Object.get (C:\work\Web\my-project\backend\node_modules\@strapi\strapi\lib\core\registries\controllers.js:37:61)
at Object.get [as api::user.user] (C:\work\Web\my-project\backend\node_modules\@strapi\strapi\lib\core\registries\controllers.js:55:25)
at C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:4967:32
at baseForOwn (C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:3032:24)
at Function.mapKeys (C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:13430:7)
at removeNamespacedKeys (C:\work\Web\my-project\backend\node_modules\@strapi\strapi\lib\core\domain\module\index.js:11:12)
at Object.get controllers [as controllers] (C:\work\Web\my-project\backend\node_modules\@strapi\strapi\lib\core\domain\module\index.js:103:14)
at C:\work\Web\my-project\backend\node_modules\@strapi\plugin-users-permissions\server\services\users-permissions.js:152:28
at C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:3585:27
at C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:4967:15
at baseForOwn (C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:3032:24)
at C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:4936:18
at baseMap (C:\work\Web\my-project\backend\node_modules\lodash\lodash.js:3584:7)
Even with the entire content of the methods commented out I’m still getting this error. Only when the controller/user.js and routes/router.js files are completely removed - the server is able to start.
So what am I doing wrong here? How do I enable the end user to upload avatars and update their profiles?