getServerSideProps and mysql (RowDataPacket) - next.js

I'd like to do server side rendering with Next.js using the getServerSideProps method like explained in the docs.
The data should come from a database, so I'm using the mysql package. This results in the following error:
Error serializing `.assertions[0]` returned from `getServerSideProps` in "/assertion". Reason: `object` ("[object Object]") cannot be serialized as JSON. Please only return JSON serializable data types.
I think the reason for this is, because the query method from mysql returns special objects (RowDataPacket). The result that I'd like to pass to getServerSideProps looks like this when logged:
[ RowDataPacket { id: 1, title: 'Test' } ]
I can fix this error by wrapping the result with JSON.parse(JSON.stringify(result)) but this seems very odd to me.
So, my simple question is: How to use mysql.query and getServerSideProps correctly?
Or might this be an issue that should be addressed by Next.js?
Thank you

I've run into this issue myself. When I had the issue it wasn't related to MySQL. The problem is getServerSideProps() expects you to return a "JSON serializable data type" which basically means a Plain ol' JavaScript Object (POJO).
To fix it, simply create a new POJO to return. A few ways you can go are:
// using spread operator to create new object
const plainData = {
...queryResult
}
// recreating the object with plucked props
const plainData = {
title: queryResult.title,
content: queryResult.content
}
// data conversion (wax-on wax-off)
const plainData = JSON.parse(JSON.stringify(queryResult))
Your specific data is in an array so your simplest solution is the wax-on wax-off since it will support arrays. Otherwise you've got to map over it.
why tho?
You can see your object has RowDataPacket attached to it. This means it's an instance of RowDataPacket and NextJS doesn't allow any instances unless it strictly equals the Object.prototype (see related code)
This seems weird, but they have already described why it's necessary in a Github Issue. TL;DR dates cause issues client-side when the page hydrates.

Related

Fetch error on Office Script (Excel on web)

I am trying to call an external API from an Excel on web. However, I am stuck on trying to get the result from the fetch call. I am even using the Office doc example to make sure
From an Excel, click on Automate to create a new script
async function main(workbook: ExcelScript.Workbook): Promise<void> {
let fetchResult = await fetch('https://jsonplaceholder.typicode.com/todos/1');
let json = await fetchResult.json();
}
I keep on getting the following message (at the fetchResult.json() call)
"Office Scripts cannot infer the data type of this variable or inferring it might result in unexpected errors. Please annotate the type of the variable to avoid this error. You can also use the Quick fix option provided in the editor to auto fill the type based on the usage. Quick Fix can be accessed by right clicking on the variable name and selecting Quick Fix link."
When running the Chrome inspector, the API request seems to be on hold "CAUTION: request is not finished yet"
PS: I am not the Office administrator and is not reachable right now, but hoping this is not a problem with my user or the Office account configuration
Any idea what the problem might be?
Thanks!
"any" types not being allowed in OfficeScript is by design. We think any types in general can lead to developer errors. I understand it can be hard to declare types – but these days most popular APIs provide you the interface (or d.ts) that you can use.
Secondly, there are tools such as https://quicktype.io/typescript where you can type in your sample JSON and it’ll give you the full interface which you can then declare in your code using interface keyword.
See this code for example: https://github.com/sumurthy/officescripts-projects/blob/main/API%20Calls/APICall.ts
You don’t need to declare all properties – only the ones you’ll use.
It’s more up-front work – but in the end the quality is better.
Adding an interface definition for the expected JSON type fixed the problem for me.
interface Todo {
userId: number;
id: number;
title: string;
completed: boolean
}
async function main(workbook: ExcelScript.Workbook): Promise<void> {
let fetchResult = await fetch('https://jsonplaceholder.typicode.com/todos/1');
let json: Todo = await fetchResult.json();
console.log(json);
}
You may need to define a different interface if the Web API you're calling returns different data structure.

Displaying data from Firebase on load of Ionic app

