How to build a Graqhql mutation with existing variables - node.js

This might seem like an odd question, or something really straightforward, but honestly I am struggling to figure out how to do this. I am working in Node.js and I want to set data I have saved on a node object into my GraphQL mutation.
I'm working with a vendor's GraqhQL API, so this isn't something I have created myself, nor do I have a schema file for it. I'm building a mutation that will insert a record into their application, and I can write out everything manually and use a tool like Postman to manually create a new record...the structure of the mutation is not my problem.
What I'm struggling to figure out is how to build the mutation with variables from my node object without just catting a bunch of strings together.
For example, this is what I'm trying to avoid:
class MyClass {
constructor() {
this.username = "my_username"
this.title = "Some Title"
}
}
const obj = new MyClass()
let query = "mutation {
createEntry( input: {
author: { username: \"" + obj.username + "\" }
title: \"" + obj.title + "\"
})
}"
I've noticed that there are a number of different node packages out there for working with Graphql, but none of their documentation that I've seen really addresses the above situation. I've been completely unsuccessful in my Googling attempts, can someone please point me in the right direction? Is there a package out there that's useful for just building queries without requiring a schema or trying to send them at the same time?

GraphQL services typically implement this spec when using HTTP as a transport. That means you can construct a POST request with four parameters:
query - A Document containing GraphQL Operations and Fragments to execute.
operationName - (Optional): The name of the Operation in the Document to execute.
variables - (Optional): Values for any Variables defined by the Operation.
extensions - (Optional): This entry is reserved for implementors to extend the protocol however they see fit.
You can use a Node-friendly version of fetch like cross-fetch, axios, request or any other library of your choice to make the actual HTTP request.
If you have dynamic values you want to substitute inside the query, you should utilize variables to do so. Variables are defined as part of your operation definition at the top of the document:
const query = `
mutation ($input: SomeInputObjectType!) {
createEntry(input: $input) {
# whatever other fields assuming the createEntry
# returns an object and not a scalar
}
}
`
Note that the type you use will depend on the type specified by the input argument -- replace SomeInputObjectType with the appropriate type name. If the vendor did not provide adequate documentation for their service, you should at least have access to a GraphiQL or GraphQL Playground instance where you can look up the argument's type. Otherwise, you can use any generic GraphQL client like Altair and view the schema that way.
Once you've constructed your query, make the request like this:
const variables = {
input: {
title: obj.title,
...
}
}
const response = await fetch(YOUR_GRAPHQL_ENDPOINT, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, variables }),
})
const { data, errors } = await response.json()

Related

How to add TypeScript Interface to shorthand variable?

How to set TypeScript interface to variable looking like this:
const { body, statusCode } = await got.post('smth', requestOpts)
How can I set the interface to ex. body. I would like to assign there an interface with potential requests from the server. An interface that I'm willing to implement looks like that:
interface ResponseBody {
data: [{ username: string }]
}
I tried different things to attach this interface to the upper variable body but I'm getting build errors. The only workaround that I have here is to do not use shorthand variable but that's not my goal - I wonder if there are solutions for such issue.
TypeScript Playground
You'd need to annotate the whole object, like this:
const { body, statusCode }: { body: ResponseBody, statusCode: number } =
await got.post<ResponseBody>('users', requestOpts)
While it would be nice if you could annotate the individual destructured variables inside the object, this is not currently possible. The syntax const { body: ResponseBody } = ... can't work because JavaScript interprets this as assigning to a new variable name (so there'd be a variable named ResponseBody holding the value that was in the body property). Perhaps something like const { body::ResponseBody, statusCode::number } would work instead, as requested in microsoft/TypeScript#29526. But for now this is not possible, and you have to annotate the whole object.
That's the answer to the question as asked.
Do note that for your particular example, though, the got.post() method has a call signature that's generic in the type you expect the body property to be. So you can write
const { body, statusCode } = await got.post<ResponseBody>('users', requestOpts);
to get a strongly typed body variable with a minimum of extra keystrokes.
Playground link to code

Client is Angular 8 with NgRx-Data; Server is NestJs + MySQL. How to get data using criteria and SQL?

