NextJs & Strapi using getStaticPaths error - javascript

Currently I am using Strapi to build out a custom API and NextJs for the front end, I am trying to use getStaticPaths to create pages based on categories. I have setup a categories collection with a relationship to my papers collection in Strapi and when using Postman to test API routes everything works great. However Next is giving me an error when I attempt to access the getStaticPaths route which should http://localhost:3000/categories/1 but instead I get the error Error: A required parameter (category) was not provided as a string in getStaticPaths for /categories/[category] currently my code looks like this below; However I am confused because I am converting it to a string which should fix the error correct? I am no pro at NextJs btw.
If I manually enter the route in either Postman or my browser it works correctly, responding with the correct json output. And the console for strapi also shows the sent request, However this does not appear in the console when Next tries to load the page I am guessing because it isn't getting that far.
How the F do I fix the above mentioned error I have been here for days and it is getting slightly annoying lol
// pages/categories/[category].js
function Category({ categories }) {
return (
<>
<h1>{categories.name}</h1>
<h2>{categories.papers.name}</h2>
</>
)
}
export async function getStaticPaths() {
const res = await fetch('http://localhost:1337/Categories')
const Categories = await res.json()
await console.log(Categories);
const paths = Categories.map((category) => ({
params: { id: category.id.toString() },
}))
return { paths, fallback: false }
}
export async function getStaticProps({ params }) {
// params contains the post `id`.
// If the route is like /posts/1, then params.id is 1
const res = await fetch(`http://localhost:1337/Categories/${params.id}`)
const categories = await res.json()
console.log(categories)
// Pass post data to the page via props
return { props: { categories } }
}
export default Category
The correct response for http://localhost:1337/Categories/**${params.id}** - which should be 1 meaning the url is http://localhost:1337/Categories/1
{
"id": 2,
"name": "English",
"published_at": "2021-10-08T10:12:08.041Z",
"created_at": "2021-10-08T10:12:04.011Z",
"updated_at": "2021-10-08T10:12:08.061Z",
"papers": [
{
"id": 1,
"name": "2020 English Studies (Testing)",
"description": "# Testing",
"PDF_link": "/uploads/2020_hsc_english_studies_98eabce6e7.pdf",
"published_at": "2021-10-08T10:14:55.816Z",
"created_at": "2021-10-08T10:12:48.714Z",
"updated_at": "2021-10-08T10:14:55.835Z",
"Media_Upload": [
{
"id": 1,
"name": "2020-hsc-english-studies.pdf",
"alternativeText": "",
"caption": "",
"width": null,
"height": null,
"formats": null,
"hash": "2020_hsc_english_studies_98eabce6e7",
"ext": ".pdf",
"mime": "application/pdf",
"size": 4959.79,
"url": "/uploads/2020_hsc_english_studies_98eabce6e7.pdf",
"previewUrl": null,
"provider": "local",
"provider_metadata": null,
"created_at": "2021-10-08T10:14:32.827Z",
"updated_at": "2021-10-08T10:14:32.847Z"
}
]
}
]
}

Keys in params should correspond to your dynamic route name. You pass id key there, but your route is called /categories/[category] so you need to pass category key.
const paths = Categories.map((category) => ({
params: { category: category.id.toString() },
}))
And in getStaticProps obviously also grab category from params.

Related

My PATCH request is showing as successful, but nothing is being updated

Trying to make a simple patch request against a single document, and the request returns
{
"acknowledged": true,
"modifiedCount": 1,
"upsertedId": null,
"upsertedCount": 0,
"matchedCount": 1
}
This is the document I am trying to update
{
"_id": "63843e60079d9cdf9c26505a",
"name": "AKG_HSD271",
"image": "images/Products/AKG_hsd271.png",
"colour": "Black",
"description": "AKG HSD271 over-ear headset",
"price": "165.99",
"startingDateAvailable": "2022-05-10T15:23:28.000Z",
"type": "Over-Ear",
"isOnSale": false,
"stock": 46,
"EndingDateAvailable": "N/A",
"manufacturer": "AKG",
"updatedAt": "2022-12-03T08:48:35.302Z"
}
This is the request body I am sending (via Postman)
{
"price": "100.99"
}
And here is the code for my route handler
router.patch('/Products/:id', (req, res) => {
console.log('/Products/'+req.params.id);
const updates = req.body;
Product.updateOne({_id: ObjectId(req.params.id)}, {$set: updates})
.then(result => {
console.log(result);
res.json(result);
})
.catch(err => {
res.status(500).send(err.message);
});
});
Can't for the love of me figure out what is going wrong and why the price field won't change, and can't find any threads that have a suggestion I haven't tried. Any ideas?
Found the problem. Including the built in json() function in express before my route handlers seemed to do the trick:
router.use(express.json())
Apparently in express, the body property does not exist on the req object unless you include the json middleware. Hope this helps others.

