1

Bear with me, I will explain this the best I can. Please let me know if more information is needed, I am trying to keep this as brief as possible.

I am using Apollo Server and the 'apollo-datasource-rest' plugin to access a REST API. When attempting to get the property values from a nested array of objects I get a null response for each field/property. In addition, the array being queried is only showing a single iteration when multiple are available.

The field in question is the 'cores' field within the Rocket type, i.e., launch.rocket.firstStage.cores

I have attempted various ways of mapping through 'cores' (thinking this was what it wanted) with no success.

To keep things short and simple I'm only including the code for the specific issue. All other parts of the query are operating as expected.

You can view the API response I am hitting here: https://api.spacexdata.com/v3/launches/77

schema.js

const { gql } = require('apollo-server');

const typeDefs = gql`
  type Query {
    singleLaunch(flightNumber: Int!): Launch
  }

  type Launch {
    flightNumber: Int!
    rocket: Rocket
  }

  type Rocket {
    firstStage: Cores
  }

  type Cores {
    cores: [CoreFields]
  }

  type CoreFields {
    flight: Int
    gridfins: Boolean
    legs: Boolean
    reused: Boolean
    landingType: String
    landingVehicle: String
    landingSuccess: Boolean
  }
`;

module.exports = typeDefs;

Data Source - launch.js

const { RESTDataSource } = require('apollo-datasource-rest');

class LaunchAPI extends RESTDataSource {
  constructor() {
    super();
    this.baseURL = 'https://api.spacexdata.com/v3/';
  }

  async getLaunchById({ launchId }) {
    const res = await this.get('launches', {
      flight_number: launchId,
    });
    return this.launchReducer(res[0]);
  }

launchReducer(launch) {
    return {
      flightNumber: launch.flight_number || 0,
      rocket: {
        firstStage: {
          cores: [
            {
              flight: launch.rocket.first_stage.cores.flight,
              gridfins: launch.rocket.first_stage.cores.gridfins,
              legs: launch.rocket.first_stage.cores.legs,
              landingType: launch.rocket.first_stage.cores.landing_type,
              landingVehicle: launch.rocket.first_stage.cores.landing_vehicle,
              landingSuccess: launch.rocket.first_stage.cores.landing_success,
            },
          ],
        },
    };
  }
}

module.exports = LaunchAPI;

resolvers.js

module.exports = {
  Query: {
    singleLaunch: (_, { flightNumber }, { dataSources }) =>
      dataSources.launchAPI.getLaunchById({ launchId: flightNumber }),
  },
};

Query

query GetLaunchById($flightNumber: Int!) {
  singleLaunch(flightNumber: $flightNumber) {
    flightNumber
    rocket {
      firstStage {
        cores {
          flight
          gridfins
          legs
          reused
          landingType
          landingVehicle
          landingSuccess
        }
      }
    }
  }
}

Expected Result

{
  "data": {
    "singleLaunch": {
      "flightNumber": 77,
      "rocket": {
        "firstStage": {
          "cores": [
            {
              "flight": 1,
              "gridfins": true,
              "legs": true,
              "reused": true,
              "landingType": "ASDS",
              "landingVehicle": "OCISLY",
              "landSuccess": true,
            },
            {
              "flight": 1,
              "gridfins": true,
              "legs": true,
              "reused": false,
              "landingType": "RTLS",
              "landingVehicle": "LZ-1",
              "landSuccess": true
            },
            {
              "flight": 1,
              "gridfins": true,
              "legs": true,
              "reused": false,
              "landingType": "RTLS",
              "landingVehicle": "LZ-2",
              "landSuccess": true
            },
          ]
        }
      },
    }
  }
}

Actual Result (Through GraphQL Playground)

{
  "data": {
    "singleLaunch": {
      "flightNumber": 77,
      "rocket": {
        "firstStage": {
          "cores": [
            {
              "flight": null,
              "gridfins": null,
              "legs": null,
              "reused": null,
              "landingType": null,
              "landingVehicle": null,
              "landingSuccess": null
            }
          ]
        }
      },
    }
  }
}

Any suggestions as to what I am doing wrong here would be greatly appreciated. Again, let me know if more information is needed.

Thank you!

2
  • from response ... it looks like there shouldn't be res[0] but only res - maybe api specs changed - console.log(res) ? Commented May 4, 2019 at 0:38
  • @xadm - Removing the brackets from res will result in the response being undefined. The frustrating part is the data prints to the console, just fails at the query. I am looking into the query and resolver today as the possible cause. Commented May 6, 2019 at 15:31

1 Answer 1

1

Missing base url

There should be

await this.get( this.baseURL + 'launches'


IMHO there should be a map used within launchReducer to return an array, sth like:

launchReducer(launch) {
    return {
      flightNumber: launch.flight_number || 0,
      rocket: {
        firstStage: {
          cores: launch.rocket.first_stage.cores.map(core => ({
            flight: core.flight,
            gridfins: core.gridfins,
            legs: core.legs,
            landingType: core.landing_type,
            landingVehicle: core.landing_vehicle,
            landSuccess: core.land_success,
          })),
        },
      },
    };
}  

.map(core => ({ is for returning object [literal], the same as/shorter version of .map(core => { return {

Sign up to request clarification or add additional context in comments.

5 Comments

To my knowledge RESTDataSource appends whatever is passed to this.get() to the BaseURL for me. But I did try your solution anyways, and it provided no change. Data from the API is returning successfully to other parts of the query. As I stated in my question this is only 1 part of a larger query, of which all other data is returned correctly. The problem is this particular nested array 'cores' is not returning any values. However, I have found if I provide an index to the array within the reducer it will return a value. But I cannot map within the reducer, so I am looking into that now.
try firstStage: { cores: { - without [
I have tried that in the past, doing so returns: "Expected Iterable, but did not find one for field Cores.cores." Which makes sense I suppose, since 'cores' is an array.
If I provide an index to any of the properties of cores, I DO get a response. So, flight: launch.rocket.first_stage.cores[1].flight returns a value. I am starting to think my resolver and/or reducer is not written correctly for what I am trying to accomplish.
I accidentally put my comment in an edit summary. @xadm YES! We were both on the same track and your answer pushed me into the home stretch. I edited your solution ever-so-slightly as the return from the map was causing an error. I will mark this as the correct answer. THANK YOU again for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.