I am making an application that shows information about different users, which is taken from third party API. I save this information in my own format with multiple tables in PostgreSQL to keep track of any changes to the data and provide history of changes (third party API only provides current data).
I want to use GraphQL, specifically Postgraphile to simplify backend development. But there is one use case which I can't find a way to implement with Postgraphile. Here is what I want to implement:
User wants to see an updated information
GraphQL mutation query is sent to the server, something like this:
mutation UpdateUserData($userid: Int) {
updateUser(id: $userid) {
field1,
field2,
relatedObjects {
field3,
filed3
}
}
}
Server makes an API request to third party server, processes data, makes some calculations and updates the database
Requested fields are returned to client
I know that this type of custom mutations can be implemented with database functions like PL/pgSQL or PLV8, but they can't make http requests and I already have most of the logic for data processing in Typescript, so would like to use it.
Is there a way to create a custom mutation that will call JavaScript function which has access to Node.js modules, interfaces and classes that I already created?
One solution that I think will work:
Call REST endpoint on my server, like /update_user?id=$userid
User data is loaded from third party API and database is updated
Client receives response, like Update successful
Normal GraphQL query is called to get the data
Is there a better way of satisfying this use case?
This part is a bit hidden in the documentation, but the easiest way to add mutations written in JavaScript is the makeExtendSchemaPlugin.
Here you can define type definitions in SDL and implement resolvers in JS.
Related
I am attempting to write an Azure CosmosDB integration (Core SQL Api) that integrates with an external service to provide some of the query data. As an example, I need a query made on Cosmos DB to convert some of the data returned (e.g. ID's) by the query into real data by calling an external service via a REST API. This should only happen when querying certain columns.
I initially investigated using a JS stored procedure and/or a UDF to make this external call, but the JS environment seems to be extremely limited and doesn't provide any way to make external calls. I then tried using this https://github.com/Oblarg/cosmosdb-storedprocs-ts repository, which uses webpack to bundle all of node.js into the stored procedure, allowing node modules to be used in stored procedures. Whilst this does allow some node modules to be used, whenever I try and use "https", "fetch", or "axios" modules to make an HTTP GET request I get errors (the same code works fine in a normal node environment, but I'm not a JS expert and can't seem to work past these errors). After a day of attempts it seems like the stored procedure approach is not possible.
Is this the case or is there some way of making HTTP GET requests from a JS stored procedure? If not possible with stored procedures, are there any other techniques to achieve the requirement of reading data from a remote API when querying cosmos DB?
Thanks
There is no way to achieve this from CosmosDB directly, for queries you also cannot use the change feed as the document dont change, so really your only option is to use a function or some preprocessor app to handle it, as you say its not ideal but there is no other solution here. If it was an insert or an update then change feed would allow you to do this but for plain queries its not possible.
I'm building a GraphQL server from scratch with an API backend, replacing a REST API server. Currently some requests in the existing API server, mainly Create / Update requests that will be mutations in GraphQL, include a request id which is used by the client. This request id is metadata about the request itself not part of the domain resource.
My question is how to model / include request metadata in GraphQL queries and mutations? My only solution so far is to make a request Type, which other types could include as a field so the request data can be included in the mutation return type. However i do not like this approach as it mixes request data into my domain types and this very much feels against the ethos of GraphQL. Is there an accepted way to pass 'arbitrary' e.g. non-domain type data in the response of a query or mutation in GraphQL?
Example - what i would like to avoid:
type UserType {
id: ID
name: String
request: RequestType // mixing request data in with domain type of User
}
type RequestType {
id: ID
}
Update
For others interested in this problem, based on the responses here I have decided that the GraphQL extensions key is good option for adding arbitrary data to a GraphQL response without the data becoming part of your data Graph. In Express-GraphQL, docs on adding an extensions key to responses can be found here: https://github.com/graphql/express-graphql#providing-extensions. A good overview of extensions here: https://marmelab.com/blog/2017/09/06/dive-into-graphql-part-iii-building-a-graphql-server-with-nodejs.html#server-logging
That said, if the request metadata is conceptually part of the domain data then following Kashif's suggestion below of creating ResponseTypes that embed domain Types might be the correct approach.
Since GraphQL was designed to be protocol agnostic, you should use your chosen protocol's metadata pattern. If you're using HTTP, you should pass headers. If you're using WS/STOMP/MQTT/AMQP you can include metadata in each frame.
Alternatively GraphQL has an extensions protocol. You could add a request-id to your responses in the extensions object. Apollo uses extensions for caching, telemetry, etc.
We've been using GraphQL in production for about a year, we made the mistake of adding metadata into GraphQL and it gets hard to manage. Don't lose out on the benefits from the features of the protocol you're using.
This kind of meta elements are usually passed in HEADERS with each request. And then you can handle those in your GraphQL server as you like
For eg.
//Request Headers
...
X-Request-Id: <Your_Request_Id>
...
Updates
Headers work both ways so there shouldn't be any problems using them on client too. Pull them out of the response whenever you need.
However if you really want the requestId in your mutation response then that IS a part of your domain. And there is nothing wrong in have a custom response type, Many existing GraphQL apis do have a custom response type like LoginResponse, RegisterResponse which then wraps around your domain objects but also include extra stuff in meta fields
I have an nodejs application having some REST APIs and is working well.
One of the API, say /billinginfo POST, receives a client code and a piece of data via JSON format, and it will make a API call, to another service, say /client GET, that returns country of the client, and it then inserts the data into the database.
I later found out that, for performance improvements, I can actually load all the client's countries into a HashTable 1st with key being the client code with one API call that return all the clients and avoid calling that /client GET API many times and will look into the HashTable instead.
My question is now, where do I normally put codes loading the HashTable to be used by the /billinginfo POST API?
Update:
The country and the client info is on AWS AURORA in the cloud of another system and /billinginfo POST is writing to a on-premise MS SQL database hence I must make calls to /client GET API.
I think what you can do is put the data of countries in your database and put the proper indexing, and after that query from your database.It'll be quicker than calling third party API.
As the title suggest. I'm trying to figure out where I should cache data in my node.js application.
I'm using a express.js and controllers to handle the routes in the application. The controller for a particular route will get data via the model layer using REST API and then it uses handlebars for the view rendering on the server.
For this particular route, I'm displaying a menu and the data I have got for this has been done in the model and a remote REST call.
When the user select different items in the menu, I do not want to make a new REST call to get the same data for the menu again, I just need to get the data for this menu once since it will never change.
I need to find out a way to cache it, but do not know where I should implement it?
Best Regards
You could just cache the response from the REST API or DB lookup using a memory-store like Redis or Memcached, both have good modules available on npm - (Redis, memcached).
You would need to attempt to fetch the data from the memory-store (in your controller), if no matching data was found, you would make the request to the API or database to get the data, and then store it in your chosen memory-store so future requests will hit the cache.
note: There are also some pure JavaScript caches available such as memory-cache or lru-cache if you don't want to add an additional application.
In my Angular app, I want to display a table which contains the following
a) URL
b) Social share counts divided by different social networks
Using Sails.js, I already have the api created for the URL when the results show up, I can display the URL now I'm confused how to get the appropriate social counts showing right besides
Here's the API I'm using: https://docs.sharedcount.com/
by itself, I can see the JSON it produces
But here are my questions:
Should I create a new api (model/controller) for social count data or include it in my model where I have the 'url' action defined?
If I create a new api or include the social_counts as an action in the current, what would my JSON query look like? to retrieve the URL's, I'm using default API blueprint that Sails provides, so:
http://www.example.com/url/find?where={"title":{"contains":"mark"}}
Struggling a bit in terms of the thought process, would be great to get input on this
It depends on your app. is your app will store that data or just consume it? If it need to store, of course you need the API. In purpose for modification or aggregating the data for example.
No, you can't do that. That shortcut method only works if you have the data in your database and let the Sails Waterline ORM and Blueprint API served it.
Perhaps, if you only need to consume the data from that Sharedcount API, you didn't need to use Sails as a backend, in this context. Just use Angular as a client of that API. Except if you need to modify the data first and store it in your own database, so Sails will helps with it's Waterline ORM and Blueprint API.