Post Json with axios to Strapi

I have a backend strapi-service and i try to post a JSON to it with axios. It creates the new Content with an ID, but the JSON is empty. As a response it returns null.
I am using react-js. My Code:
import axios from 'axios';
function App() {
const apiUrl = 'http://localhost:1338/api/participants'
const posting = async () => {
await axios.post(apiUrl,{
"data": {
"startStudyTime": 0,
"endStudyTime": 0,
"objectsPressed": [{}],
"searchHistory": [{}],
"connection": {
"Device": "",
"Browser": "",
"OS": ""
},
"finished": false,
"canceled": false
}
}, { headers: { 'Content-Type': 'application/json' } })
.then( response =>{
console.log('response.data:', response.data)
console.log('response.data.data:', response.data.data)
console.log('response.data.data.id:', response.data.data.id)
})
}
return (
<div className="App">
<button onClick={posting}>Submit</button>
</div>
);
}
export default App
The code runs and when I press on the submit-button, I'll always get a log, where the data has a diffrent id, but the participantLoggingData remains null, as the postman log below.
So i tried to use postman to see if anything is wrong with axios or sth:
I used the "post" call, put the Json object into the body, set the body to raw and JSON and got the following:
{
"data": {
"id": 27,
"attributes": {
"participantLoggingData": null,
"createdAt": "2022-11-07T00:23:41.759Z",
"updatedAt": "2022-11-07T00:23:41.759Z",
"publishedAt": "2022-11-07T00:23:41.759Z"
}
},
"meta": {}
}
and the json is stil null, idk...
I tried stuff like JSON.stringify() this gave me a 400 error and i tried to store the json into a container, so i can all sth like await axios.post(apiUrl, data,{ headers: { 'Content-Type': 'application/json' } }), but nothing worked.
So I looked up the strapi documentation and i couldn't find any diffrence(syntax-wise), so i guess my strapi isn't set up 100% correct. If I create a new contentType with only a Json it has the same issue. Is there a fix for it?
My strapi configs:
Under Settings/Roles/Public/Participant, all boxes are checked, so basicly everyone should be able to create, find, update and delete stuff.
My ContentType is called Participant with a JSON named "participantLoggingData"
I also have tried to use the axios.put call, but this doesnt change the object, it still remains empty :/
For json field participantLoggingData in your post request you need to send data like:
{
"data": {
"participantLoggingData": {
"startStudyTime": 0,
"endStudyTime": 0,
"objectsPressed": [{}],
"searchHistory": [{}],
"connection": {
"Device": "",
"Browser": "",
"OS": ""
},
"finished": false,
"canceled": false
}
}
}
You cannot directly pass data in data key in this case.

Discord Bot - Downloading JSON file from a website and extract certain elements of it

