I know you can set arguments in a schema to default values but is it possible to make the argument limit argument completely optional in my GraphQL Schema?
Right now it seems like when I hit this without specifying a limit I think that's why I get Int cannot represent non-integer value: undefined
const schema = buildSchema(`
companies(limit: Int): [Company]
...)
I want to be able to skip the limit so that it gets all companies.
In JS, I call it like this:
query: `query {
companies(limit: ${limit}) {
...
but sometimes I don't want to specify a limit. So what is happening is the client is sending crafters(limit: undefined) and it's probably trying to convert that to Int. I'm not sure how to not send limit in and how to make that entire param optional.
(I also read that from the client I should be instead specifying the arguments as variables like query($limit: Int) { companies(limit: $limit) { I guess from my client, from JS? If so how would I send in my limit JS variable into that?
Arguments in GraphQL are nullable (i.e. optional) by default. So if your type definition looks like this:
companies(limit: Int): [Company]
there is nothing else you need to do to make limit optional -- it already is. If you wanted to make limit required, you would make it non-nullable by appending a ! to the type like this:
companies(limit: Int!): [Company]
The errors you are seeing are unrelated to the type of the limit argument. The issue is with the query that you're sending, which based on the error messages, looks something like this:
query ($limit: Int){
companies (limit: undefined) {
# ...
}
}
There's two issues here: One, you are defining a variable ($limit) that you never actually use inside the query (as indicated by the second error). Two, you are setting the limit to undefined, which isn't a valid literal in GraphQL.
Instead of using string interpolation, you should use variables to pass any dynamic values to your query. For example:
query ($limit: Int){
companies (limit: $limit) {
# ...
}
}
If the variable is nullable (notice we used Int instead of Int!), then it can be omitted from the request entirely, effectively making the value of the argument undefined server-side. It's unclear how you're sending your requests to the server, but assuming you're not using some client library, you can check the documentation here for how to structure your request. Otherwise, check your library's documentation for how to correctly use variables with your query.
Below is an example of how you could define a query on client and pass non-required argument. Not sure about your client-side config, but you may want to use a lib like graphql-tag to convert string to AST.
const GET_COMPANIES = gql`
query Companies($limit: Int) {
companies(limit: $limit) {
... // return fields
}
}
`;
Related
So i have a method that searches for anime by name, API is graphQL.
Here's the important part of the query
const searchQuery = this.state.searchString;
var query = `query Search{
# the rest of the query omitted for brevity
media(type:ANIME, search: ${searchQuery} ){
# ...
}
`
I'm getting two types of errors in response, first is when search string consists of multiple words separated by spaces - "Syntax Error: Expected :, found )"
Second when i search for single word - "Field "media" argument "search" requires type String, found naruto."
What is the problem here?
You can see full code here - https://github.com/red4211/react-anime-search , app deployed to github pages, search API response goes to console - https://red4211.github.io/react-anime-search/
The issue is that given some query like "naruto", your current code results in the following text:
media(type:ANIME, search: naruto ) {
This is not valid syntax since String literals should be surrounded by double quotes (").
Don't use string interpolation to provide dynamic values to the query. These should always be expressed as variables and included as a separate object inside your request alongside query.
You need to define the variable as part of your operation, providing the appropriate type
var query = `query Search ($searchQuery: String!) {
then you can use the variable anywhere inside the operation:
media(type:ANIME, search: $searchQuery) {
Now just pass the variable value along with your request.
body: JSON.stringify({
query,
variables: {
searchQuery,
}
})
Note that the variable name is prefixed with a $ inside the GraphQL document, but outside of it, we don't do that.
media() looks like a function, so in that case the correct syntax would be:
media(type="ANIME", search=searchQuery)
or if the argument of media() is an object
media({type: "ANIME", search: searchQuery})
Also, you don't need to use ${} around searchQuery since searchQuery is already a string. The usage for that would be something like
`${searchString}` or `foo${searchString}bar`
using the `` around the ${} utility to represent a string and its variable inside the string literal.
Hope it helps!
I am trying to fetch first five items of a set. My query is following:
query sequence($id: String) {
sequence(id: $id) {
items(first:1) {
content
}
}
}
How ever, I get response
"Unknown argument \"first\" on field \"items\" of type \"Sequence\"."
As far as I understood from the docs this is how I am supposed to make query if I want to get a limited amount of items back.
Do I need to define the argument somewhere in the schema? How do I limit the amount of returned items properly?
All field arguments need to be defined in the schema, the default behaviour is for a field to accept no arguments.
You can define a first argument in your items field in your schema using syntax like this:
type Sequence {
items(first: Int): [Item]
}
(See: Example No. 120 in the spec.)
I would like to be able to have the formatting.formatValue function convert undefined into null.
But there does not appear to be a way that I can set the default function from the initOptions given to pg-promise as pgFormatting is a boolean, format value wants it as an argument. But the library does not appear to pass it for normal queries.
vitaly-t wrote
But i'm not sure how much value it would add, since you do not have access to formatting options from query methods.
And that is true. But I kind of just want to set a default of null for all missing values being formatted into queries. Partial does not mater I don't use it?
Using coalesce to have "optional" values in some of the queries, to default not set variables anyway.
Example:
UPDATE sometable SET value = COALESCE(${value}, value)
How can I stop getting the "Property doesn't exist Error?
I think that I need a way to pass a value to this options for all calls to the format.
if ('default' in options) {
const d = options.default, value = typeof d === 'function' ? d.call(obj, v.name, obj) : d;
return formatValue(value, v.fm, obj);
}
Related issue that led to creation of options.default.
https://github.com/vitaly-t/pg-promise/issues/173
I can't over-ride the format value function as it is added as a non configurable read only property.
Do I just have to bite the bullet and put the variables in as null everywhere I want them to be optional...
I kind of just want to set a default of null for all missing values being formatted into queries...
Here's your formatting function for this, if you want to format queries manually:
function format(query, values) {
return pgp.as.format(query, values, {'default': null});
}
And for automatically generated queries within the helpers namespace, you would provide the value for property def, as per the Column API.
Other than that, the query methods make use of the format function on their own, so you cannot override that, neither you should, it is generally not needed, if you make the right use of the library's API, i.e. if you can give me a specific example of where you think you need it, then I can advise you of the better approach that avoids it.
One other approach - method helpers.concat can consume the formatting options, as it implements a specific case of joining queries.
I am using Breezejs in 'NoDB' mode, meaning I write my metadata by hand. When I create a Breeze query with OData parameters I add a filter by id, say
new breeze.Predicate('iD', datacontext.breeze.FilterQueryOp.Equals, myId)
The var myId is indeed a GUID value (though it's defined as a String), but in my DB and in both my server-side and client-side model it's a string (I can't change the DB structure). the property definition in my metadata model is
dataProperties: {
...
iD: { dataType: DataType.String },
...
}
(I know the property name looks weird, but I have to use this syntax since I have the breeze.NamingConvention.camelCase.setAsDefault() on my datacontext, and the property's name on the DB is ID uppercased)
When I execute the query I see that the corresponding oData filter option in the WebAPI url is like
$filter=ID eq guid'65BEB144-5C0C-4481-AC70-5E61FDAA840D'
which leads me to this server error: No coercion operator is defined between types 'System.Guid' and 'System.String'.
Is there a way to disable this automatic 'parsing' of GUIDs and leave them as strings?
I have temporarily solved this by removing the parsing directly inside breeze's source code so that my webAPI call would look like
$filter=ID eq '65BEB144-5C0C-4481-AC70-5E61FDAA840D'
but I don't like this solution and I would be glad if there was a better one, like parametrize this behaviour in some way. I didn't find anything about this on Breeze's official website.
Breeze uses its metadata to determine that datatype of each property in a query and then uses this information to generate the correct OData filter. So your metadata definition of ID as a string should be correct.
However, in order to perform this operation breeze needs to know the EntityType of your query. For example in the following query
var q = EntityQuery.from("Foo").where(....)
breeze needs to know the EntityType that "Foo" ( a resourceName) corresponds to. Once it has the entity type it can correctly format any filters for specific properties of this entityType. If breeze does not have 'EntityType', then it falls back to guessing about the datatype of each property. In your case, its guessing that the datatype is a 'Guid'
So the fix is to either tell the query directly about the EntityType that you are querying
var q = breeze.EntityQuery.from("Foo).where(....).toType(FoosEntityType);
or you can handle it more globally via via the MetadataStore.setEntityTypeForResourceName method.
breeze.MetadataStore.setEntityTypeForResourceName("Foo", FoosEntityType);
var q = breeze.EntityQuery.from("Foo).where(....); // your original query
How do you fix a names mismatch problem, if the client-side names are keywords or reserved words in the server-side language you are using?
The DOJO JavaScript toolkit has a QueryReadStore class that you can subclass to submit REST patterned queries to the server. I'm using this in conjunction w/ the FilteringSelect Dijit.
I can subclass the QueryReadStore and specify the parameters and arguments getting passed to the server. But somewhere along the way, a "start" and "count" parameter are being passed from the client to the server. I went into the API and discovered that the QueryReadStore.js is sending those parameter names.
I'm using Fiddler to confirm what's actually being sent and brought back. The server response is telling me I have a parameter names mismatch, because of the "start" and "count" parameters. The problem is, I can't use "start" and "count" in PL/SQL.
Workaround or correct implementation advice would be appreciated...thx.
//I tried putting the code snippet in here, but since it's largely HTML, that didn't work so well.
While it feels like the wrong thing to do, because I'm hacking at a well tested, nicely written JavaScript toolkit, this is how I fixed the problem:
I went into the DOJOX QueryReadStore.js and replaced the "start" and "count" references with acceptable (to the server-side language) parameter names.
I would have like to handled the issue via my PL/SQL (but I don't know how to get around reserved words) or client-side code (subclassing did not do the trick)...without getting into the internals of the library. But it works, and I can move on.
As opposed to removing it from the API, as you mentioned, you can actually create a subclass with your own fetch, and remove start/count parameters (theoretically). Have a look at this URL for guidance:
http://www.sitepen.com/blog/2008/06/25/web-service-data-store/
Start and count are actually very useful because they allow you to pass params for the query that you can use to filter massive data sets, and it helps to manage client-side paging. I would try to subclass instead, intercept, and remove.
Is your pl/sql program accessed via a URL and mod_plsql? If so, then you can use "flexible parameter passing" and the variables get assigned to an array of name/value pairs.
Define your package spec like this...
create or replace package pkg_name
TYPE plsqltable
IS
TABLE OF VARCHAR2 (32000)
INDEX BY BINARY_INTEGER;
empty plsqltable;
PROCEDURE api (name_array IN plsqltable DEFAULT empty ,
value_array IN plsqltable DEFAULT empty
);
END pkg_name;
Then the body:
CREATE OR REPLACE PACKAGE BODY pkg_name AS
l_count_value number;
l_start_value number;
PROCEDURE proc_name (name_array IN plsqltable DEFAULT empty,
value_array IN plsqltable DEFAULT empty) is
------------
FUNCTION get_value (p_name IN VARCHAR) RETURN VARCHAR2 IS
BEGIN
FOR i IN 1..name_array.COUNT LOOP
IF UPPER(name_array(i)) = UPPER(p_name) THEN
RETURN value_array(i);
END IF;
END LOOP;
RETURN NULL;
END get_value;
----------------------
begin
l_count_value := get_value('count');
l_start_value := get_value('start');
end api;
end pkg_name;
Then you can call pkg_name.api using
http://server/dad/!pkg_name.api?start=3&count=3