I am started learn graphql and use SpaceX api (https://api.spacex.land/graphql/)
I have theese query:
{
shipsResult(
limit: 5,
offset: 0,
find: {
type: "Cargo",
home_port: "Port Canaveral"
}) {
result {
totalCount
}
data {
id
name
type
home_port
}
}
}
I need select more than one value in home_port parameter, like array ["Port Canaveral", "Port of Los Angeles"]
What i shall do?
Related
I have an array of countries received from Apollo backend without an ID field.
export const QUERY_GET_DELIVERY_COUNTRIES = gql`
query getDeliveryCountries {
deliveryCountries {
order
name
daysToDelivery
zoneId
iso
customsInfo
}
}
`
Schema of these objects:
{
customsInfo: null
daysToDelivery: 6
iso: "UA"
name: "Ukraine"
order: 70
zoneId: 8
__typename: "DeliveryCountry"
}
In nested components I read these objects from client.readQuery.
What I want is to insert it to localStorage, read it initially and write this data to Apollo Client Cache.
What I've already tried to do:
useEffect(() => {
const deliveryCountries = JSON.parse(localStorage.getItem('deliveryCountries') || '[]')
if(!deliveryCountries || !deliveryCountries.length) {
getCountriesLazy()
} else {
deliveryCountries.map((c: DeliveryCountry) => {
client.writeQuery({
query: QUERY_GET_DELIVERY_COUNTRIES,
data: {
deliveryCountries: {
__typename: "DeliveryCountry",
order: c.order,
name: c.name,
daysToDelivery: c.daysToDelivery,
zoneId: c.zoneId,
iso: c.iso,
customsInfo: c.customsInfo
}
}
})
})
}
}, [])
But after execution the code above I have only one object in countries cache. How to write all objects without having an explicit ID, how can I do it? Or maybe I'm doing something wrong?
Lol. I just had to put the array into necessary field without iterating. writeQuery replaces all the data and not add any "to the end".
client.writeQuery({
query: QUERY_GET_DELIVERY_COUNTRIES,
data: {
deliveryCountries: deliveryCountries
}
})
This is my fist time creating an order. From what I understand you need to create a draft order - add products, price, email, notes etc. I am just creating a test query now to see how it works and it tells me "Add at least 1 product". I am trying to add a product, but I dont know how. I have been messing around and reading and cant figure it out.
This is my query:
mutation draftOrderCreate {
draftOrderCreate(input: {email: "123abc#hotmail.com"}) {
draftOrder {
id
order {
id
}
status
}
userErrors {
field
message
}
}
}
If anyone can give me an example on how to add products to this would be great. Thanks.
You can create an draft order like so:
mutation draftOrderCreate($items: DraftOrderInput!) {
draftOrderCreate(input: $items) {
draftOrder {
id
order {
id
}
status
}
userErrors {
field
message
}
}
}
query variables:
{
"items": {
"email": "123abc#hotmail.com",
"lineItems": [
{
"variantId": "gid://shopify/ProductVariant/32231002996788",
"quantity": 1
}
]
}
}
Or if you don't want to use query variables you can pass the whole object as the input:
mutation draftOrderCreate {
draftOrderCreate(input: {email: "123abc#hotmail.com", lineItems: [{variantId: "gid://shopify/ProductVariant/32231002996788", quantity: 1}]}) {
draftOrder {
id
order {
id
}
status
}
userErrors {
field
message
}
}
}
For the following query, in some objects in the results array, some of the requested fields might not be present in the response (for example photo or address), which causes the data of my useQuery to be undefined (without any error or warning).
people(xyz: { q: $q, offset: $offset, rows: $rows }) {
results {
uri <--- this is a field of type ID!
name
photo
address {
city
country
}
}
}
My fix is to specifically check if the field exists in the incoming data and provide a fallback value, i.e.: pass a type policy for Person to be {keyFields: false} and do this in the merge function:
newItem = {...item};
newItem.photo = item.photo ?? null;
newItem.address = item.address ?? {city: "", country: ""};
Is the reason for having to do this that there's no id field in the Person type (instead, uri is of type ID!)?
Can I handle this in a better way?
Found a better way on Apollo GraphQL's GitHub.
I'd still appreciate a solution where I don't have to go over each type's nullable field in turn, if there is one.
function nullable() {
// Create a generic field policy that allows any field to be null by default:
return {
read(existing = null) {
return existing;
},
};
}
new InMemoryCache({
typePolicies: {
Person: {
fields: {
photo: nullable(),
address: nullable(),
},
},
Address: { // If there's the case of either city or country missing
fields: {
city: nullable(),
country: nullable(),
}
}
},
})
Essentially, I have users who can have payments, and theses payments can be filtered with an arg.
Here is my schema, simplified :
type User {
payments($filter: PaymentsFilter): PaymentsConnection,
}
enum PaymentsFilter {
MissingDetails,
}
type PaymentsConnection {
edges { ... }
pageInfo { ... }
}
type Payment {
id
description
}
The MissingDetails filter returns only the Payment who are missing a description.
For example, if I have 2 Payment :
[
{ id: 1, description: null },
{ id: 2, description: 'A great payment' },
]
A query as such :
query {
loggedUser {
payments(filter: MissingDetails) {
...
}
}
}
Would return only the first Payment, with id: 1.
I want to achieve an UpdatePaymentMutation, that would update the payment and depending on if the description is set or not in the response, I would RANGE_ADD it to the connection with the filter MissingDetails, or RANGE_DELETE it.
How can I achieve that ?
Let's assume a type hierarchy of Customer -(hasMany)-> Orders -(hasMany)-> OrderLines
Something like this:
Customer {
Name
Orders [
{
OrderId
Date
OrderLines [
{
ItemCount
ItemName
}
]
}
]
}
I want to query for this whole tree, and filter on properties at any level in the tree.
For instance: Get all customers who ordered 'gizmos'.
This is what I tried: at each level of the hierarchy, I specify optional arguments that would filter based on the properties available at that level:
Customer (Name) {
Name
Orders (OrderId, Date) [
{
OrderId
Date
OrderLines (ItemCount, ItemName) [
{
ItemCount
ItemName
}
]
}
]
}
GraphQL needs me to define how to resolve each type in the hierarchy, so when resolving, I filter based on the arguments in the query.
But what if I only specify a filter at a deep level? e.g. ItemName : 'gizmo'
Assuming there's only one order line in the system containing a gizmo, I would expect to get a response like this:
[{
Name: "cust12",
Orders [{
OrderId: "ade32f",
OrderLines: [{
ItemCount: 50000, //customer really likes gizmos
ItemName: "gizmo"
}]
}]
}]
But what I actually get is all customers (no filter there), all their orders (no filter there) and all order items, mostly empty (the items inside are filtered).
[{
Name: "cust12",
Orders [
{
OrderId: "aaaaaa",
OrderLines: [ ]
},
{
OrderId: "ade32f",
OrderLines: [{
ItemCount: 50000,
ItemName: "gizmo"
}]
},
{
OrderId: "bbbbbb",
OrderLines: [ ]
},
{
OrderId: "cccccc",
OrderLines: [ ]
}
]
},
{
Name: "cust345",
Orders [
{
OrderId: "eeeeee",
OrderLines: [ ]
},
{
OrderId: "ffffff",
OrderLines: [ ]
}
]
}]
GraphQL calls the resolvers top-down:
- get all (filtered) clients
- for each of these get all (filtered) orders
- for each of those get all (filtered) order lines
Because of the top-down nature of calling the resolvers, I get a lot more data than I bargained for.
How should I approach this?
Relation filters
This is actually a more complex topic than it first seems. The problem is that your current filter condition expresses
get all customers, but only include items named 'gizmo'
but what you really want is
get all customers that are related to at least one item named 'gizmo'
get all customers that are related to at least one item named 'gizmo'
An elegant solution for this problem is the addition of relation filters to the schema. In your case, it could look like this:
query {
Customer(filter: {
orders_some: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
}) {
Name
Orders {
OrderId
Date
OrderLines {
ItemCount
ItemName
}
}
}
}
Using
orders_some: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
we only fetch customers that are indirectly related to an item named 'gizmo', exactly what we wanted.
Two more examples:
get all customers that are not related to any item named 'gizmo'
query {
Customer(filter: {
orders_none: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
}) {
Name
Orders {
OrderId
Date
OrderLines {
ItemCount
ItemName
}
}
}
}
get all customers where all their orders contain some order line with an item named 'gizmo'
query {
Customer(filter: {
orders_every: {
orderLines_some: {
item: {
itemName: "gizmo"
}
}
}
}) {
Name
Orders {
OrderId
Date
OrderLines {
ItemCount
ItemName
}
}
}
}
The every, some and none relation filters are an essential part of the Graphcool APIs - you can read more here.