I'm working on a command that will automatically fetch a file from a link once a day and extract two of the elements in it and send that as a message in a channel.
My issue here is that I'm having issues actually getting the file downloaded. I've been trying several different functions to fetch the file but nothing has worked so far. I have attached one of the functions I've tried below.
async function getQuote () {
const url = "https://quotes.rest/qod?category=inspire";
const path = Path.resolve(__dirname, 'temp', 'qod.json')
const writer = fs.CreateWriteStream(path)
const response = await axios({
url,
method: 'GET',
responseType: 'stream'
})
response.data.pipe(writer)
getQuote();
return new Promise((resolve, reject) => {
writer.on('finish', resolve)
writer.on('error', reject)
})
}
fs.readFile('./temp/qod.json', 'utf8', function (err, data) {
if (err) throw err;
var obj = JSON.parse(data);
msg.channel.send(data);
})
The file I'm trying to work with here looks something like this:
{
"success": {
"total": 1
},
"contents": {
"quotes": [
{
"quote": "What you do speaks so loudly that I cannot hear what you say.",
"length": "61",
"author": "Ralph Waldo Emerson",
"tags": [
"action",
"inspire",
"leadership",
"management",
"tod"
],
"category": "inspire",
"language": "en",
"date": "2020-08-23",
"permalink": "https://theysaidso.com/quote/ralph-waldo-emerson-what-you-do-speaks-so-loudly-that-i-cannot-hear-what-you-say",
"id": "eZ0NtMPtGp8c5eQJOBfJmweF",
"background": "https://theysaidso.com/img/qod/qod-inspire.jpg",
"title": "Inspiring Quote of the day"
}
]
},
"baseurl": "https://theysaidso.com",
"copyright": {
"year": 2022,
"url": "https://theysaidso.com"
}
}
It wants to download as a json file, but when visiting the link, it is listed as a xml document.
How would I go about getting this downloaded and extracting two lines from it? If you're wondering, the two lines are the quote and author lines.
Thanks!
I copy your code and run my local machine and everythin fine.
Limitations are like mirages created by your own mind. When you realise that limitation do not exist, those around you will also feel it and allow you inside their space. - Stephen Richards
Looks like you are trying to write the result to a file and then read from the file which is not efficient. Here's a much simpler way of doing it.
async function getQuote() {
const url = "https://quotes.rest/qod?category=inspire";
const response = await axios(url);
const result = response.data;
/*
result =
{
"success": {
"total": 1
},
"contents": {
"quotes": [
{
"quote": "Limitations are like mirages created by your own mind. When you realise that limitation do not exist, those around you will also feel it and allow you inside their space. ",
"length": "171",
"author": "Stephen Richards",
"tags": [
"inspire",
"motivational",
"positive-thinking",
"self-empowerment",
"self-help",
"self-improvement",
"wealth",
"wealth-creation"
],
"category": "inspire",
"language": "en",
"date": "2020-08-24",
"permalink": "https://theysaidso.com/quote/stephen-richards-limitations-are-like-mirages-created-by-your-own-mind-when-you",
"id": "OLSVpLiSwrWplvCcFgPPiweF",
"background": "https://theysaidso.com/img/qod/qod-inspire.jpg",
"title": "Inspiring Quote of the day"
}
]
},
"baseurl": "https://theysaidso.com",
"copyright": {
"year": 2022,
"url": "https://theysaidso.com"
}
}
*/
//this is an array of quote objects
const quotes = result.contents.quotes;
//extracting first quote object from the array
const quoteObject = quotes[0];
//extracting quote text and author from quote object
const quote = quoteObject.quote;
const author = quoteObject.author;
//the >>> will make it look like a quote in discord.
console.log(`>>> ${quote}\n- ${author}`);
//send the formatted quote to the channel
msg.channel.send(`>>> ${quote}\n- ${author}`);
//if for some reason you want to save the result to a file
fs.writeFile(filePath, result, function(err) {
if (err) throw err;
console.log('Saved!');
});
}
getQuote();
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
I would suggest simply reading the quote to an object, then creating a string using interpolation and send it on the discord channel:
async function getQuote () {
const url = "https://quotes.rest/qod?category=inspire";
console.log("getQuote: Reading quote...");
// Get the response as an object
const response = await axios({
url,
method: 'GET'
})
// Use destructuring to get the quote and author
let { quote, author } = response.data.contents.quotes[0];
// Format our quote
let data = `${quote} - ${author}`;
// Add a console.log for debugging purposes..
console.log("getQuote: Sending quote:", data);
// Send the quote on the channel
msg.channel.send(data);
}
Todays quote would then look like so:
Limitations are like mirages created by your own mind. When you realise that limitation do not exist, those around you will also feel it and allow you inside their space. - Stephen Richards

Graphql - creating a schema from a generated JSON file

