How to send a GraphQL Query from Node.js to Prisma - graphql

I just learnt how to create a GraphlQL server using graphql-yoga and prisma-binding based on the HowToGraphQL tutorial.
Question: The only way to query the database so far was to use the Prisma Playground webpage that was started by running the command graphql playground.
Is it possible to perform the same query from a Node.js script? I came across the Apollo client but it seems to be meant for use from a frontend layer like React, Vue, Angular.

This is absolutely possible, in the end the Prisma API is just plain HTTP where you put the query into the body of a POST request.
You therefore can use fetch or prisma-binding inside your Node script as well.
Check out this tutorial to learn more: https://www.prisma.io/docs/tutorials/access-prisma-from-scripts/access-prisma-from-a-node-script-using-prisma-bindings-vbadiyyee9
This might also be helpful as it explains how to use fetch to query the API: https://github.com/nikolasburk/gse/tree/master/3-Use-Prisma-GraphQL-API-from-Code
This is what using fetch looks like:
const fetch = require('node-fetch')
const endpoint = '__YOUR_PRISMA_ENDPOINT__'
const query = `
query {
users {
id
name
posts {
id
title
}
}
}
`
fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: query })
})
.then(response => response.json())
.then(result => console.log(JSON.stringify(result)))
If you want to use a lightweight wrapper around fetch that saves you from writing boilerplate, be sure to check out graphql-request.
And here is how you use Prisma bindings:
const { Prisma } = require('prisma-binding')
const prisma = new Prisma({
typeDefs: 'prisma.graphql',
endpoint: '__YOUR_PRISMA_ENDPOINT__'
})
// send `users` query
prisma.query.users({}, `{ id name }`)
.then(users => console.log(users))
.then(() =>
// send `createUser` mutation
prisma.mutation.createUser(
{
data: { name: `Sarah` },
},
`{ id name }`,
),
)
.then(newUser => {
console.log(newUser)
return newUser
})
.then(newUser =>
// send `user` query
prisma.query.user(
{
where: { id: newUser.id },
},
`{ name }`,
),
)
.then(user => console.log(user))

Since you are using Prisma and want to query it from a NodeJS script, I think you might have overlooked the option to generate a client from your Prisma definitions.
It takes care of handling create/read/update/delete/upsert methods depending on your datamodel.
Also, you can worry less about keeping your models and queries/mutations in sync since it is generated using the Prisma CLI (prisma generate).
I find it to save a lot of coding time compared to using raw GrahQL queries, which I save for more complicated queries/mutations.
Check their official documentation for more details.
Also, note that using the Prisma client is the recommended way of using Prisma in prisma-binding resository, unless:
Unless you explicitly want to use schema delegation
which I can't tell you much about.
I did not know of the prisma-binding package untill I read your question.
EDIT:
Here is another link that puts them both in perspective

Related

How to work with both mocked graphql API and an externally served GraphQL endpoint

I'm hoping to hear some inputs from the experts here.
I'm currently working on NextJS project and my graphql is running on mocked data which is setup in another repo.
and now that the backend is built by other devs were slowly moving away from mocked data to the real ones.
They've given me an endpoint to the backend where I'm supposed to be querying data.
So the goal is to make both mocked graphql data and the real data in backend work side by side at least until we fully removed mocked data.
So far saw 2 ways of doing it, but I was looking for a way where I could still use hooks like useQuery and useMutation
Way #1
require('isomorphic-fetch');
fetch('https://graphql.api....', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query: `
query {
popularBrands ( storefront:"bax-shop.nl", limit:10, page:1){
totalCount
items{id
logo
name
image
}
}
}`
}),
})
.then(res => res.json())
.then(res => console.log(res.data));
Way #2
const client = new ApolloClient({
uri: 'https://api.spacex.land/graphql/',
cache: new InMemoryCache()
});
async function test () {
const { data: Data } = await client.query({
query: gql`
query GetLaunches {
launchesPast(limit: 10) {
id
mission_name
launch_date_local
launch_site {
site_name_long
}
links {
article_link
video_link
mission_patch
}
rocket {
rocket_name
}
}
}
`
});
console.log(Data)
}
Pseudo code:
Query the real data first
check if its empty, if it is, query the mock data.
If both are empty, then it's really an empty result set.
You can write a wrapper around the hooks you use that does this for you so you don't have to repeat yourself in every component. When you're ready to remove the mocked data you just remove the check for the second. data set.
This is a common technique when switching to a new database.

Use Apollo server as a pass through of a query from client

I have a use case where I have apollo-server-express running with a React based apollo-client. I have an external graphql-datasource for some queries. Currently, I've configured apollo-datasource-graphql to be used as a data source for my apollo-server-express. However, this requires duplication of work on the resolver in Apollo as well as the resolver on my external graphql system.
Is there a way for me to pass queries made in the client through the Apollo Server and to the external graphql data source?
Maybe you could access the GraphQL AST from the fourth resolver argument (resolveInfo) and pass it into a GraphQL client?
Here is some prototype code:
import { print } from 'graphql/language/printer';
function forwardOperationResolver(root, args, context, resolveInfo) {
return fetch('https://remote.host/graphql', {
method: 'POST',
body: JSON.stringify({
query: print(resolveInfo.operation),
variables: resolverInfo.variableValues,
}),
})
.then(response => response.json())
.then(response => {
if (response.errors) {
// Handle errors
}
return response.data;
});
}
Downside: This breaks a few things that usually work in GraphQL like partial results and error locations...

