How to remove <br> tags from string in GraphQL query results - javascript

I'm working on a React application that utilizes Apollo and GraphQl to query an external API. My issue is that the data contains strings that have tags in them. I'd like to remove the tags.
The string looks like:
Additionally, Igor works as a driver for a transport company.<br /><br />The spring agricultural works on the land started already and he now supports more expenses.
My response data looks like 'data.loans.lend.values', and so I've tried using the str.replace() method on my data. However, it didn't work. I've probably spent about five hours combing through the web to find a solution, but haven't been able to.
This is what my Apollo query component looks like.
<Query query={kivaLoans} variables={{ country: country, sortBy: sort, limit: limitResults }}>
{({ data, loading, error }) => {
if (loading) return <div><p>Loading...</p></div>;
if (error) return <p>ERROR</p>;
return (
And this is my GraphQL query.
gql`
query ($country: [String], $sortBy: LoanSearchSortByEnum, $limit: Int) {
lend {
loans(filters: {status: fundraising, country: $country}, sortBy: $sortBy, limit: $limit) {
values {
id
plannedExpirationDate
image {
url(customSize: "s900")
}
name
loanFundraisingInfo {
fundedAmount
}
loanAmount
description
loanAmount
}
}
}
}`
Has anyone else encountered this issue before?

if you are receiving data back in a format you don't like, this means the graphql server, a database it leverages, or an api it leverages, is returning data to the graphql server in a format that isn't useful for you. The other possibility is that your server itself is formatting your data in an annoying way. So here are your options:
change your server / data sources as appropriate
do a global replace on the string returned: str.replace(/<b>/g, '').replace(/<\/b>/g, ''). Double check my escape characters, I may have that backwards.
in a string replace, /[what you want replaced]/g = a regex for global detection, across the entire string

Related

GitHub GraphQL API query for response simplification [duplicate]

Let's say I've got a GraphQL query that looks like this:
query {
Todo {
label
is_completed
id
}
}
But the client that consumes the data from this query needs a data structure that's a bit different- e.g. a TypeScript interface like:
interface Todo {
title: string // "title" is just a different name for "label"
data: {
is_completed: boolean
id: number
}
}
It's easy enough to just use an alias to return label as title. But is there any way to make it return both is_completed and id under an alias called data?
There is no way to do that. Either change the schema to reflect the client's needs or transform the response after it is fetched on the client side.

Problem with getting RAW format of excerpt in WPGraphQL using Apollo

When I try to get an excerpt from WPGraphQL plugin and pass excerpt(format: RAW) in the query, it's working fine in the WPGraphiQL window, but when I'm executing the same query in Vue Apollo it's always returning null.
Here is my code:
apollo: {
posts: gql`
query {
posts {
nodes {
title
uri
date
databaseId
featuredImage {
sourceUrl
}
excerpt(format: RAW)
}
}
}
`
},
Am I guessing right that it has to deal with enum type on the server-side and the way it's passed in Apollo query string? Also when I pass only excerpt without argument it returns excerpt with HTML tags, so... what's wrong?
Use excerpt(format: FORMATTED)
and use in html like this:
dangerouslySetInnerHTML={{ __html: node.excerpt }}
You can only access content in the RAW format if your user is authenticated. This is why you can see the RAW content in the WPGraphiQL window, but not when you try to get this same data from your Vue app. You need to authenticate the query in your app. https://www.wpgraphql.com/docs/authentication-and-authorization/

How can I format my SQL output to match my GraphQL type?

I've had a google for this, but can't seem to find the answer.
I have a GraphQL type that looks like this:
type Ticket {
id: Int!
bandID: Int!
band: Band
ticketURL: String!
price: Int!
date: String!
}
I'd like to be able to return something like this from MSSQL, GraphQL and JS:
[
{
id: 1,
ticketURL: "https://example.co.uk",
price: 50,
date: "2019/01/01",
band: {
id: 1,
name: "Band name"
}
}
]
What would be the most efficient way of returning a data structure like this? The first thing that comes to mind is something like the below, but it seems so inefficient and wrong.
// Call SQL to get all tickets: "SELECT * FROM Ticket"
// For each ticket
// Call SQL to get the Band
// Merge with the ticket obj
Generally speaking, I would encourage you not to shoot for what you're describing. The designing principles of the GraphQL spec encourage you to make sure that your API logic is specifically for your client's wants, and that if something better-suited to your needs comes along to replace GraphQL, you should be able to remove the GraphQL layer and replace it with whatever the new thing is without having to rewrite your logic. This specific request is, according to the GraphQL inventors, too tightly-coupled to the API. For most people, the latency to the database isn't a big enough bottleneck to need this kind of optimization. Instead, I would encourage you to use dataloaders (for caching and for bulk requests) and just to write your resolvers to call your ORM or whatever to fetch these data points.

Best way to escape array of data on MysQl nodeJS query

So I have the following object with is made by data submitted by the user in order to sign up:
var dataToInsert = {
userName: 'Wilson J',
userEmail: 'WilsonJ#gmail.com',
userAddress: '2020 St.',
userCellPhone: '95587412',
}
And I'm using the following query to insert it:
var insertQuery = `INSERT INTO users ( ${Object.keys(dataToInsert).toString()} ) VALUES( '${Object.values(dataToInsert).join("','")}' )`;
Which at the end is taken as:
INSERT INTO
users (
userName,
userEmail,
userAddress,
userCellPhone
)
VALUES
(
'Wilson J',
'WilsonJ#gmail.com',
'2020 St',
95587412
)
So far I'm having a hard time understanding how data escaping works. I'd really appreciate if someone could show me how a SQL Injection could take place with this code and how to prevent it.
I'm using the MysQl npm module and it has this method: mysql.escape() but I would like to find a more automated approach instead of escaping every single value manually.
In this day and age, it's actively discouraged to do anything other than bind variables to your query. See this for more information on other ways to escape data:
connection.query(`
INSERT INTO users ( ${Object.keys(dataToInsert).toString()} ) VALUES (?)`,
Object.values(dataToInsert),
function (error, results, fields) {
if (error) throw error;
// ...
}
);
Word of caution: You wont be able to bind variables to the column names, so unfortunately that part of the query is necessary. Ensure your keys of your dataToInsert are either static, or not from any user input.
Alternatively, you can use ? characters as placeholders for values you would like to have escaped like this: [...]
There is a way. https://github.com/mysqljs/mysql#user-content-escaping-query-values

How to do a simple join in GraphQL?

I am very new in GraphQL and trying to do a simple join query. My sample tables look like below:
{
phones: [
{
id: 1,
brand: 'b1',
model: 'Galaxy S9 Plus',
price: 1000,
},
{
id: 2,
brand: 'b2',
model: 'OnePlus 6',
price: 900,
},
],
brands: [
{
id: 'b1',
name: 'Samsung'
},
{
id: 'b2',
name: 'OnePlus'
}
]
}
I would like to have a query to return a phone object with its brand name in it instead of the brand code.
E.g. If queried for the phone with id = 2, it should return:
{id: 2, brand: 'OnePlus', model: 'OnePlus 6', price: 900}
TL;DR
Yes, GraphQL does support a sort of pseudo-join. You can see the books and authors example below running in my demo project.
Example
Consider a simple database design for storing info about books:
create table Book ( id string, name string, pageCount string, authorId string );
create table Author ( id string, firstName string, lastName string );
Because we know that Author can write many Books that database model puts them in separate tables. Here is the GraphQL schema:
type Query {
bookById(id: ID): Book
}
type Book {
id: ID
title: String
pageCount: Int
author: Author
}
type Author {
id: ID
firstName: String
lastName: String
}
Notice there is no authorId on the Book type but a type Author. The database authorId column on the book table is not exposed to the outside world. It is an internal detail.
We can pull back a book and it's author using this GraphQL query:
{
bookById(id:"book-1"){
id
title
pageCount
author {
firstName
lastName
}
}
}
Here is a screenshot of it in action using my demo project:
The result nests the Author details:
{
"data": {
"book1": {
"id": "book-1",
"title": "Harry Potter and the Philosopher's Stone",
"pageCount": 223,
"author": {
"firstName": "Joanne",
"lastName": "Rowling"
}
}
}
}
The single GQL query resulted in two separate fetch-by-id calls into the database. When a single logical query turns into multiple physical queries we can quickly run into the infamous N+1 problem.
The N+1 Problem
In our case above a book can only have one author. If we only query one book by ID we only get a "read amplification" against our database of 2x. Imaging if you can query books with a title that starts with a prefix:
type Query {
booksByTitleStartsWith(titlePrefix: String): [Book]
}
Then we call it asking it to fetch the books with a title starting with "Harry":
{
booksByTitleStartsWith(titlePrefix:"Harry"){
id
title
pageCount
author {
firstName
lastName
}
}
}
In this GQL query we will fetch the books by a database query of title like 'Harry%' to get many books including the authorId of each book. It will then make an individual fetch by ID for every author of every book. This is a total of N+1 queries where the 1 query pulls back N records and we then make N separate fetches to build up the full picture.
The easy fix for that example is to not expose a field author on Book and force the person using your API to fetch all the authors in a separate query authorsByIds so we give them two queries:
type Query {
booksByTitleStartsWith(titlePrefix: String): [Book] /* <- single database call */
authorsByIds(authorIds: [ID]) [Author] /* <- single database call */
}
type Book {
id: ID
title: String
pageCount: Int
}
type Author {
id: ID
firstName: String
lastName: String
}
The key thing to note about that last example is that there is no way in that model to walk from one entity type to another. If the person using your API wants to load the books authors the same time they simple call both queries in single post:
query {
booksByTitleStartsWith(titlePrefix: "Harry") {
id
title
}
authorsByIds(authorIds: ["author-1","author-2","author-3") {
id
firstName
lastName
}
}
Here the person writing the query (perhaps using JavaScript in a web browser) sends a single GraphQL post to the server asking for both booksByTitleStartsWith and authorsByIds to be passed back at once. The server can now make two efficient database calls.
This approach shows that there is "no magic bullet" for how to map the "logical model" to the "physical model" when it comes to performance. This is known as the Object–relational impedance mismatch problem. More on that below.
Is Fetch-By-ID So Bad?
Note that the default behaviour of GraphQL is still very helpful. You can map GraphQL onto anything. You can map it onto internal REST APIs. You can map some types into a relational database and other types into a NoSQL database. These can be in the same schema and the same GraphQL end-point. There is no reason why you cannot have Author stored in Postgres and Book stored in MongoDB. This is because GraphQL doesn't by default "join in the datastore" it will fetch each type independently and build the response in memory to send back to the client. It may be the case that you can use a model that only joins to a small dataset that gets very good cache hits. You can then add caching into your system and not have a problem and benefit from all the advantages of GraphQL.
What About ORM?
There is a project called Join Monster which does look at your database schema, looks at the runtime GraphQL query, and tries to generate efficient database joins on-the-fly. That is a form of Object Relational Mapping which sometimes gets a lot of "OrmHate". This is mainly due to Object–relational impedance mismatch problem.
In my experience, any ORM works if you write the database model to exactly support your object API. In my experience, any ORM tends to fail when you have an existing database model that you try to map with an ORM framework.
IMHO, if the data model is optimised without thinking about ORM or queries then avoid ORM. For example, if the data model is optimised to conserve space in classical third normal form. My recommendation there is to avoid querying the main data model and use the CQRS pattern. See below for an example.
What Is Practical?
If you do want to use pseudo-joins in GraphQL but you hit an N+1 problem you can write code to map specific "field fetches" onto hand-written database queries. Carefully performance test using realist data whenever any fields return an array.
Even when you can put in hand written queries you may hit scenarios where those joins don't run fast enough. In which case consider the CQRS pattern and denormalise some of the data model to allow for fast lookups.
Update: GraphQL Java "Look-Ahead"
In our case we use graphql-java and use pure configuration files to map DataFetchers to database queries. There is a some generic logic that looks at the graph query being run and calls parameterized sql queries that are in a custom configuration file. We saw this article Building efficient data fetchers by looking ahead which explains that you can inspect at runtime the what the person who wrote the query selected to be returned. We can use that to "look-ahead" at what other entities we would be asked to fetch to satisfy the entire query. At which point we can join the data in the database and pull it all back efficiently in the a single database call. The graphql-java engine will still make N in-memory fetches to our code. The N requests to get the author of each book are satisfied by simply lookups in a hashmap that we loaded out of the single database call that joined the author table to the books table returning N complete rows efficiently.
Our approach might sound a little like ORM yet we did not make any attempt to make it intelligent. The developer creating the API and our custom configuration files has to decide which graphql queries will be mapped to what database queries. Our generic logic just "looks-ahead" at what the runtime graphql query actually selects in total to understand all the database columns that it needs to load out of each row returned by the SQL to build the hashmap. Our approach can only handle parent-child-grandchild style trees of data. Yet this is a very common use case for us. The developer making the API still needs to keep a careful eye on performance. They need to adapt both the API and the custom mapping files to avoid poor performance.
GraphQL as a query language on the front-end does not support 'joins' in the classic SQL sense.
Rather, it allows you to pick and choose which fields in a particular model you want to fetch for your component.
To query all phones in your dataset, your query would look like this:
query myComponentQuery {
phone {
id
brand
model
price
}
}
The GraphQL server that your front-end is querying would then have individual field resolvers - telling GraphQL where to fetch id, brand, model etc.
The server-side resolver would look something like this:
Phone: {
id(root, args, context) {
pg.query('Select * from Phones where name = ?', ['blah']).then(d => {/*doStuff*/})
//OR
fetch(context.upstream_url + '/thing/' + args.id).then(d => {/*doStuff*/})
return {/*the result of either of those calls here*/}
},
price(root, args, context) {
return 9001
},
},

Categories

Resources