Sveltekit: Can't call API from +layout.ts. Error: "Failed to parse URL from /api/..." - api

This is the code in my +layout.ts
import type { LayoutLoad } from './$types';
export const load: LayoutLoad = async () => {
const response = await fetch('/api/thumbnails', { method: 'GET' })
if (response.ok) {
return { json: await response.json() }
}
else {
console.log('There were no blog posts to get.')
// TODO: do something!
}
};
I had the exact same code in a +page.ts file (the only difference was LayoutLoad was changed to PageLoad), and it worked there. I was calling my thumbnails api and populating my page. I don't understand why it doesn't work at all in +layout. It just crashes my web app.
On top of this, LayoutLoad has an error in VsCode that reads Module '"./$types"' has no exported member 'LayoutLoad'. I don't understand why this is. Can somebody help me?

I figured it out, the answer was here: https://kit.svelte.dev/docs/load#making-fetch-requests
To get data from an external API or a +server.js handler, you can use the provided fetch function, which behaves identically to the native fetch web API with a few additional features:
Basically, in my code I had to change this line
export const load: LayoutLoad = async () => {
to this
export const load: LayoutLoad = async ({fetch}) => {
Because without that change I was using the native fetch and not sveltekit's provided fetch.
Also, I seemed to have fixed this error: Module '"./$types"' has no exported member 'LayoutLoad' by updating sveltkit to the latest version.

Related

Fresh Framework: Fetching to own api results in "URL not found"

In my "/yourPage" route, my handler is trying to fetch "/api/joke" from my local database. I get "URL not found" error. Since Fresh is server rendered, I'd like to get all the data I need when loading the first time.
This works fine when fetching after initial load (like with a button).
As per its documentation, it should work fine, and does for any API that is not in its own repository.
Any way I can make this work? Am I thinking of this the wrong way?
The fetch inside my handler:
routes/yourPage.ts
export const handler: Handlers = {
async GET(req, ctx) {
const joke = await getJokes()
return ctx.render(joke);
},
};
/routes/api/joke.ts
const JOKES = [
"Why do Java developers often wear glasses? They can't C#.",
"A SQL query walks into a bar, goes up to two tables and says “can I join you?”",
];
export const handler = (_req: Request, _ctx: HandlerContext): Response => {
const randomIndex = Math.floor(Math.random() * JOKES.length);
const body = JOKES[randomIndex];
return new Response(body);
};
Pretty old post, but this is the first StackOverflow Google result when you try to search for API calling in Fresh Framework.
I am assuming you imported inside routes/yourPage.ts the handler from /routes/api/joke.ts as this:
import { handler as getJokes } from "./api/joke.ts";
Inside routes/yourPage.ts you also have to extract the text/json from the response before using it:
export const handler: Handlers = {
async GET(_req, _ctx) {
const response = getJokes(_req, _ctx);
const jokeText = await response.text();
return _ctx.render(jokeText);
},
};
Then you can use the response in your page as:
export default function Home({ data }: PageProps) { //...
Documentation here:
https://fresh.deno.dev/docs/getting-started/fetching-data

express fetch promise will not resolve before render

I have an express route and I want to send back the result of a fetch to my pug template. I know my fetch URL works as I have checked it with postman and the data comes back as it should. I would like to store the fetch of the result to the variable called weather at the bottom of the route. My template looks for this variable to exist before adding weather to the template
I have also logged my form data to make sure the form is sending the data to my express server
I get this error in my command console when logging the return:
Promise { <pending> }
(node:18060) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'json' of undefined
I think the issue must be with my promise structure or perhaps it has to do with CORS not being enabled in my app? I'm not getting any errors and I'm hoping someone might have an answer for me??
router.post("/", async(req, res, next)=>{
console.log(req.body.selectedCity)
console.log(req.body.selectedState)
console.log(req.body.selectedZip)
var result = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${req.body.selectedCity}&units=imperial&appid=${apiKey}`)
.then(function(result) {
console.log(result.json())
})
.then((result)=>{
console.log(result.json())
res.render('index', {states:[
{
id:"none",
name:"choose"
},
{
id:"OH",
name:"Ohio"
},
{
id:"UT",
name:"Utah"
},
{
id:"VT",
name:"Vermont"
},
{
id:"VA",
name:"Virginia"
},
{
id:"WA",
name:"Washington"
},
{
id:"WV",
name:"West Virginia"
},
{
id:"WI",
name:"Wisconsin"
},
{
id:"WY",
name:"Wyoming"
}
],weather:result})
})
});
You have an uncorrect syntax on async/await.
You do not use .then in async/await but you just await the promise and store the result in a variable.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
var result = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${req.body.selectedCity}&units=imperial&appid=${apiKey}`)
.then(function(result) {
console.log(result.json())
})
.then((result)=>{
console.log(result.json())
res.render [...]
Becomes:
const result = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${req.body.selectedCity}&units=imperial&appid=${apiKey}`);
console.log(result.json())
res.render [...]
Try and avoid var as it may lead to unexpected behavior.
Try using axios as a fetch library, it's much cleaner than fetch.
https://www.npmjs.com/package/axios
This way it's just const result = await axios.get([...]
This should be structured this way instead -
fetch('url')
.then(result=>result.json)
.then(result=>res.render())
You should also remove async keyword from the callback function provide to router.post.

Fetch API not showing json data

I am relatively new to react native and trying to build an app and am using the fetch API to try and get a json file from the api. My problem is that it seems to not have any response when i make the calls to the api.
Here is the function that contains the fetch calls
export const fetchData = url => {
return async dispatch => {
dispatch(fetchingRequest());
try {
let response = await fetch(url);
let json = response.json();
console.log(json);
dispatch(fetchingSuccess(json));
} catch (error) {
dispatch(fetchingFailure(error));
}
};
};
The console.log(json) does not come up when I check in the chrome debugger.
if the url is needed for reference, I used https://randomuser.me/api/.
This function is called in one of my other components. I am also using redux and redux-thunk to store the data in the JSON file.
Edited in:
I believe the problem to be the function is not being executed when called.
I import the function and all the redux actions like this
import {
fetchingSuccess,
fetchingRequest,
fetchingFailure,
fetchData
} from "../data/redux/actions/appActions.js";
The fetchData function is then called in a _onPress function that is written like this
_onPress = () => {
let url = "https://randomuser.me/api/?results=10"
fetchData(url);
console.log("should have fetched");
};
in the console the expected output should be the
JSON contents or error // logged when fetchData is called
should have fetched // logged from _onPress
but instead the console outputs
should have fetched // logged from _onPress
The problem is that response.json() returns a promise, so when you do:
let json = response.json();
Without the await then the log after is still a promise, in order for this to work you must add the await in front of the response.json():
let json = await response.json();
The json() method of the Body mixin takes a Response stream and reads
it to completion. It returns a promise that resolves with the result
of parsing the body text as JSON.

using async data in my page using nuxtjs

I have read using async data or fetch is a better approach in pages in nuxtjs instead of using the created hook.
I am struggling to get my code to work though
I had the following (Which does work fine)
created () {
this.$store.dispatch('cases/getCase', this.$route.params.caseId );
},
But how would I change that to work with the async method instead please, and be able to return more than one state when I need to.
I tried the following
async asyncData ({ params }) {
const thisCase = await this.$store.dispatch('cases/getCase', this.$route.params.caseId );
// constant thisUser
return { thisCase }
// return { thisCase, thisUser}
},
but this generated an error
undefined is not an object (evaluating 'this.$store')
Can anyone tell me what I am doing wrong please
Thanks
this not available in asyncData/fetch. It is even stated in docs in special orange warning.
You do NOT have access of the component instance through this inside
asyncData because it is called before initiating the component.
And again as said in docs
method receives the context object as the first argument, you can use
it to fetch some data and return the component data.
Context is where from you should be getting your store. Here docs for context.
So your code would be
async asyncData ({ params, store }) {
const thisCase = await store.dispatch('cases/getCase', params.caseId )
return { thisCase }
},

How Do I use a node.js module with Next.js?

Do I need to use express with next.js?
Im trying to add this code into a next.js application. ( from npm module example code: pdf2json )
let fs = require('fs');
var PDFParser = require("pdf2json");
let pdfParser = new PDFParser(this,1);
pdfParser.on("pdfParser_dataError", errData =>
console.error(errData.parserError) );
pdfParser.on("pdfParser_dataReady", pdfData => {
fs.writeFile("./sometxt.txt", pdfParser.getRawTextContent());
pdfParser.loadPDF("./page1.pdf");
You can require it conditionally by testing if it is the server:
static async getInitialProps({isServer}){
var fs;
if(isServer){
fs=require('fs');
//and do what ever you want
}
}
and dot not forgot to tell webpack to do not send the module to the client side by changing package.json like so:
"browser": {
"fs": false
}
unless it can produce errors.
The thing that's probably biting you is that most of your code must work on both the client and the server. You can write server-only code by creating a getInitialProps() method and checking to see if it's passed in a opts.req - if so, you know the code is running server-side and you can hit the filesystem:
import React from 'react'
const doServerSideStuff = () => {
let fs = require('fs');
var PDFParser = require("pdf2json");
let pdfParser = new PDFParser(this,1);
pdfParser.on("pdfParser_dataError", errData =>
console.error(errData.parserError) );
pdfParser.on("pdfParser_dataReady", pdfData => {
fs.writeFile("./sometxt.txt", pdfParser.getRawTextContent());
pdfParser.loadPDF("./page1.pdf");
}
export default class extends React.Component {
static async getInitialProps ({ req }) {
if (req) {
doServerSideStuff();
}
return {};
}
render () {
return <div> Hello World </div>
}
}
This isn't really a complete example yet, you should really make doServerSideStuff() async (or return a promise) and then await it in getInitialProps, and eventually return props that represent the result of the parsing & saving. Also, handle fs.writeFile errors. But, hopefully it's enough to get you going in the right direction.
See the docs for some more info on this.
Or you could just use Express like you suggested. There is a good tutorial and example code that should help you get started if you decide to go that route.