Authenticating ok w/SupaBase
I have two very similar api functions user() and events()
Netlify finds and runs user() ok, but returns a 400 on events() – right after succeeding multiple times w/user() – Everything works fine in dev, and most of my other functions work fine in a Netlify deploy…
Nothing shows up in the Netlify log so it makes me think that it’s not getting past the GraphQL server (?)
Odd…
How do I get more insight into why this call is failing?
users.sdl.ts
export const schema = gql`
type User {
id: String!
email: String!
customer: Customer
customerId: String
business: Business
businessId: String
owner: Business
ownerId: String
purchases: [BusinessPurchase]!
attendees: [Attendee]!
events: [Event]!
canPurchase: Boolean!
created_at: DateTime!
updated_at: DateTime!
}
type Query {
user: User
}
input CreateUserInput {
email: String!
customerId: String
exployeeId: String
ownerId: String
purchaserId: String
canPurchase: Boolean!
created_at: DateTime!
updated_at: DateTime!
}
input UpdateUserInput {
email: String
customerId: String
exployeeId: String
ownerId: String
purchaserId: String
canPurchase: Boolean
created_at: DateTime
updated_at: DateTime
}
`;
users.ts
import type { Prisma } from "@prisma/client";
import type { ResolverArgs, BeforeResolverSpecType } from "@redwoodjs/api";
const stringify = require('json-stringify-safe');
import { context } from '@redwoodjs/api'
import { logger } from 'src/lib/logger'
import { thenDebug } from 'src/lib/thenables'
import { db } from "src/lib/db";
import { requireAuth } from "src/lib/auth";
// Used when the environment variable REDWOOD_SECURE_SERVICES=1
export const beforeResolver = (rules: BeforeResolverSpecType) => {
rules.add(requireAuth);
};
export const user = () => {
if (context?.currentUser?.sub) {
return db.user
.findUnique({
where: { id: context?.currentUser?.sub }
})
.then(thenDebug('user'))
} else {
return Promise.resolve(null)
}
};
export const User = {
customer: (_obj, { root }: ResolverArgs<ReturnType<typeof User>>) =>
db.user.findUnique({ where: { id: root.id } }).customer(),
exployee: (_obj, { root }: ResolverArgs<ReturnType<typeof User>>) =>
db.user.findUnique({ where: { id: root.id } }).business(),
owner: (_obj, { root }: ResolverArgs<ReturnType<typeof User>>) =>
db.user.findUnique({ where: { id: root.id } }).owner(),
purchaser: (_obj, { root }: ResolverArgs<ReturnType<typeof User>>) =>
db.user.findUnique({ where: { id: root.id } }).purchases(),
attendees: (_obj, { root }: ResolverArgs<ReturnType<typeof User>>) =>
db.user.findUnique({ where: { id: root.id } }).attendees(),
events: (_obj, { root }: ResolverArgs<ReturnType<typeof User>>) =>
db.user.findUnique({ where: { id: root.id } }).events(),
};
events.sdl.ts
export const schema = gql`
type Event {
id: String!
business: Business!
businessId: String!
planner: User!
plannerId: String!
imageStore: ImageStore
imageStoreId: String
name: String
description: String
attendees: [Attendee]!
guests: [Guest]!
images: [Image]!
questions: [Question]!
start: DateTime!
stop: DateTime!
hasVaxxifi: Boolean!
hasVaccess: Boolean!
created_at: DateTime!
updated_at: DateTime!
}
type Query {
events: [Event]!
event(id: String): Event
}
input CreateEventInput {
name: String!
description: String
start: DateTime
stop: DateTime
}
input UpdateEventInput {
name: String
description: String
hasVaccess: Boolean
start: DateTime
stop: DateTime
}
type Mutation {
deleteEvent(id: String!): String
createEvent(input: CreateEventInput): Event
updateEvent(id: String!, input: UpdateEventInput): Event
}
`;
events.ts
import type { Prisma } from "@prisma/client";
import type { ResolverArgs, BeforeResolverSpecType } from "@redwoodjs/api";
const stringify = require('json-stringify-safe');
import { context } from '@redwoodjs/api'
import { logger } from 'src/lib/logger'
import { thenDebug } from 'src/lib/thenables'
import { nanoid } from 'nanoid'
// https://www.prisma.io/docs/reference/api-reference/prisma-client-reference
import { db } from "src/lib/db";
import { requireAuth } from "src/lib/auth";
// Used when the environment variable REDWOOD_SECURE_SERVICES=1
export const beforeResolver = (rules: BeforeResolverSpecType) => {
rules.add(requireAuth);
};
export const Event = {
business: (_obj, { root }: ResolverArgs<ReturnType<typeof Event>>) =>
db.event.findUnique({ where: { id: root.id } }).business(),
planner: (_obj, { root }: ResolverArgs<ReturnType<typeof Event>>) =>
db.event.findUnique({ where: { id: root.id } }).planner(),
imageStore: (_obj, { root }: ResolverArgs<ReturnType<typeof Event>>) =>
db.event.findUnique({ where: { id: root.id } }).imageStore(),
attendees: (_obj, { root }: ResolverArgs<ReturnType<typeof Event>>) =>
db.event.findUnique({ where: { id: root.id } }).attendees(),
guests: (_obj, { root }: ResolverArgs<ReturnType<typeof Event>>) =>
db.event.findUnique({ where: { id: root.id } }).guests(),
images: (_obj, { root }: ResolverArgs<ReturnType<typeof Event>>) =>
db.event.findUnique({ where: { id: root.id } }).images(),
questions: (_obj, { root }: ResolverArgs<ReturnType<typeof Event>>) =>
db.event.findUnique({ where: { id: root.id } }).questions(),
};
export const events = () => {
try {
if (context?.currentUser?.sub) {
return db.event.findMany({
where: { plannerId: context?.currentUser?.sub }
})
.then(thenDebug(`db.event.findMany`))
} else {
return Promise.resolve([])
}
} catch (err) {
console.error(`events ~ err`, err)
}
};
export const event = ({ id }) => {
return db.event.findUnique({
where: { id }
})
.then(thenDebug(`db.event.findUnique`));
};
export const createEvent = async ({ input }) => {
if (context?.currentUser?.sub) {
const newEventId = nanoid()
const newImageStoreId = nanoid()
const newS3Bucket = nanoid()
logger.debug(`createEvent id: ${newEventId}, input:${stringify(input, null, 2)}`)
const me = await db.user.findUnique({
where: { id: context?.currentUser?.sub }
})
// create an event with it's imageStore
return await db.event.create({
data: {
name: input.name,
id: newEventId,
plannerId: me.id,
businessId: me.businessId,
imageStore: {
create: {
id: newImageStoreId,
s3Bucket: newS3Bucket
}
}
}
})
.then(thenDebug(`db.event.create`))
.catch(logger.error)
} else {
return Promise.resolve(null)
}
};
export const updateEvent = async ({ id, input }) => {
if (context?.currentUser?.sub) {
const updated = await db.event.updateMany({
where: { id, plannerId: context?.currentUser?.sub },
data: input
})
.then(thenDebug(`db.event.updateMany`))
.catch(logger.error)
return db.event.findFirst({
where: { id, plannerId: context?.currentUser?.sub }
})
.then(thenDebug(`.event.findFirst`))
.catch(logger.error)
} else {
return Promise.resolve(null)
}
};
export const deleteEvent = async ({ id }) => {
if (context?.currentUser?.sub) {
return await db.event.delete({
where: { id }
})
// .then(thenDebug(`db.event.delete`))
.catch(logger.error)
} else {
return Promise.resolve(null)
}
};
netlify.toml
[build]
command = "yarn rw deploy netlify"
publish = "web/dist"
functions = "api/dist/functions"
[dev]
command = "yarn rw dev"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
GetUserDataCell.tsx
export type UserProfileProps = {
id: string,
email: string
customer: {
customerPK: string
}
canPurchase: boolean
owner: {
businessPK: string
hasPlanner: boolean
hasVaxxifi: boolean
events: {
hasVaxxifi: boolean
hasVaccess: boolean
}
}
}
export const beforeQuery = (props) => {
const variables = { ...props }
return { variables, fetchPolicy: 'no-cache' }
}
export const QUERY = gql`
query GetUserDataQuery {
user {
id
email
customer {
customerPK
}
canPurchase
owner {
businessPK
hasPlanner
hasVaxxifi
events {
hasVaxxifi
hasVaccess
}
}
}
}
`
export const Loading = () => null
export const Empty = () => null
export const Failure = ({ error }) => (
<div style={{ color: 'red' }}>Error: {error?.message}</div>
)
export const Success = ({ user, variables }) => {
console.debug('user', user)
if (variables.exfiltrate) {
setTimeout(() => variables.exfiltrate(user))
}
return null
}
GetEventListCell
export const beforeQuery = (props) => {
const variables = { ...props }
return { variables, fetchPolicy: 'no-cache' }
}
export const QUERY = gql`
query GetEventListQuery {
events {
id
name
description
start
stop
hasVaxxifi
hasVaccess
created_at
updated_at
}
}
`
export const Loading = () => null
export const Empty = () => null
export const Failure = ({ error }) => (
<div style={{ color: 'red' }}>Error: {error?.message}</div>
)
export const Success = ({ events, variables }) => {
console.debug(`GetEventListQuery ~ events`, events)
if (variables.exfiltrate) {
setTimeout(() => variables.exfiltrate(events))
}
return null
}