Has anyone used this GraphQL Laravel Library before?
I managed to get it working on my local machine.
But when I deploy it to Heroku, I keep getting an error that my schema is not loaded.
How do I resolve this?
Here's a screenshot of my local GraphQL environment:
You may find the Heroku GraphQL Playground here.
I can't find much documentation on deploying GraphQL in PHP/Laravel online.
Thank you in advance for your help.
Edit:
Here is my schema:
"A datetime string with format `Y-m-d H:i:s`, e.g. `2018-05-23 13:43:32`."
scalar DateTime
#scalar(class: "Nuwave\\Lighthouse\\Schema\\Types\\Scalars\\DateTime")
"Indicates what fields are available at the top level of a query operation."
type Query {
"Gets a page."
pages(
"Filters by name. Accepts SQL LIKE wildcards `%` and `_`."
name: String #where(operator: "like")
): [Page!]! #paginate(defaultCount: 1)
"Gets a list of posts."
posts(
"Filters by featured property."
featured: Boolean
"Filter a single post by the slug"
slug: String
): [Post!]!
#paginate(defaultCount: 10)
#orderBy(column: "published_at", direction: DESC)
}
"A page of the blog."
type Page {
"Unique primary key."
id: ID!
"Name of the page. Used for filters"
name: String!
"Title of the page."
title: String!
"Subtitle of the page."
subtitle: String
"Head title of page."
metaTitle: String
"Head description of page."
metaDescription: String
}
"A blog post."
type Post {
"Unique primary key."
id: ID!
"Post's name. Used for filters."
name: String!
"Post's slug. Used for filters."
slug: String!
"Post's title."
title: String!
"Post's subtitle."
subtitle: String
"Post's short description."
summary: String
"Post's content."
text: String
"Post's head title."
metaTitle: String
"Post's head description."
metaDescription: String
"The date the post was published."
publishedAt: DateTime
}
Here are my Heroku configs:
Lighthouse is working fine. I think you have Introspection disabled on production, thats why GraphqlPlayground fails.
Related
New to GraphQL, Amplify, AppSync, etc, and running into an issue when attempting to subscribe to an onUpdate event.
I added the 'API' library to my Amplify project with authentication through an API key. I can successfully send a mutation (updatePurchaseOrder) request through Postman, and the subscription listener registers an update, but the data returned is null on everything besides the id of the updated record.
screenshot in the AppSync console
The status field is null here, I would expect to see the new updated value. Is that the expected behavior?
The defined type on this:
type PurchaseOrder #model #auth(rules: [ { allow: public } ] ){
id: ID!
name: String!
description: String!
user: String
time: String
file: String!
status: String
}
Schema mutations and subscriptions created from the initial type definition haven't been changed:
type PurchaseOrder {
id: ID!
name: String!
description: String!
user: String
time: String
file: String!
status: String
createdAt: AWSDateTime!
updatedAt: AWSDateTime!
}
type Mutation {
updatePurchaseOrder(input: UpdatePurchaseOrderInput!, condition: ModelPurchaseOrderConditionInput): PurchaseOrder
}
input UpdatePurchaseOrderInput {
id: ID!
name: String
description: String
user: String
time: String
file: String
status: String
}
type Subscription {
onUpdatePurchaseOrder: PurchaseOrder
#aws_subscribe(mutations: ["updatePurchaseOrder"])
}
I tried logging to console in browser and see the same empty object returned. Figured listening through the AppSyncConsole would be less error prone, but I'm still seeing the same result.
Figured out where I went wrong... I needed to specify the response fields I wanted in the POST query (eg.:
mutation updatePurchaseOrder {
updatePurchaseOrder(input: {status: "Pending", id: "53a98236-7b64-428c-93ea-2fae5228c0ef"}) {
id
**status**
}
)
'status' was not in the query response parameters originally. The subscription response will only include fields that are part of the mutation response in the query itself.
I'm currently working on an Activity Feed built using GraphQL Nexus and Apollo Server (3.9.0). It will receive a flurry of information that will have shared fields that are handled by a shared IActivity interface.
In addition, there will be types that will also share similar fields through other interfaces that are not included in IActivity, say for example IMedia and INews.
We are looking for a way to bring all the fields from IActivity and be able to query IMedia and INews within IActivity. We know that there is a possibility to query the concrete types, but we'd like to avoid it, as we want to extend the backend by adding new types of feeds (That share the same fields of those interfaces) without updating the client (it's a react-native application). We would use concrete types only when rendering custom UI components.
Here's an example:
interface IActivity {
id: ID!
name: String!
description: String
}
interface IMedia implements IActivity {
id: ID!
name: String!
description: String
url: String
type: String
}
interface INews implements IActivity {
id: ID!
name: String!
description: String
date: DateTime
author: String
content: String
}
type Video implements IActivity & IMedia {
id: ID!
name: String!
description: String
url: String
type: String
format: String
codec: String
}
type Image implements IActivity & IMedia {
id: ID!
name: String!
description: String
url: String
type: String
compressed: Boolean
codec: String
extension: String
}
type Audio implements IActivity & IMedia {
id: ID!
name: String!
description: String
url: String
type: String
bitrate: Boolean
}
type Post implements INews & IActivity {
id: ID!
name: String!
description: String
date: DateTime
author: String
content: String
comments: [Comment]
}
type Comment {
author: String
message: String
}
type FlashNews implements INews & IActivity {
id: ID!
name: String!
description: String
date: DateTime
author: String
content: String
rating: Int
}
type Query {
activityFeed(): [IActivity]
}
This is the query
query getFeed() {
activityFeed {
id
name
description
... on IMedia {
url
type
}
... on INews {
date
author
content
}
}
}
This queries all the fields from IActivity but none of IMedia nor INews. There are no GraphQL errors (and we lint them through graphql-codegen and the Nexus builder.)
Our belief was that having IActivity also share the same as other interfaces, we could query IActivity and then specify the other interface (e.g: IMedia) as we do with concrete types.
In hindsight, what we're trying to do is somehow a union type of interfaces (which I know it's not possible)...
Is there a workaround or a solution for what we're trying to accomplish?
Edit
We found out that this exact example IS valid, and the problem is within how GraphQL Nexus is configured.
Here's a code sandbox and its Git Repo using plain Apollo Server.
Edit 2:
Try the following query:
query getFeed {
activityFeed {
id
name
description
... on IMedia {
type
format
}
... on INews {
date
author
content
}
... on Video {
length
}
}
}
We have found the problem. It's been Apollo Client (front-end) which was not properly parsing the heuristic fragment matcher.
More information on how we solved the issue can be found here:
https://stackoverflow.com/a/64886593/1057052
We generated something like this:
schema: "./appsync/appSync.gql"
# documents: "./appsync/**/*.gql"
generates:
src/generated/graphql.schema.json:
plugins:
- 'fragment-matcher'
apolloClientVersion: 3
Then the interfaces were working properly!
I was learning to use AWS amplify with React, and the API it uses is a GraphQL API that leverages AWS AppSync. I'm very new to graphQL and my schema currently is like this. This is the schema inside the amplify app:
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
}
To give you an example, I want to store an array of objects inside components in the Note type like this:
Code-1
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
components: []
}
But reading the docs I got to know there aren't any array scalar types. I know that I can create another table and do it like this instead:
Code-2
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
components: [elements!]!
}
type elements #model {
id: ID!
item: String!
}
But I don't want this as it creates a new table. I just want one table containing id, name, description, title, image and a components array where you can store objects in like shown above in Code-1. Is there any possible way to do this? Also whats the role of "#modal" in the schema?
Checked out the AWS docs and found out that I could use AWSJSON for lists/arrays like [1, 2, 3] and maps like {"upvotes": 10}, so now my schema is:
type Note #model {
id: ID!
name: String!
description: String
title: String
image: String
components: AWSJSON
}
Here is the link to know more about it AWS Scalar Types
I’m trying to replicate a REST API that I’ve built in the past and one part that got me thinking was if one of my tables had an array of objects. So for example, I have a table called Profile and it contains arrays Experience and Education that would strictly be under Profile but has its own fields as well but not its own table.
While I was adding fields in GraphQL, I bumped into this not really having a solid solution other than to create new types and then associating them with relationships and then have a resolver or a front-end make sure a Profile is created first before the Experience/Education portion is. I’m not sure if it’s the right way to do it or if there is a better way to do it. Down below is a snippet of what I ended up using… looking at the admin page, there are created tables for Profile, Experience and Education which is expected. But is there a way to only have just Profile and accomplish something similar? Or is this more of a way of life with GraphQL?
type Profile {
id: ID! #id
handle: String!
company: String
website: String
location: String
status: String!
githubUsername: String
experience: [Experience!] #relation(link: INLINE)
education: [Education!] #relation(link: INLINE)
}
type Experience {
id: ID! #id
title: String!
company: String!
}
type Education {
id: ID! #id
title: String!
company: String!
}
In Prisma, you can use embedded types. You would drop the #relation directive and add #embedded directives to the types you're embedding:
type Profile {
id: ID! #id
handle: String!
company: String
website: String
location: String
status: String!
githubUsername: String
experience: [Experience!]
education: [Education!]
}
type Experience #embedded {
title: String!
company: String!
}
type Education #embedded {
title: String!
company: String!
}
However, this only possible if you're using MongoDB for your database and there's some specific limitations listed in the docs when using embedded types.
I'm building a small blog using GraphQL, Apollo Express and MongoDB with Mongoose.
Currently, articles are fetched by their IDs and visitors can browse an article with the id of let's say "123" here: example.com/articles/123
Instead, I would like to use slugs, so visitors can go to example.com/articles/same-article-as-above
My resolver so far:
import { gql } from 'apollo-server-express';
export default gql`
extend type Query {
articles: [Article!]
article(id: ID!): Article
}
type Article {
id: ID!
slug: String!
title: String!
desription: String!
text: String!
}
`;
I could just add another query:
articleBySlug(slug: String!): Article
This would work perfectly fine. However, this doesn't look very elegant to me and I feel like I am missing some basic understanding. Do I really have to add a new query to my resolvers each time I am trying to fetch an article by its title, text, description or whatever? I would end up with a lot of queries like "articleByTitle", "articleByDate", and so on. Can someone please give me a hint, an example or some best practices (or just confirm that I do have to add more and more queries☺)?
A common way to do this is to add all inputs to the same query, and make them optional:
export default gql`
extend type Query {
articles: [Article!]
article(id: ID, slug: String, date: String, search: String): Article
}
type Article {
id: ID!
slug: String!
title: String!
description: String!
text: String!
}
`;
Then, in the resolver just check that exactly one of id, slug or date is provided, and return an error if not.
Another option is to use a search string similar to what Gmail uses (eg id:x before:2012-12-12) that you then parse in the resolver.
export default gql`
extend type Query {
articles: [Article!]
article(search: String): Article
}
type Article {
id: ID!
slug: String!
title: String!
description: String!
text: String!
}
`;
A third option is to set up a separate search query that can return several types:
export default gql`
extend type Query {
articles: [Article!]
search(query: String!, type: SearchType): SearchResult
}
union SearchResult = Article | User
enum SearchType {
ARTICLE
USER
}
type Article {
id: ID!
slug: String!
title: String!
description: String!
text: String!
}
type User {
id: ID!
email: String!
name: String!
}
`;