As Angular, NgRx-Data and NestJs are becomming more and more popular, I feel there may be quite a few programmers who are wondering about the querying syntax for the following.
I have a running prototype of a client (front end) composed in Angular 8 with NgRx-Data.
On the back end is a NestJs based server + MySQL.
I can nicely retrieve and pass data between all parts, except queries. I do not seem to be able to find proper documentation on the syntax.
Here is the example of how the client is set:
// Simple entity example (all ngrx-data metadata are declared and set):
export class Hero {
id: number;
name?: string;
age?: number;
}
Entity Service / for fetching data
#Injectable({providedIn: 'root'})
export class HeroService extends EntityCollectionServiceBase<Hero> {
constructor(serviceElementsFactory: EntityCollectionServiceElementsFactory) {
super('Hero', serviceElementsFactory);
}
}
Component for showing data
#Component({
selector: 'hero-comp',
templateUrl: './hero.component.html',
styleUrls: ['./hero.component.scss']
})
export class HeroComponent {
heroData$: Observable<Hero[]>;
constructor(private heroDatService: HeroService) {
this.heroData$ = this.heroDatService.entities$;
}
private getAllData() {
// This works nicely, I get all records from the db via server
this.heroDatService.getAll();
}
private queryData() {
// This queryParams syntax fails - server complains with this error:
// [HttpExceptionFilter] GET /hero/?age>20
// QueryFailedError: ER_EMPTY_QUERY: Query was empty
// QUESTION: What is the proper syntax?
let queryParams: QueryParams = {
'age > 20'
}
this.fetchDataService.getWithQuery(queryParams);
}
Here is the server related code excerpt: -
(there is a service, but for simplicity here, I moved the repo functions to the controller functions):
#Controller('hero')
export class HeroController <Hero> {
constructor(readonly repo: Repository<Hero>) {}
// This returns nicely all Hero records from the MySQL db server
#Get()
async getAll(): Promise<Hero[]> {
return await this.repo.find();
}
// This does not work !
// I am not sure about any piece of the code here !
#Get('query')
async query(#Query() sql): Promise<any> {
// Does the sql argument need to be manipulated into parameters: {...} ?
// If yes - how ?
let parameters: undefined;
return await this.repo.query(sql, parameters);
}
Please see the comments above each code line - the problems are spelled out there.
And here are the important questions:
On the client how do we properly pass query criteria for some of these examples:
- {'age > 20'}
- {'age BETWEEN 20 AND 40'}
- {'age = 20 OR age = 30 OR age = 40'}
- {'name = "Superman"'}
- {'name LIKE "Super%"'}
- etc.
Also, what would be the syntax for passing a full SQL sentence, such as:
- {'SELECT * FROM Heroes WHERE name LIKE "Super%" AND Age > 20;'}
and getting the result from the server.
What needs to be done on both ends (client and server) for these queries to work?
All inputs much appreciated.
It seems like you're confused about HTTP Query parameters and SQL querying, which are two different topics. Query parameters, in the context of HTTP, are parameters that can be passed from the client to the server and modify the outcome of the HTTP call. Query parameters are always passed starting with a ? in the URL in the form of <key>=<value> and separated with an &.
A SQL Query is a specific string that tells a SQL server what table to query against, for what columns, with what conditions. Usually in the form of SELECT <columns> FROM <table> WHERE <conditions>;, but they can be much more complex than that.
Now that definitions are out of the way, the endpoint you are trying to reach should be /hero/query. You'll need to end up doing a lot of data processing on the server side of things, sanitization, ensuring that the incoming string is proper for SQL WHERE clauses, ensuring that you won't be vulnerable to SQL Injections (if you pass the query params straight to your query, you will be), but a very very naive approach would look something like this:
#Controller('hero')
export class HeroController {
constructor(#InjectRepository(Hero) private readonly repo: Repository<Hero>) {}
#Get('query')
queryForHero(#Query() queryParam) {
return this.repo.query(`SELECT <field_go_here> FROM Hero WHERE ${queryParams.query};`);
}
}
For the love of all that is good in the world, do not actually use the above code. It is 100% vulnerable to all kinds of SQL injections.
A corresponding request could look something like
curl http://<host>/hero/query?query=Name%3D%27Superman%27
This would cause the server to use the query
SELECT <fields_go_here> FROM Hero WHERE Name='Superman';
You'll really want to add in a ton of validations on what is coming into your server before just sending it to your SQL server lest you end up like Little Bobby Table.
Hopefully this helps get you on the right path.

How to develop an Import/Export Functionality for my node application

I have a configuration application in Nodejs. It has a Component with name and uuid. A Component can have many Schemas. A Schema has a uuid, name, componentId, json. A Schema can have many Configurations. A Configuration has name, schemaId, json and uuid. A Schema can contain reference of many other Schemas in it. Now I want to create a functionality of exporting all the data from one instance of the application and import it in another. What should be the simplest way to do it? a few questions are
How to tell application what to export. for now i think there should be separate arrays for components, schemas and configurations. Like
{
components: ['id1', 'id2'],
schemas: ['s1', 's2'],
configuration: ['c1', 'c2'],
}
this data should be sent to application to return a file with all information that will later be used for importing in another instance
The real question is how should my export file look like keeping in mind that dependencies are also involved and dependencies can also overlap. for example a schema can have many other schemas referenced in its json field. eg schema1 has schema2 and schema4 as its dependencies. so there is another schema schema5 that also require schema2. so while importing we have to make sure that schema2 should be saved first before saving schema1 and schema5. how to represent such file that requires order as well as overlapped dependencies, making sure that schema2 is not saved twice while importing. json of schema1 is shown below as an example
{
"$schema": "http://json-schema.org/draft-04/schema#",
"p1": {
"$ref": "link-to-schema2"
},
"p2": {
"$ref": "link-to-schema4"
},
}
What should be the step wise sudo algorithm i should follow while importing.
This is a perfect occasion for a topological sort.
Taking away components, schemas and configurations terminology, what you have is objects (of various kinds) which depend on other objects existing first. A topological sort will create an order that has only forward dependencies (assuming you don't have circular ones, in which case it is impossible).
But the complication is that you have dependency information in a mix of directions. A component has to be created before its schema. A schema has to be created after the schemas that it depends on. It is not impossible that those schemas may belong to other components that have to be created as well.
The first step is to write a function that takes an object and returns a set of dependency relationships discoverable from the object itself. So we want dependencyRelations(object1 to give something like [[object1, object2], [object3, object1], [object1, object4]]. Where object1 depends on object2 existing. (Note, object1 will be in each pair but can be first or second.)
If every object has a method named uniqueName that uniquely identifies it then we can write a method that works something like this (apologies, all code was typed here and not tested, there are probably syntax errors but the idea is right):
function dependencyInfo (startingObject) {
const nameToObject = {};
const dependencyOf = {};
const todo = [startingObject];
const visited = {};
while (0 < todo.length) {
let obj = todo.pop();
let objName = obj.uniqueName();
if (! visited[ objName ]) {
visited[ objName ] = true;
nameToObject[objName] = obj;
dependencyRelations(obj).forEach((pair) => {
const [from, to] = pair;
// It is OK to put things in todo that are visited, we just don't process again.
todo.push(from);
todo.push(to);
if (! dependencyOf[from.uniqueName()]) {
dependencyOf[from.uniqueName()] = {}
}
dependencyOf[from.uniqueName()] = to.uniqueName();
});
}
}
return [nameToObject, dependencyOf];
}
This function will construct the dependency graph. But we still need to do a topological sort to get dependencies first.
function objectsInOrder (nameToObject, dependencyOf) {
const answer = [];
visited = {};
// Trick for a recursive function local to my environment.
let addObject = undefined;
addObject = function (objName) {
if (! visited[objName]) {
visited[objName] = true; // Only process once.
// Add dependencies
Object.keys(dependencyOf[objName]).forEach(addObject);
answer.push(nameToObject[objName]);
}
};
Object.keys(dependencyOf).forEach(addObject);
return answer;
}
And now we have an array of objects such that each depends on the previous ones only. Send that, and at the other end you just inflate each object in turn.

Is there a way to convert a graphql query string into a GraphQLResolveInfo object?

I have written a piece of software that parses and formats the fourth parameter of a graphql resolver function (the info object) to be used elsewhere. I would like to write unit tests for this software. Specifically, I do not want to build the GraphQLResolveInfo object myself, because doing that would be very cumbersome, error-prone and hard to maintain. Instead, I want to write human-readable query strings and convert them to GraphQLResolveInfo objects so I can pass those to my software.
After extensive googling and reading of the graphql-js source code, I have not found a simple way to do what they are doing internally. I'm really hoping that I am missing something.
What I am not trying to do is use the graphql-tag library, because that just generates an AST which has a very different format from the GraphQLResolveInfo type.
Has anyone done this before? Help would be much appreciated!
I will keep monitoring this question to see if a better answer comes along, but I've finally managed to solve my particular issue by creating as close an approximation of the GraphQLResolveInfo object as I need for my particular use case.
The GraphQLResolveInfo object is composed of several attributes, two of which are called fieldNodes and fragments. Both are in fact parts of the same AST that graphql-tag generates from a query string. These are the only parts of the GraphQLResolveInfo object that concern the software I wrote, the rest of it is ignored.
So here is what I did:
import gql from 'graphql-tag';
// The converter function
const convertQueryToResolveInfo = (query) => {
const operation = query.definitions
.find(({ kind }) => kind === 'OperationDefinition');
const fragments = query.definitions
.filter(({ kind }) => kind === 'FragmentDefinition')
.reduce((result, current) => ({
...result,
[current.name.value]: current,
}), {});
return {
fieldNodes: operation.selectionSet.selections,
fragments,
};
};
// An example call
const query = gql`
query {
foo {
bar
}
}
`;
const info = convertQueryToResolveInfo(query);
From the AST generated by graphql-tag, I extract and modify the operation and fragment definitions so that they look the way they do within the GraphQLResolveInfo object. This is by no means perfect and may be subject to change in the future depending on how my software evolves, but it is a relatively brief solution for my particular problem.

GraphQL string concatenation or interpolation

I'm using GitHub API v 4 to learn GraphQL. Here is a broken query to fetch blobs (files) and their text content for a given branch:
query GetTree($branch: String = "master") {
repository(name: "blog-content", owner: "lzrski") {
branch: ref(qualifiedName: "refs/heads/${branch}") {
name
target {
... on Commit {
tree {
entries {
name
object {
... on Blob {
isBinary
text
}
}
}
}
}
}
}
}
}
As you see on line 3 there is my attempt of guessing interpolation syntax, but it does not work - I leave it as an illustration of my intention.
I could provide a fully qualified name for a revision, but that doesn't seem particularly elegant. Is there any GraphQL native way of manipulating strings?
I don't think there's anything in the GraphQL specification that specifically outlines any methods for manipulating string values within a query.
However, when utilizing GraphQL queries within an actual application, you will provide most of the arguments for your query by utilizing variables that are passed alongside your query inside your request. So rather than being done inside your query, most of your string manipulation will be done within your client code when composing the JSON that will represent your variables.

Resources