Next.js ApolloError Only absolute URLs are supported - next.js

I followed this video tutorial
https://youtu.be/JUEw1yHJ8Ao?t=715
at this time i have an error Only absolute URLs are supported
Server Error
Error: Only absolute URLs are supported
This error happened while generating the page. Any console logs will be displayed in the terminal window.
my code:
import { ApolloClient, InMemoryCache, createHttpLink, gql } from '#apollo/client'
import { setContext } from '#apollo/client/link/context'
export async function getServerSideProps() {
const httpLink = createHttpLink({
uri: 'https://api.github.com/graphql',
})
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`,
}
}
})
const apolloClient = new ApolloClient({
uri: authLink.concat(httpLink),
cache: new InMemoryCache()
});
const { data } = await apolloClient.query({
query: gql`
{
user(login: "mygithublogin") {
avatarUrl(size: 36)
gists(privacy: PUBLIC, last: 10) {
totalCount
nodes {
createdAt
url
stargazerCount
}
}
login
}
}
`
})
console.log(data);
return {
props: {
}
};
}
help please 🙋‍♂️

Related

How to create a function that returns new session format with extra key value pair

I am using NextJS with NextAuth with google and email providers. Unfortunately, the session returns only few fields that does not include userId of the user from the database.
I created however a function that I intend to use with every getServerSideProps request. The function returns the following:
{
user: {
name: 'daniel sas',
email: 'emailofuser#gmail.com',
image: 'https://lh3.gooleusercontent.com/a/AEdFTp6r44ZwqcfJORNnuYtbVv_LYbab-wv5Uyxk=s96-c',
userId: 'clbcpc0hi0002sb1wsiea3q5d'
},
expires: '2022-12-17T20:18:52.580Z'
}
The problem is I am getting an error that does not allow me to pass the props in the page:
Error: Your `getServerSideProps` function did not return an object. Did you forget to add a `return`?
In the function I get the user by the email, and attach the userId.
import { getSession } from "next-auth/react";
import prisma from './prisma'
// This function get the email and returns a new session object that includes
// the userId
export const requireAuthentication = async context => {
const session = await getSession(context);
const errorOrUserNotFound = () => {
return {
redirect: {
destination: '/signup',
permanent: false
}
}
}
// If there is no user or there is an error ret to signup page
if (!session) {
errorOrUserNotFound();
}
// If the user is not found return same redirect to signup
else {
try {
const user = await prisma.user.findUnique({where: { email: session.user.email }});
if (!user) return errorOrUserNotFound();
// Must return a new session here that contains the userId...
else {
const newSession = {
user: {
...session.user,
userId: user.id
},
expires: session.expires
};
console.log(newSession);
return {
props: {
session: newSession
}
}
}
}
catch (error) {
if (error) {
console.log(error);
}
}
}
}
The react component looks like this. In the getServerSideProps i return the await function. The problem is that when I log the prop in the serverside, I get the following:
{
props: { session: { user: [Object], expires: '2022-12-17T20:18:52.580Z' } }
}
However, if i log the props in the clientside, I get an empty object...
//Clientside compoen
import { getSession } from "next-auth/react"
import { Fragment, useState } from "react";
import { requireAuthentication } from "../../lib/requireAuthentication";
import CreateListModal from "./CreateListModal";
const DashboardPage = props => {
const [loading, setloading] = useState(false);
console.log(props);
return (
<section className="border-4 border-orange-800 max-w-5xl mx-auto">
<CreateListModal userId={props.userId} loading={loading} setloading={setloading} />
</section>
)
}
export const getServerSideProps = async context => {
const session = await getSession(context);
const reqAuth = await requireAuthentication(context);
console.log(reqAuth);
return reqAuth
}
export default DashboardPage;

Graphql subscriptions not working on serverless environment

I'm using graphql yoga and apollo client in my next app. Graphql yoga suggests this example for apollo client. link It works fine on non-serverless environment but when I deploy on vercel, subscriptions not working. I have tried checking for if it's running on browser but didn't do much. Here's my current apollo client
import {
ApolloLink,
Observable,
ApolloClient,
InMemoryCache,
} from '#apollo/client/core'
import { split } from '#apollo/client/link/core'
import { HttpLink } from '#apollo/client/link/http'
import { print, getOperationAST } from 'graphql'
import { setContext } from '#apollo/client/link/context'
import { getCookie } from 'cookies-next'
const isBrowser = typeof window !== 'undefined'
const token = getCookie('token')
class SSELink extends ApolloLink {
constructor() {
super()
}
request(operation) {
const url = new URL(`${process.env.NEXT_PUBLIC_APP_BASE_URL}/api/graphql`)
url.searchParams.append('query', print(operation.query))
if (operation.operationName) {
url.searchParams.append(
'operationName',
JSON.stringify(operation.operationName)
)
}
if (operation.variables) {
url.searchParams.append('variables', JSON.stringify(operation.variables))
}
if (operation.extensions) {
url.searchParams.append(
'extensions',
JSON.stringify(operation.extensions)
)
}
return new Observable((sink) => {
const eventsource = new EventSource(url.toString(), this.options)
eventsource.onmessage = function (event) {
const data = JSON.parse(event.data)
sink.next(data)
if (eventsource.readyState === 2) {
sink.complete()
}
}
eventsource.onerror = function (error) {
sink.error(error)
}
return () => eventsource.close()
})
}
}
const uri = `${process.env.NEXT_PUBLIC_APP_BASE_URL}/api/graphql`
const sseLink = isBrowser ? new SSELink({ uri }) : null
const httpLink = new HttpLink({ uri })
const authLink = setContext((_, { headers }) => {
return {
headers: {
...headers,
...(isBrowser && token && { authorization: `Bearer ${token}` }),
},
}
})
const link = isBrowser
? split(
({ query, operationName }) => {
const definition = getOperationAST(query, operationName)
return (
definition?.kind === 'OperationDefinition' &&
definition.operation === 'subscription'
)
},
sseLink,
httpLink
)
: authLink.concat(httpLink)
export default new ApolloClient({
ssrMode: !isBrowser,
link,
cache: new InMemoryCache(),
})

Nextjs getting single product from woocommerce

new in graphQL and nextjs, why do i keep getting this error
Error: Cannot find module 'react'
Require stack:
- /home/monster/app/nextpress/node_modules/#apollo/client/react/context/context.cjs
- /home/monster/app/nextpress/node_modules/#apollo/client/react/react.cjs
i already checked the package it exit in my node, if use on other page it work but once i put in this code, it have this error.
// product/[slug].tsx
import React from 'react'
import { ApolloClient, InMemoryCache, gql } from '#apollo/client'
export default function Product({ product }) {
console.log('product:', product)
return (
<main>
<div>
<h1>Product Page</h1>
</div>
</main>
)
}
export async function getStaticProps(context) {
const client = new ApolloClient({
uri: 'http://localhost:3080/graphql/',
cache: new InMemoryCache(),
})
const {
params: { slug },
} = context
const { data } = await client.query({
query: gql`
query Product($slug: ID!) {
product(id: $slug, idType: SLUG) {
id
name
}
}
`,
variables: { slug },
})
return {
props: {
product: data?.product || {},
},
revalidate: 1,
}
}
export async function getStaticPaths() {
const client = new ApolloClient({
uri: 'http://localhost:3080/graphql/',
cache: new InMemoryCache(),
})
const { data } = await client.query({
query: gql`
query Products {
products(first: 10) {
nodes {
id
slug
}
}
}
`,
})
const pathsData = []
data?.products?.nodes.map((product) => {
if (!isEmpty(product?.slug)) {
pathsData.push({ params: { slug: product?.slug } })
}
})
return {
paths: pathsData,
fallback: false,
}
}
what wrong with it ? if anyone can help me pinpoint my mistake, will be greatful and am i doing right to get single product data like this or there is a better way ? thanks :D

How do you do server side rendering with nextjs [id].js in headless wordpress? fetch single page using graphql from Wordpress. like service/[id].js

I have a nextjs project that is using apollo graphql to fetch data from the backend. I am trying to render my page using server side rendering. But I am currently using graphql apollo hooks to fetch my data from the backend, and the react hooks prevents me from calling my backend inside of the getServerSideProps.
Create and fetch single page using graphql from Wordpress with clean URLs like services/[id].js
N.B: Warning Show ( Error: Response not successful: Received status code 500)
import {
gql,
ApolloClient,
InMemoryCache
} from "#apollo/client";
export const client = new ApolloClient({
uri: 'https://.........../graphql',
cache: new InMemoryCache()
});
const serviceDetail = (serviceOutput) => {
return (
<div>
{serviceOutput.serviceTitle}
{serviceOutput.serviceContent}
</div>
)
}
export const getServerSideProps = async (context) => {
const result = await client.query({
query: gql`
query serData($id: id!) {
HomePage: pageBy(uri: "https://......./home/") {
aboutSection {
serviceSec(id: $id) {
id
serviceTitle
serviceContent
serviceImage {
sourceUrl
}
}
}
}
}
`,
variables: {
id: context.params.id
}
})
return {
props: {
serviceOutput: result.data.HomePage.aboutSection.serviceSec;
},
};
}
export default serviceDetail;
i am not an expert, but as far i have used. you cannot use Apollo together with next js fetching method(ssg,ssr,isr).
Apollo runs queries on client side, and can be used with useQuery and useLazyQuery. while next js fetching is completely different.
I will demonstrate 2 ways here.
-- Using Apollo --
const FETCH_ALL = gql`
query MyQuery($first: Int!, $after: String) {
posts(first: $first, after: $after) {
edges {
node {
title
}
}
}
}
`;
export default function LoadMoreList() {
const { data } = useQuery(FETCH_ALL, {
variables: { first: 5, after: null },
notifyOnNetworkStatusChange: true,
});
return (
<>
<div>
{postdata.map((node, index) => {
{
return (
<div key={index}>
<h1>{node?.node?.title}</h1>
</div>
);
}
})}
</div>
</>
)}
=== using fetch and getStaticProps ==
--File1 (this is a fetch function, to which you pass your queries and variables)
async function fetchAPI(query, { variables } = {}) {
const headers = { "Content-Type": "application/json" };
const res = await fetch(process.env.WP_API, {
method: "POST",
headers,
body: JSON.stringify({ query, variables }),
});
const json = await res.json();
if (json.errors) {
console.log(json.errors);
throw new Error("Failed to fetch API");
}
return json.data;
}
export default fetchAPI;
-- File2 (this is a file that contains your query)
import fetchAPI from "./fetching";
export async function homeheadposts() {
const data = await fetchAPI(
`
query homeheadposts {
posts(first: 7) {
edges {
node {
id
slug
title
featuredImage {
node {
sourceUrl
}
}
excerpt(format: RAW)
}
}
}
}
`
);
return data?.posts;
}
-- File3 (place this function , where you wanna call and use the data, )
export async function getStaticProps() {
const latestPosts = await homeheadposts();
return {
props: { latestPosts },
};
}
export default function CallingData({ latestPosts }) {
console.log(latestPosts);
return <h1>hello</h1>;
}

How to extract query from `getServerSideProps` to separate helper file?

I've got several pages that I want to call a query inside of getServerSideProps to request the currentUser.
What I have currently is something like this:
import { NextPageContext } from 'next';
import { withAuth } from 'hoc/withAuth';
import { addApolloState, initializeApollo } from 'lib/apolloClient';
import { MeDocument } from 'generated/types';
import nookies from 'nookies';
import Profile from 'components/Profile';
const ProfilePage: React.FC = () => <Profile />;
export const getServerSideProps = async (
context: NextPageContext
): Promise<any> => {
// withAuth(context);
const client = initializeApollo();
const { my_token } = nookies.get(context);
await client.query({
query: MeDocument,
context: {
headers: {
authorization: my_token ? `Bearer ${my_token}` : '',
},
},
});
return addApolloState(client, { props: {} });
};
export default ProfilePage;
This works, and I can verify in my Apollo devtools that the cache is being updated with the User.
When I try to move the Apollo initialization and query in to a separate file, the cache is never updated for some reason.
Inside of a withAuth.tsx file, I had something like this:
import { NextPageContext } from 'next';
import { addApolloState, initializeApollo } from 'lib/apolloClient';
import { MeDocument } from 'generated/types';
import nookies from 'nookies';
export const withAuth = async (context: any,) => {
const client = initializeApollo();
const { gc_token } = nookies.get(context);
await client.query({
query: MeDocument,
context: {
headers: {
authorization: gc_token ? `Bearer ${gc_token}` : '',
},
},
});
return addApolloState(client, { props: {} });
};
With this, all I have to do is call withAuth() in the getServerSideProps. There are no errors, however the cache doesn't update.
How can I extract that code to a separate file correctly?
Thanks to #juliomalves in the comments, I simply forgot to return the withAuth function!
Here's how it looks now:
pages/index.tsx
export const getServerSideProps = async (
context: NextPageContext
): Promise<any> => await withAuth(context);
withAuth.tsx
/* eslint-disable #typescript-eslint/explicit-module-boundary-types */
import { getSession } from 'next-auth/client';
import redirectToLogin from 'helpers/redirectToLogin';
import { addApolloState, initializeApollo } from 'lib/apolloClient';
import { MeDocument } from 'generated/types';
import nookies from 'nookies';
export const withAuth = async (context: any) => {
const session = await getSession(context);
const isUser = !!session?.user;
// no authenticated session
if (!isUser) redirectToLogin();
const client = initializeApollo();
const { token } = nookies.get(context);
await client.query({
query: MeDocument,
context: {
headers: {
authorization: token ? `Bearer ${token}` : '',
},
},
});
return addApolloState(client, { props: {} });
};

Resources