Use Apollo Client or Isomorphic Fetch with GraphiQL

I am trying to integrate the GraphiQL IDE into my website and am wondering if I can get some advice on whether I would be best using the Apollo Client that the rest of the site uses or using Isomorphic Fetch as recommended in the documentation.
If I use the Apollo Client then I only have one connection to worry about and don't have to think about ensuring authentication is correct but the code is more complex.
I have this code working for the fetcher function, but so far it only works with queries and to my understanding would need a fair amount of work to work with mutations as well.
graphQlFetcher = (params) => {
return this.props.client.query({
query: gql`
${params.query}
`
}).then(function(result) {
return result;
});
}
Alternatively there is the isomorphic fetch approach, but for this to work I need to get the authentication token first and I am not good enough with promises to make this work. Not working code:
import { Auth } from 'aws-amplify';
getToken = async () => {
const session = await Auth.currentSession();
return session.accessToken.jwtToken;
}
graphQLFetcher = (graphQLParams) => {
return getToken().then(function(token) {
fetch(window.location.origin + '/graphql', {
method: 'post',
headers: {
'Content-Type': 'application/json',
"Authorization": token
},
body: JSON.stringify(graphQLParams),
}).then(response => response.json());
})
}
Appreciate that there are two possible ways to solve this problem and that it is as much a design question as a technical one but hoping that someone can help me out.
The first one is fine, but you have some excess syntax on there. This is what I use:
params => client.query({ ...params, query: gql(params.query) });

Cypress w/graphql - having issues getting AUTH with testing via UI. Better way to stub mutation?

So, if I am testing pages in a vacuum without much interaction with the backend, it works great. I am having issues with actually interacting with my UI if it hits any type of service. Basically, nothing is Auth'd. I try programmatically setCookie, no dice. I try to read the cookie, nope. Btw, my whole site requires a login.
cy.setCookie('sess', ';askjdfa;skdjfa;skdjfa;skdjfa;skfjd');<-- does not work
cy.getCookie('sess').should('exist') <-- does not work
I am having an issue on really the best way to "test" this. For example, I have an account section that a user can "update" their personals. I try, fill out the form (via UI testing), but the submission is rejected, no Auth. EVEN THOUGH I just logged in (via UI testing). - I know I need to remove that since it is bad practice to UI-Login for every section of my site.
So, I don't know how to stub graphql calls with cy.request(). Here is my mutation.
mutation Login($email: Email!, $password: String!) {
login(email: $email, password: $password) {
userID
firstName
lastName
}
}
Right now, I am importing the login spec for each section of the site i am testing. I know this is an anti-pattern. Like to solve this problem.
My AUTH (cookie) is not being set. Even when I try to set it, programmatically, doesn't work.
Maybe I should just stub out my graphql mutations? How?
Lastly, IF I am stubbing out my graphql mututations, how do I update the session ( via my main session query ). If I can get these mutations to work, then refreshing the page will get my my updated data, so I'm not completely needing this part.
Any ideas?
I didn't do the stub and all those, as you were asking how the mutation would work with cy.request in my other post. I did it this way and it just basically works. Hopefully this would help
I created a const first though
export const join_graphQL = (query, extra={}) => {
return `mutation {
${query}(join: { email: "${extra.email}", id: "${extra.id}" }) {
id, name, email
}
}`
};
request config const
export const graphqlReqConfig = (body={}, api=graphQlapi, method='POST') => {
return {
method,
body,
url: api,
failOnStatusCode: false
}
};
mutation query with cy.request
const mutationQuery = join_graphQL('mutationName', {
email: "email",
id: 38293
});
cy.request(graphqlReqConfig({
query: mutationQuery
})).then((res) => {
const data = res.body.data['mutationName']; // your result
});
hopefully it's not too messy to see.
basically the fields need to be string such as "${extra.email}" else it will give you error. Not sure how the graphql works deeply but if I just do ${extra.email} I would get an error which I forgot what error it was.
Here's a simpler way of handling a mutation with cy.request
const mutation = `
mutation {
updateUser(id: 1, firstName: "test") {
firstName
lastName
id
role
}
}`
cy.request({
url: url,
method: 'POST',
body: { query: mutation },
headers: {
Authorization: `Bearer ${token}`,
},
})

Passing a token through Query?

I have a Graph QL server running (Apollo Server 2) and the API behind it requires every request to include a token.
Currently the token comes from HTTP Request Cookie. This was simple enough to work. When the request comes in, grab the cookie from the header and pass it along to the HTTP request to be sent to the API server through the resolvers.
I'd like to make it so a GraphQL client can pass this token along through the POST query itself.
Basically wondering if I can define a global GQL variable of some sort. "All queries, this variable is required."
I had a similar implementation in Typescript, and in order to achieve something like this, I've define an object:
const globalInput = {
token: {
type: GraphQLString;
}
}
And then use it in your GraphQLObjectType:
const Query = new GraphQLObjectType({
name: 'Query',
fields: () => ({
myObject: {
type: MyTypeObject,
args: { ...globalInput },
resolve: (source: any, args: any) => {
// global input values can be access in args
// ex: args.token
return {}
}
}
})
})
The problem is that I need to extend it(...globalInput) it in every object type.
But it does the job.

Resources