I am new user for graphql. I am planning to use graphql as a middleware layer where different application will hit the API and get the data they require. But main problem is training different groups as to how to post data and query the data they require. Is is good idea to build a middleware which accepts JSON over REST api and converts it to graphql request. I am thinking of 2 options
1. Build REST middle layer which accepts JSON and convert it to graphql request.
2. Ask user to get comfortable with graphql.
Mixing REST and graphql is never a good idea for a new project, because you will waste your resources for doing the same thing in two different ways and you will have to maintain larger codebase. Providing REST and graphql at the same time may seems like a convenience for your customers but in the long run, it is not. Smaller, well structured and well documented API is always preferable.
If you are going to mix and match different resources or call outside services graphql offers better solution. Graphql provides strong typing, single round trip, query batching, instrospection and better dev tools, versionless API.
Related
I wanted to test the response times of a GraphQL endpoint, and a RESTful endpoint as I haven't ever used GraphQL before, and I am about to use it in my next Laravel project.
So I am using Lighthouse PHP package to serve a GraphQL endpoint from my Laravel app, and also I have created a RESTful endpoint.
Both endpoints(GraphQL and RESTful) are intended to get all Users(250 users) from my local Database.
So based on the test what I have noticed here is that, when I tested this both endpoints on Postman, the RESTful endpoint response is faster than GraphQL endpoint.
Can I know why GraphQL endpoint's response takes more time than RESTful while both endpoints are getting same data?
GraphQL endpoint result for GET request (response time: 88ms)
GraphQL endpoint result for POST request (response time: 88ms)
RESTful endpoint result (response time: 44ms)
There's no such thing as a free lunch.
GraphQL offers a lot of useful features, but those same features invariably incur some overhead. While a REST endpoint can effectively pull data from some source and regurgitate it back to the client, even for a relatively small dataset, GraphQL will have to do some additional processing to resolve and validate each individual field in the response. Not to mention the processing required to parse and validate the request itself. And this overhead only gets bigger with the size of the data returned.
If you were to introduce additional features to your REST endpoint (request and response validation, support for partial responses, ability to alias individual response fields, etc.) that mirrored GraphQL, you would see the performance gap between the two shrink. Even then, though, it's still somewhat of an apples and oranges comparison, since a GraphQL service will go through certain motions simply because that's what the spec says to do.
TLDR: Your REST example is simple and less complicated
In Lighthouse it is creating a AST for parsing the graphql request and your schema. It then afterwards passes all the directives and so on to figure out what you are trying to do. It also has to validate your query, to see if you can actually run it on the schema.
Depending on how you defined it in your application, there is a lot of steps it is passing through. However this can be reduced by multiple different ways, the parsing of your graphql schema can be cached, you could cache the result, use deferred fields (prob. wont speed up this example). You can read more about this in the performance section of the docs.
You are not specifying how your REST is setup, if you are using some kind of REST standard where it has to parse the data also. If you add more features, there is more code to run through, hence higher load speed.
As of Lighthouse v4, we have made significant performance increases by lazy-loading the minimally required fields and types from the schema. That turns out to bring about a 3x to 10x performance increase, depending on the size of your schema.
You probably still won't beat a single REST endpoint for such a simple query. Lighthouse will begin to shine on more heavily nested queries that join across multiple relationships.
Try enabling opcache on the server. This decreased my gql response time from 200ms to 20ms
To my understanding, Data Transfer Objects (DTOs) are typically smallish, flattish, behavior-less, serializable objects whose main advantage is ease of transport across networks.
GraphQL has the following facets:
encourages serving rich object graphs, which (in my head anyway) contradicts the "flattish" portion of DTOs,
lets clients choose exactly the data they want, which addresses the "smallish" portion,
returns JSON-esque objects, which addresses the "behavior-less" and "serializable" portions
Do GraphQL and the DTO pattern mutually exclude one another?
Here's what led to this question: We envision a microservices architecture with a gateway. I'm designing one API to fit into that architecture that will serve (among other things) geometries. In many (likely most) cases the geometries will not be useful to client applications, but they'll be critical in others so they must be served. However they're serialized, geometries can be big so giving clients the option to decline them can save lots of bandwidth. RESTful APIs that I've seen handling geometries do that by providing a "returnGeometry" parameter in the query string. I never felt entirely comfortable with that approach, and I initially envisioned serving a reasonably deep set of related/nested return objects many of which clients will elect to decline. All of that led me to consider a GraphQL interface. As the design has progressed, I've started considering flattening the output (either entirely or partially), which led me to consider the DTO pattern. So now I'm wondering if it would be best to flatten everything into DTOs and skip GraphQL (in favor of REST, I suppose?). I've considered a middle ground with DTOs served using GraphQL to let clients pick and choose the attributes they want on them, but I'm wondering if that's mixing patterns & technologies inappropriately.
I think it's worthwhile differentiating between 2 typical use cases for GraphQL, and a hidden 3rd use case which combines the first two.
In all 3 however, the very nature of a GraphType is to selectively decide which fields you want to expose from your domain entity. Sounds familiar? It should, that's what a DTO is. GraphQL or not, you do not want to expose the 'password' field on your Users table for example, hence you need to hide it from your clients one way or another.
This is enabled by the fact that GraphQL doesn't make any assumptions about your persistence layer and gives you the tools to treat your input types / queries as you see fit.
1. GraphQL endpoint exposed directly to clients (e.g. web, mobile):
In this use case you'd use any GraphQL client to talk to your graphql endpoint directly. The DTOs here are the actual GraphType objects, and are structured depending on the Fields you added to your exposed GraphTypes.
Internally, you would use field resolvers to transform your DTO to your domain entity and then use your repository to persist it.
DTO transformation occurs inside the GraphType's Field resolver.
GraphQL --> DTO --> Domain Entity --> Data Store
2. REST endpoint exposed to clients, which internally consumes a GraphQL endpoint:
In this use case, your web and mobile clients are working with traditional DTOs via REST. The controllers however are connecting to an internally-exposed GraphQL endpoint - as opposed to use case #1 - whose GraphTypes are an exact mapping of your domain entities, password field included!
DTO transformation occurs in the controller before calling the endpoint.
DTO --> Domain Entity --> GraphQL --> Data Store
3. Combining 1 and 2
This is is a use case for when you're shifting your architecture from one to the other and you don't want to break things for client consumers, so you leave both options open and eventually decommission one of them.
We are considering using GraphQL on top of a REST service (using the
FHIR standard for medical records).
I understand that the pattern with GraphQL is to aggregate the results
of multiple, independent resolvers into the final result. But a
FHIR-compliant REST server offers batch endpoints that already aggregate
data. Sometimes we’ll need à la carte data—a patient’s age or address
only, for example. But quite often, we’ll need most or all of the data
available about a particular patient.
So although we can get that kind of plenary data from a single REST call
that knits together multiple associations, it seems we will need to
fetch it piecewise to do things the GraphQL way.
An optimization could be to eager load and memoize all the associated
data anytime any resolver asks for any data. In some cases this would be
appropriate while in other cases it would be serious overkill. But
discerning when it would be overkill seems impossible given that
resolvers should be independent. Also, it seems bloody-minded to undo
and then redo something that the REST service is already perfectly
capable of doing efficiently.
So—
Is GraphQL the wrong tool when it sits on top of a REST API that can
efficiently aggregate data?
If GraphQL is the right tool in this situation, is eager-loading and
memoization of associated data appropriate?
If eager-loading and memoization is not the right solution, is there
an alternative way to take advantage of the REST service’s ability
to aggregate data?
My question is different from
this
question and
this
question because neither touches on how to take advantage of another
service’s ability to aggregate data.
An alternative approach would be to parse the request inside the resolver for a particular query. The fourth parameter passed to a resolver is an object containing extensive information about the request, including the selection set. You could then await the batched request to your API endpoint based on the requested fields, and finally return the result of the REST call, and let your lower level resolvers handle parsing it into the shape the data was requested in.
Parsing the info object can be a PITA, although there's libraries out there for that, at least in the Node ecosystem.
How do you prevent a nested attack against an Apollo server with a query such as:
{
authors {
firstName
posts {
title
author {
firstName
posts{
title
author {
firstName
posts {
title
[n author]
[n post]
}
}
}
}
}
}
}
In other words, how can you limit the number of recursions being submitted in a query? This could be a potential server vulnerability.
As of the time of writing, there isn't a built-in feature in GraphQL-JS or Apollo Server to handle this concern, but it's something that should definitely have a simple solution as GraphQL becomes more popular. This concern can be addressed with several approaches at several levels of the stack, and should also always be combined with rate limiting, so that people can't send too many queries to your server (this is a potential issue with REST as well).
I'll just list all of the different methods I can think of, and I'll try to keep this answer up to date as these solutions are implemented in various GraphQL servers. Some of them are quite simple, and some are more complex.
Query validation: In every GraphQL server, the first step to running a query is validation - this is where the server tries to determine if there are any serious errors in the query, so that we can avoid using actual server resources if we can find that there is some syntax error or invalid argument up front. GraphQL-JS comes with a selection of default rules that follow a format pretty similar to ESLint. Just like there is a rule to detect infinite cycles in fragments, one could write a validation rule to detect queries with too much nesting and reject them at the validation stage.
Query timeout: If it's not possible to detect that a query will be too resource-intensive statically (perhaps even shallow queries can be very expensive!), then we can simply add a timeout to the query execution. This has a few benefits: (1) it's a hard limit that's not too hard to reason about, and (2) this will also help with situations where one of the backends takes unreasonably long to respond. In many cases, a user of your app would prefer a missing field over waiting 10+ seconds to get a response.
Query whitelisting: This is probably the most involved method, but you could compile a list of allowed queries ahead of time, and check any incoming queries against that list. If your queries are totally static (you don't do any dynamic query generation on the client with something like Relay) this is the most reliable approach. You could use an automated tool to pull query strings out of your apps when they are deployed, so that in development you write whatever queries you want but in production only the ones you want are let through. Another benefit of this approach is that you can skip query validation entirely, since you know that all possible queries are valid already. For more benefits of static queries and whitelisting, read this post: https://dev-blog.apollodata.com/5-benefits-of-static-graphql-queries-b7fa90b0b69a
Query cost limiting: (Added in an edit) Similar to query timeouts, you can assign a cost to different operations during query execution, for example a database query, and limit the total cost the client is able to use per query. This can be combined with limiting the maximum parallelism of a single query, so that you can prevent the client from sending something that initiates thousands of parallel requests to your backend.
(1) and (2) in particular are probably something every GraphQL server should have by default, especially since many new developers might not be aware of these concerns. (3) will only work for certain kinds of apps, but might be a good choice when there are very strict performance or security requirements.
To supplement point (4) in stubailo's answer, here are some Node.js implementations that impose cost and depth bounds on incoming GraphQL documents.
graphql-depth-limit
graphql-validation-complexity
graphql-query-complexity
These are custom rules that supplement the validation phase.
A variation on query whitelisting is query signing.
During the build process, each query is cryptographically signed using a secret which is shared with the server but not bundled with the client. Then at runtime the server can validate that a query is genuine.
The advantage over whitelisting is that writing queries in the client doesn't require any changes to the server. This is especially valuable if multiple clients access the same server (e.g. web, desktop and mobile apps).
Example
In development, you write your queries as usual against your dev server which allows unsigned queries.
Then in your client build step in CI, each query is tagged with its cryptographic signature. This signature is sent by the client as a header to the server when making the request, along with the full GraphQL query string.
Your staging and production servers are configured to require a signed queries. They calculate the signature of the query received in the same way as the CI server did during the build. If the signatures don't match then they don't process the query.
Limitations:
not suitable for public facing APIs since the secret must be shared with developers
clients cannot dynamically build a GraphQL query at runtime using string interpolation, but I've never had a need for this and it is discouraged
For the Query cost limiting you could use graphql-cost-analysis
This is a validation rule which parses the query before executing it. In your GraphQL server you just have to assign a cost configuration for each field of your Schema Type Map you want.
Don't miss graphql-rate-limit 👌a GraphQL directive to add basic but granular rate limiting to your Queries or Mutations.
I am developing Sharepoint hosted app, and there is a situation where i need to get the data from 4 lists simultaneously, then use it later on. I am able to do it using CSOM. But performance wise what will be better CSOM or REST API. If rest API is the better approach then how can i do it.?
My approach for SharePoint-hosted add-in is to use
a. REST API when requesting:
Single Element / Single Collection retrieval (single List, single ListColletion, single ListItem, single ListItemCollection, single Field, single FieldCollection etc.)
Large Datasets
Two things to consider when using REST API:
i. I do prefer using sp.RequestExecutor.js to executeQueryAsync over $Ajax calls. Reason #1: developing addins that interacts with other Site Collections or sibling webs. Reason #2: your X-RequestDigest header is resolved natively.
ii. Choose wisely your odata value in the Accept: application/json; odata=? header. odata=verbose is, well, verbose, meaning that it returns A LOT of generally unuseful metadata information that slow down responses. odata=mininalmetadata is a good choice for when you need a single metadatata information. odata=nometadata is what you generally need. Note that the object returned varies. While in verbose mode: obj.body.d.results. For the two other methods, obj.body.value
b. I use JSOM API when I need to:
Request ==at once== more than one List or ListItem, or need to load into the context different elements.
Batch updates
References:
https://blogs.msdn.microsoft.com/brian_farnhill/2014/03/11/approaches-to-optimising-sharepoint-client-side-communication/
http://www.andrewconnell.com/blog/sharepoint-2013-csom-vs.-rest-...-my-preference-and-why
http://blog.mannsoftware.com/?p=1521
https://blogs.office.com/2014/08/13/json-light-support-rest-sharepoint-api-released/
http://www.odata.org/documentation/odata-version-2-0/overview/
https://msdn.microsoft.com/en-us/library/office/dn168907.aspx
http://www.vrdmn.com/2013/07/batch-operations-using-javascript.html
I invite you to read this article :
http://blog.mannsoftware.com/?p=1521
In my understanding, REST shows better performance. In time response time, it's about 30% shorter.
And how to dot it ?
With Ajax, it's quite easy. Here is an example which show how to use it :
http://blogs.msdn.com/b/nickpinheiro/archive/2015/01/30/build-a-sharepoint-hosted-app-to-access-list-data-in-your-host-web-using-the-rest-api-in-10-easy-steps.aspx