I'm trying to create a custom graphql schema to use on my graphql yoga server. The graphql yoga server is just a proxy to another graphql API from which I have managed to retrieve a schema from in JSON format. Here is a preview of what that schema looks like:
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
},
"mutationType": null,
"subscriptionType": null,
"types": [
{
"kind": "OBJECT",
"name": "Core",
"description": null,
"fields": [
{
"name": "_meta",
"description": null,
"args": [],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Meta",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "_linkType",
"description": null,
"args": [],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
}
],
"inputFields": null,
"interfaces": [
{
I now want to take this generated JSON schema and use it to create a graphql schema to use in my graphql yoga server. I believe the correct way to do this is by using the new GraphQLSchema method from graphql along with a root query. Here is my code attempting this:
schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: 'Query',
fields: schema.data.__schema
})
});
The above code gives me the following error:
Error: Query.mutationType field config must be an object
Not entirely sure where it's going wrong or if this is the proper approach to creating a graphql schema from generated JSON?
The JSON you have is the results of an introspection query. Unfortunately, introspection will not allow you to copy a remote schema. That's because while it does identify what fields exist in a schema, it does not tell you anything about how they should be executed. For example, based on the snippet you posted, we know the remote server exposes a _meta query that returns a Meta type -- but we don't know what code to run to resolve the value returned by the query.
Technically, it's possible to pass the results of an introspection query to buildClientSchema from the graphql/utilities module. However, the schema will not be executable, as the docs point out:
Given the result of a client running the introspection query, creates and returns a GraphQLSchema instance which can be then used with all GraphQL.js tools, but cannot be used to execute a query, as introspection does not represent the "resolver", "parse" or "serialize" functions or any other server-internal mechanisms.
If you want to create a proxy to another GraphQL endpoint, the easiest way is to use makeRemoteExecutableSchema from graphql-tools.
Here's the example based on the docs:
import { HttpLink } from 'apollo-link-http';
import fetch from 'node-fetch';
const link = new HttpLink({ uri: 'http://your-endpoint-url/graphql', fetch });
async function getRemoteSchema () {
const schema = await introspectSchema(link);
return makeRemoteExecutableSchema({
schema,
link,
});
}
The resulting schema is a GraphQLSchema object that can be used like normal:
import { GraphQLServer } from 'graphql-yoga'
async function startServer () {
const schema = await introspectSchema(link);
const executableSchema = makeRemoteExecutableSchema({
schema,
link,
});
const server = new GraphQLServer({ schema: executableSchema })
server.start()
}
startServer()
graphql-tools also allows you to stitch schemas together if you not only wanted to proxy the existing endpoint, but wanted to add on to it as well.

Query works in GraphiQL but returns empty array in Actual Code while using React Apollo

I have a simple query like this
import gql from "graphql-tag";
export const GET_TODOS_BY_PRODUCT = gql`
query getTodosByProduct(
$id: ID!
$completed: Boolean = false
$limit: Int = 100
) {
product(id: $id) {
hashtag
todos(completed: $completed, limit: $limit) {
body
}
}
}
`;
In GraphiQL, it returns results like -
{
"data": {
"product": {
"todos": [
{
"body": "Remove Custom Font from Tweet #a2k",
"product": {
"id": "1439"
},
"__typename": "Todo"
},
{
"body": "Make Site a PWA #a2k",
"product": {
"id": "1439"
},
"__typename": "Todo"
}
]
}
}
}
But while using React Apollo's Query component, it returns the hashtag properly but returns todos as an empty array [] & I can't seem to figure out what's wrong with the query.
If I fetch additional parameters from the query outside of todos then it returns them properly but only todos returns empty array [].
I am requesting it like -
<Query
query={GET_TODOS_BY_PRODUCT}
variables={{ id: state.get("selectedProduct.id") }}
>
{({ data: { product } }) => {
return <Main todos={product.todos} hashtag={product.hashtag} />;
}}
</Query>
And I can't seem to figure out why something's wrong? Any suggestions?
Thanks to #dkulkarni I found the solution. In my GraphiQL, completed was true & in Apollo, I didn't set it up so it was false.
And my product didn't have any completed equal to false so it was messing up.
Thanks again #dkulkarni I wasted 2 hours for this thing 😂

Categories