How to create a route with Strapi 4? - api

I am trying to set a route. I followed a tutorial.
Everything is happening in a folder inside the api folder.
Route folder contains post.js file :
'use strict';
/**
* post router.
*/
const { createCoreRouter } = require('#strapi/strapi').factories;
module.exports = createCoreRouter('api::post.post', {
method: 'GET',
path: '/api/posts/:id/comments',
handler: 'posts.comments'
});
Controllers folder contains an other post.js file :
'use strict';
/**
* post controller
*/
const { createCoreController } = require('#strapi/strapi').factories;
module.exports = createCoreController('api::post.post', ({strapi}) => ({
comments: async (ctx) => {
return "Hello"
}
}));
Finally, when I tested URL : http://localhost:1337/api/posts/:id/comments; I have :
{
"data": null,
"error": {
"status": 404,
"name": "NotFoundError",
"message": "Not Found",
"details": {}
}
}
What did I do wrong ? Is something missing ?

I think the url should be like http://localhost:1337/api/posts/1/comments and not http://localhost:1337/api/posts/:id/comments. Means url should provide actual id instead of ':id'. Try it.

Related

Express validator fails to validate data correctly

Hello i am using the latest version of express-validator to validate my requests body, the problem is when i am using notEmpty() or not().isEmpty() it always shows an error with prsonalized message i putted "text field is required" even when the text field is not empty
this is my validator.js file
import { body } from "express-validator";
export const checkPost = () => {
return [
body("text")
.trim()
.notEmpty()
.withMessage("text field is required")
];
};
this is my route.js :
router.post("/", checkPost(), uploadImg, createPost);
and this is my controller.js
export const createPost = async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.json({ errors: errors.array() });
} ....
this is the response i get :
{
"errors": [
{
"value": "",
"msg": "text field is required",
"param": "text",
"location": "body"
}
]
}
Can anyone help me please ?
You will need a body parser middleware set up before handling the body fields. For instance, try setting your route like this (if you're sending the body as json):
router.post("/", express.json(), checkPost(), uploadImg, createPost);
After many hours of search i found that the express-validator middleware should be called after the usage of multer so changing my route this way solved the problem
router.post("/",uploadImg, checkPost(), createPost);

How to access object on Vue front end from axios proxy

I have a locally hosted mongodb database with mongoose, express, axios, and a Vue front end. Right now I'm trying to access a single object from an exported array, but I'm missing the mark and getting "undefined" as the result.
vue.config.js:
module.exports = {
devServer: {
proxy: 'http://localhost:3000',
}
}
here's the front end Vue script meant to use the objects:
import axios from 'axios';
export default {
name: 'Game',
data () {
return {
pages: [],
currentPage: {},
pageTitle: "",
pageText: "",
options: [],
}
},
created () {
this.getPages();
},
methods: {
async getPages() {
try {
let res = await axios.get('/api/pages');
this.pages = res.data;
console.log(this.pages);
this.currentPage = this.pages[0];
console.log(this.currentPage);
return true;
} catch (error) {
console.log(error);
}
},
my "get" endpoint in pages.js:
router.get('/', async (req, res) => {
try {
let pages = await Page.find();
res.send({pages: pages}); //send result of search for pages as list of pages called "pages"
} catch (error) {
console.log(error);
res.sendStatus(500); //500 = server could not fulfill request
}
});
the route in server.js:
const pages = require('./routes/pages');
app.use('/api/pages', pages);
app.listen(3000, () => console.log('Server listening on port 3000!'));
module.exports = app;
and here's the console output, with the "pages" object from vue's data property and the "currentPage" that's supposed to be at pages[0] (printed to console in earlier example):
I can access the api at 'localhost:3000/api/pages' just fine, but how do I break into that array and access the first page object? I want to get an object from the list axios fetches from mongoose, then hold that object in a variable so I can access it's properties. The whole "pages > [[Target]] > pages > [ ]" is part of the problem I'm sure, but I don't know what to tell the code to open it.
Whoops! I realized my mistake. In pages.js I should have sent "res.send(pages);" After a whole couple days too XD

NuxtJS Apollo response is null and Missing field warnings

I'm trying to make graphql query calls using apollo on NuxtJS and I'm getting the following error.
WARN Missing field description in { 11:29:49
"__typename": "EduExp"
}
WARN Missing field componentName in { 11:29:49
"__typename": "EduExp"
}
{ 11:29:49
data: null,
loading: false,
networkStatus: 7,
stale: true
}
Here is my query
fragment IntroCardFields on IntroCard {
legend
profile {
title
url
}
introList
description {
json
}
componentName
}
query getPage($pageId: String!) {
page(id: $pageId) {
slug
name
componentsCollection {
items {
...IntroCardFields
}
}
}
}
I'm using it like this in vuex
async fetchPageData({ commit, state }) {
const apollo = this.app.apolloProvider.defaultClient;
const pageData = [];
const res = await apollo.query({
query: getPage,
variables: {
pageId: '2S3x7vBmaB2FhTUbNXWvwY',
},
});
console.log(res);
},
When I try this query without parameters on a api tool like postman or insomnia works well.
I don't get it why not working on Nuxt

How do I get only a defined amount of attributes of my Express API with a browser?

Let me give an example: By accessing the following page we have access to all JSON code: https://jsonplaceholder.typicode.com/todos
But if I want I can retrieve just the first 6 elements of the JSON by accessing the following: https://jsonplaceholder.typicode.com/todos?_limit=6
I want to do this same thing with my Express code that I am accessing with http://localhost:3100
When I try http://localhost:3100?_limit=6 it brings the entire JSON file, I don't understand why. How can I fix this? I want the browser to be able to limit the amount that it gets from the API.
Here is my Express code:
const express = require("express");
const app = express();
const projects = [
{ project: "Challenges_jschallenger.com" },
{ project: "Using-Studio-Ghilis-API-With-JS-Only" },
{ project: "my-portfolio-next" },
{ project: "Youtube-Navbar-2021" },
{ project: "Mana-raWozonWebsite" },
{ project: "Movies-Website" },
{ project: "Add-Remove-Mark-and-Mark-off-With-ReactJS" },
{ project: "My-Portfolio" },
{ project: "Github_Explorer" },
{ project: "MestreALMO.github.io" },
{ project: "Tests-With-useState-useEffect-useRef" },
{ project: "Tic-Tac-Toe-React-in-JS" },
{ project: "ReactJS-with-TypeScript-Template" },
{ project: "Retractable-Accordion" },
];
app.get("/", function (req, res) {
res.send(projects);
});
app.listen(3100);
You need to extract the query from the express request. Also the correct way to respond with a json object would be to call the json method.
app.get("/", (req, res) => {
const { limit } = req.query
res.json(projects.slice(0, limit))
})
For it to work you would have to make the request to http://localhost:3100/?limit=6

Ant Design Pro dynamic menu not showing up

Following the instruction at https://pro.ant.design/docs/router-and-nav#fetch-menu-from-server
I changed file BasicLayout.tsx as below. Menu is not showing up.
...
const testMenu = [{name:"login", path:"/user/login"}] as any;
const [menuData, setMenuData] = useState([]);
useEffect(() => {
if (dispatch) {
dispatch({
type: 'user/fetchCurrent',
});
}
setMenuData(testMenu)
}, []);
...
menuDataRender={()=>menuData}
...
I was doing same as you and failed as you. Document is still wrong.
And I found getting menu from server has a lot of bug with ant design pro v4. (Maybe I did not know)
So my final decision is to display all menu from /config/config.ts as designed initially.
And get only authorization information from server and set only authority to show only logged in user related menu.
So my solution (not correct answer) is:
I referenced this link. https://umijs.org/docs/runtime-config#patchroutes-routes-
Created file /src/app.tsx and inserted code as follow:
interface PathAndIdsModel {
path: string;
ids: string[];
}
const setAuthority = (routes: any, pathAndIds: PathAndIdsModel[]) => {
routes.forEach((route: any) => {
const found = pathAndIds.find((item) => item.path === route.path);
if (found) {
// eslint-disable-next-line no-param-reassign
route.authority = [...new Set([...(route.authority || []), ...found.ids])];
}
if (route.routes) {
setAuthority(route.routes, pathAndIds);
}
});
};
async function patchRoutes({ routes }) {
const response = await fetch(`https://localhost:44357/authorities`);
const pathAndIds = await response.json();
setAuthority(routes, pathAndIds);
}
export { patchRoutes };
Inserted following code to ASP.Net Core Controller:
[HttpGet("/authorities")]
public IEnumerable<object> Authorities()
{
return new[]
{
new {
Path = "/dashboard/analysis",
Ids = new [] { "user", "admin", },
},
new {
Path = "/dashboard/monitor",
Ids = new [] { "user", "admin", },
},
new {
Path = "/dashboard/workplace",
Ids = new [] { "admin", },
},
new {
Path = "/form/basic-form",
Ids = new [] { "admin", },
},
};
}
/dashboard/workplace and /form/basic-form page will be hidden if logged in as user, but shows if logged in as admin.
I tried to get full routes from server, but failed because of async call, UmiJS did not wait until fetching from server and setting new routes.
So when I fetched routes from server and changed routes, UmiJS already converted icon and component of old routes and my new routes never changed.