I'm a beginner in Ionic and Firebase. To learn using ionic+firebase, I'm writing a RandomQuote app to fetch a random entry from Firebase. A reload() method is called when I click a reload button, and the random quote is displayed as expected.
However, I also want the quote to display when the app is loaded, i.e., before I click the reload button. I call the reload() method in the constructor but it doesn't work. I have tried to search for answers on the web but cannot find anything that I could understand. Not sure if I'm searching the wrong keywords or in the wrong domains.
The following is the reload() method that I put in my FirebaseProvider class and called from my home.ts:
reload(){
this.afd.list('/quoteList/').valueChanges().subscribe(
data => {
this.oneQuote = data[Math.floor(Math.random() * data.length)];
}
)
return this.oneQuote;
}
Can anyone give me some hints? Or any pointer to useful books / materials for beginners will also be highly appreciated. Thank you very much.
Data is loaded from Firebase asynchronously. This means that by the time your return statement runs this.oneQuote doesn't have a value yet.
This is easiest to say by placing a few log statements around your code:
console.log("Before subscribing");
this.afd.list('/quoteList/').valueChanges().subscribe(
data => {
console.log("Got data");
}
)
console.log("After subscribing");
When you run this code, the output is:
Before subscribing
After subscribing
Got data
This is probably not what you expected. But it completely explains why your return statement doesn't return the data: that data hasn't been loaded yet.
So you need to make sure your code that needs the data runs after the data has been loaded. There are two common ways to do this:
By moving the code into the callback
By returning a promise/subscription/observable
Moving the code into the callback is easiest: when the console.log("Got data") statement runs in the code above, the data is guaranteed to be available. So if you move the code that requires the data into that place, it can use the data without problems.
Returning a promise/subscription/observable is a slightly trickier to understand, but nicer way to doing the same. Now instead of moving the code-that-needs-data into the callback, you'll return "something" out of the callback that exposes the data when it is available. In the case of AngularFire the easiest way to do that is to return the actual observable itself:
return this.afd.list('/quoteList/').valueChanges();
Now the code that needs the quotes can just subscribe to the return value and update the UI:
reload().subscribe(data => {
this.oneQuote = data[Math.floor(Math.random() * data.length)];
}
A final note: having a reload() method sounds like an antipattern. The subscription will already be called whenever the data in the quoteList changes. There is no need to call reload() for that.

Does AngularFire2's database.list hold a reference or actually grab data?

I'm following along the with the basic AngularFire2 docs, and the general format seems to be:
const items = af.database.list('/items');
// to get a key, check the Example app below
items.update('key-of-some-data', { size: newSize });
My confusion is that in the source code, it seems as though calling database.list() grabs all the data at the listed url (line 114 here)
Can anyone help clarify how that works? If it does indeed grab all the data, is there a better way of getting a reference without doing that? Or should I just reference each particular URL individually?
Thanks!
When you create an AngularFire2 list, it holds an internal Firebase ref - accessible via the list's public $ref property.
The list is an Observable - which serves as the interface for reading from the database - and includes some additional methods for writing to the database: push, update and remove.
In the code in your question, you are only calling the update method and are not subscribing to the observable, so no data is loaded from the database into memory:
const items = af.database.list('/items');
// to get a key, check the Example app below
items.update('key-of-some-data', { size: newSize });
It's only when a subscription to the observable is made that listeners for value and the child_... events are added to the ref and the list builds and maintains an internal array that's emitted via the observable. So if you are only calling the methods that write to the database, it won't be loading any data.
The AngularFire2 object is implemented in a similar manner.

How to manipulate the data pointed by a cursor before render it

everybody.
I have a doubt in this portion of my system: I want to encrypt some messages from users to the database and decrypt them when showing back to the users (that's just for privacy reasons). Since I couldn't find any native encrypt/decrypt library or even a better solution, then I am using the "crypto-js" (https://code.google.com/p/crypto-js/), and it's working well so far. The problem is: when the user write a message I encrypt it and save it at the database. But when I retrieve that message from the database using the "find" method in a Template Helper (using the reactive computation idea to approach the desired "Live HTML"), what I get is just a cursor that will be used to render the message in my HTML. As you can see, the message is shown without be decrypted.
I was thinking in "fetch" the data from the cursor, run the decrypt function in a "for loop" over all messages, but that's too inefficient.
I was wondering if someone know how may I manipulate the data from the cursor before it be render, then I'll be able to decrypt each message on the fly.
Really thanks for your attention and sorry any bother.
You could use a transform function. The transform is passed as the cursor is used so it only runs on each document as it is used:
YourCollection.find({}, {transform:function(doc) {
var encrypted = doc.field1;
doc.field1 = decrypt(encrypted)
return doc;
});
So now each field1 would be decrypted (on the web browser). Just before it was used. If you use .fetch() you would get all the decrypted data too.
You didn't posted the related code here, but I assume you have done something like this:
Template.yourTemplate.yourHelper = function(){
return yourCollection.find({});
}
The thing is your are returning the data to the helper, in form of cursor, which is perfectly acceptable in general. But as you are storing encrypted messages in collection, each message is rendered as it is without performing decryption.
So, try to fetch an array instead of cursor using find().fetch() which gives the array equivalent of your cursor. Something like :
Template.yourTemplate.yourHelper = function(){
var msg_arr = yourCollection.find({}).fetch(); // gives array instead of cursor.
msg_arr.forEach( function( msg ){
// traverse through each element of array and
// perform decryption.
});
}
I just had a talk at the #meteor IRC channel and some ideas came out. And I thought that this one is the best solution for my case:
{{#each messages}}
{{decrypt}}
{{/each}}
As helpers get the data from the context, the helper "decrypt" got the actual "message" in the loop as a "this" object. Then, I did the decryption and returned the message in plain text.
It works pretty well, further it is called reactively and make use of the cursor (that is update dynamically if data changes during the exhibition).
Thanks everybody whom helped me.

How do I return an Array from grails / jdo to Flex

this seems really simple but I haven't gotten this to work. I am building my app with grails on google app engine. This pretty much requires you to use JDO.
I am making an HTTP call from flex to my app. The action that I am calling on the grails end looks like so
def returnShowsByDate = {
def query = persistenceManager.newQuery( Show )
def showInstanceList = query.execute()
return (List<Show>) showInstanceList
}
I have tried just returning "hello from grails" and that works just fine. I have alos tried the following
return showInstanceList
the JDO docs say the query.execute() returns a collection. Why I cant just return that to Flex I have no clue.
Any thoughts?
after playing around with this some more I was able to get a result event back by have grails convert the object to JSON or XML
wish I could just return a damn ArrayList. That Would be better but oh well.
OK so I found the fundamental problem and I am answering my own question.
I noticed that I got a fault event when using the JSON stuff too, so I launched a browser and went to the list view that grails provided. Then I requested data from Flex and it worked.
Long story short persistenceManager was null if I didn't go to the html view first so in my method that is being called from Flex I added the following.
if(!persistenceManager)
def persistenceManager
all works well now.

Resources