Code Monkey home page Code Monkey logo

fullstack-tutorial's Introduction

ARCHIVED

This repo was archived on August 23, 2023. This repo was a companion to the Apollo Fullstack Tutorial, which is now a deprecated course and no longer maintained. If you're looking to learn GraphQL basics with Apollo, check out the Lift-off series.

Apollo tutorial

This is the fullstack app for the Apollo tutorial. ๐Ÿš€

File structure

The app is split out into two folders:

  • start: Starting point for the tutorial
  • final: Final version

From within the start and final directories, there are two folders (one for server and one for client).

Installation

To run the app, run these commands in two separate terminal windows from the root:

cd final/server && npm i && npm start

and

cd final/client && npm i && npm start

fullstack-tutorial's People

Contributors

abernix avatar adokce avatar benjamn avatar borekb avatar cheapsteak avatar dependabot[bot] avatar hwillson avatar igolopolosov avatar itshallrun avatar jakedawkins avatar jgarrow avatar jpvajda avatar justinanastos avatar kwdowik avatar mabuyo avatar mannyluvstacos avatar martinbonnin avatar peggyrayzis avatar rkoron007 avatar smyrick avatar stemmlerjs avatar trevorblades avatar unicodeveloper avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fullstack-tutorial's Issues

What is the license?

Hi,

What is the license on the tutorial code? I am asking, because I'd like to port it to a Vue (more like Quasar Framework) version. Would that be ok?

Scott

Why is it necessary to inject store/models via constructor in UserAPI

Instead of injecting via constructor can we directly import the required model or there is some significance of using this way.

fullstack-tutorial/final/server/src/datasources/user.js

class UserAPI extends DataSource {
       constructor({ store }) {
         super();
         this.store = store;
       }
}

Fix failing snapshots in final

Snapshots in final are currently failing on master

I couldn't find the resolver for Rocket

Queries
โœ• fetches list of launches (37ms)
โœ“ fetches single launch (24ms)
Mutations
โœ“ returns login token (15ms)
โœ• books trips (13ms)

โ— Queries โ€บ fetches list of launches

expect(value).toMatchSnapshot()

Received value does not match stored snapshot "Queries fetches list of launches 1".

- Snapshot
+ Received

@@ -1,26 +1,10 @@
  Object {
-   "data": Object {
-     "launches": Object {
-       "cursor": "1143239400",
-       "hasMore": false,
-       "launches": Array [
-         Object {
-           "id": "1",
-           "isBooked": true,
-           "mission": Object {
-             "missionPatch": "https://images2.imgbox.com/40/e3/GypSkayF_o.png",
-             "name": "FalconSat",
-           },
-           "rocket": Object {
-             "fullName": "Falcon 1",
-           },
-         },
-       ],
-     },
-   },
-   "errors": undefined,
+   "data": undefined,
+   "errors": Array [
+     [ValidationError: Cannot query field "fullName" on type "Rocket". Did you mean "name"?],
+   ],
    "extensions": undefined,
    "http": Object {
      "headers": Headers {
        Symbol(map): Object {},
      },

  87 |     const {query} = createTestClient(server);
  88 |     const res = await query({query: GET_LAUNCHES});
> 89 |     expect(res).toMatchSnapshot();
     |                 ^
  90 |   });
  91 |
  92 |   it('fetches single launch', async () => {

  at Object.toMatchSnapshot (src/__tests__/integration.js:89:17)

โ— Mutations โ€บ books trips

expect(value).toMatchSnapshot()

Received value does not match stored snapshot "Mutations books trips 1".

- Snapshot
+ Received

@@ -1,9 +1,9 @@
  Object {
-   "data": null,
+   "data": undefined,
    "errors": Array [
-     [GraphQLError: Cannot return null for non-nullable field TripUpdateResponse.failure.],
+     [ValidationError: Cannot query field "failure" on type "TripUpdateResponse".],
    ],
    "extensions": undefined,
    "http": Object {
      "headers": Headers {
        Symbol(map): Object {},

  153 |       variables: {launchIds: ['1', '2']},
  154 |     });
> 155 |     expect(res).toMatchSnapshot();
      |                 ^
  156 |   });
  157 | });
  158 |

  at Object.toMatchSnapshot (src/__tests__/integration.js:155:17)

โ€บ 2 snapshots failed.
Snapshot Summary
โ€บ 2 snapshots failed from 1 test suite. Inspect your code changes or run npm test -- -u to update them.

Can we remove the final folder from the starting code

Hi there,

I was going through the tutorial, which I think is great, but I think I'm spending a lot of time making sure I'm in the right file when starting to edit. We might want to remove the final folder and make it maybe a branch.

The final code is not that useful to compare with an in-progress version either since much changes when you add features in further steps on the tutorial.

CircleCI failing for client due to missing `&&` in configuration

reference

Within configuration for CircleCI for client, tests are failing due to the following:

cd final/client npx apollo client:check

&& should be added as such:

cd final/client && npx apollo client:check

was able to reproduce locally:

roboto @ ~/dev/fullstack-tutorial
masterโ””โ”€ $ cd final/client npx apollo client:check
bash: cd: too many arguments
roboto @ ~/dev/fullstack-tutorial
masterโ””โ”€ $ cd final/client && npx apollo client:check
^C.................] \ fetchMetadata: sill resolveWithNewModule [email protected] checking installable status
roboto @ ~/dev/fullstack-tutorial/final/client
masterโ””โ”€ $ 

Proving out fix.

@cheapsteak, would you have access to make this fix?

Some improvement suggestions for newbie reading the client tutorials (section 5 to 8)

https://www.apollographql.com/docs/tutorial/client.html#react-apollo

  • no react and react-dom imports
  • where did Pages component came from?

https://www.apollographql.com/docs/tutorial/queries.html#fragments

  • LAUNCH_TILE_DATA should be above GET_LAUNCHES
  • please mention src/pages/launch.js

https://www.apollographql.com/docs/tutorial/mutations.html#authenticate

  • where did resolver and typeDefs came from?

https://www.apollographql.com/docs/tutorial/local-state.html#local-query

  • where did injectStyles() came from?

https://www.apollographql.com/docs/tutorial/local-state.html#virtual-fields

  • where did GET_CART_ITEMS came from?

https://www.apollographql.com/docs/tutorial/local-state.html#direct-writes

  • where did StyledButton component came from?

Uncaught (in promise) Error: GraphQL error: Cannot read property 'id' of null

Steps to reproduce:

  1. Login as a new user (hasn't entered their email yet)
  2. Select a trip from the home page
  3. Add trip to cart
  4. Go to cart
  5. Click Book All

It will explode with: Uncaught (in promise) Error: GraphQL error: Cannot read property 'id' of null.

Looking at the error more closely reveals that we are caching the guest user somewhere. The error comes back from

// src/datasources/user.js:35
const userId = this.context.user.id;
if (!userId) return;

This means the user context is null

[email protected] not found on cdn.jsdelivr.net

Hey guys, thanks for the handy tutorial.

I've found an error running the Graphql Playground. The [email protected] ([email protected] dep) is setting the @apollographql/[email protected] version to 1.7.8, which doesn't exist anymore on the cdn.jsdelivr.net. Here's the playground html source:

<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/@apollographql/[email protected]/build/static/css/index.css" />
<link rel="shortcut icon" href="//cdn.jsdelivr.net/npm/@apollographql/[email protected]/build/favicon.png" />
<script src="//cdn.jsdelivr.net/npm/@apollographql/[email protected]/build/static/js/middleware.js"></script>

Updating apollo-server to it's current version 2.5.0 fixes the problem, as it changes the apollographql/graphql-playground-react version to 1.7.10.

I will send you guys a PR to update both server/client dependencies, if its ok.

Login exception INTERNAL_SERVER_ERROR

When performing the first login I receive this error:

"SQLITE_ERROR: no such table: users",

The sqlite db is there and I can read from it with an sql tool. I've also verified that the table users is available.

The location of this file is in server/store.sqlite but somehow when I run my server it gets copied to the root folder (whic part of the logic does this, maybe sequelize?)

I can read from src/utils that storage: './store.sqlite', so I guess the db should be located inside the server/src directory, but even copying it manually inside src doesn't fix the problem.

Maybe I've missed a step somehow?

Confusing naming of function passed to Array.map

Hello,
not a real issue but just a naming of a method that confused me for a bit.
In datasource/launch there is method called launchReducer passed to Array.map. This method is responsible to take each launch returned by the Rest API and mapping it to another object.
So I guess this function should be called lauchMapper, because that's what it does. It doesn't reduce multiple element into a single one, isn't it?

Just highlighting this because it is a bit confusing

Correct approach to datasource's that need to call each other

Let's say you have two datasource's:

return {
    moviesAPI: new MoviesAPI(),
    booksAPI: new BooksAPI(),
};

in the moviesAPI, I need to call a method that lives in the booksAPI.

What is the correct way to approach this problem?

  • Should I pass the booksAPI to the moviesAPI?
  • Or instantiate a new BooksAPI from within the MoviesAPI?

Or is there a better way?

How does login work?

in this code

<ApolloProvider client={client}>
<Query query={IS_LOGGED_IN}>
{({data}) => (data.isLoggedIn ? <Pages /> : <Login />)}
</Query>
</ApolloProvider>,

I don't understand how it renders login and then renders the pages.

I'm trying to do the same in another app but the cache doesn't rerender the query component onChange. sooooo how does it work here????

[Docs] Issue when publishing schema

Hey there!
For some reason when trying to publish the schema I was getting this error:

  โœ” Loading Apollo Project
  โœ– Uploading service to Engine
    โ†’ No service found to link to Engine
Error: No service found to link to Engine
    at Task.task (~/.npm/_npx/32532/lib/node_modules/apollo/lib/commands/service/push.js:17:31)
    at Promise.resolve.then.then.skipped (~/.npm/_npx/32532/lib/node_modules/apollo/node_modules/listr/lib/task.js:167:30)
    at <anonymous>

This is what I did, and didn't work:

  • Had my .env file with the ENGINE_API_KEY set.
  • Tried removing the sevice: prefix from the value of the variable
  • Tried restarting the server
  • Tried running npx apollo service:check && npx apollo service:push from the /server folder
  • Double and tripled checked the API key

Finally I gave up and had to type the parameters directly on the service:push command.

Is this only my issue?

Integration Tests Not Properly Mocked

I followed the integration tests example pattern in my own app.

   // mock the datasources' underlying fetch methods, whether that's a REST
    // lookup in the RESTDataSource or the store query in the Sequelize datasource
    launchAPI.get = jest.fn(() => [mockLaunchResponse]);

However I noticed it was still making api calls to the rest endpoint. I then cloned this repo turned off my wifi and ran the integration tests and sure enough I got an error.

errors": Array [
    +     Object {
    +       "extensions": Object {
    +         "code": "INTERNAL_SERVER_ERROR",
    +         "exception": Object {
    +           "code": "ENOTFOUND",
    +           "errno": "ENOTFOUND",
    +           "message": "request to https://api.spacexdata.com/v2/launches?flight_number=30 failed, reason: getaddrinfo ENOTFOUND api.spacexdata.com api.spacexdata.com:443",
    +           "type": "system",
    +         },
            },
    -       "rocket": Object {
    -         "type": "FT",
    -       },
    +       "locations": Array [
    +         Object {
    +           "column": 3,
    +           "line": 2,
    +         },
    +       ],
    +       "message": "request to https://api.spacexdata.com/v2/launches?flight_number=30 failed, reason: getaddrinfo ENOTFOUND api.spacexdata.com api.spacexdata.com:443",
    +       "path": Array [
    +         "launch",
    +       ],

This tells me that launchAPI.get is not being properly mocked. Which I think would make sense as there is no launchAPI.get however there is a launchAPI.prototype.get however that doesn't seem to work when I change the tests to that.

Any ideas?

Have issue with Mutation

I was following the tutorial for Apollo Server

I stuck at Step 3, Write your graph's resolvers.

When I run mutations in the playground:

mutation LoginUser {
login(email: "[email protected]")
}

I received the error messages like :

{
"errors": [
{
"message": "Cannot read property 'findOrCreateUser' of undefined",
"locations": [
{
"line": 30,
"column": 3
}
],
"path": [
"login"
],
"extensions": {
"code": "INTERNAL_SERVER_ERROR",
"exception": {
"stacktrace": [
"TypeError: Cannot read property 'findOrCreateUser' of undefined",
" at login (C:\laragon\www\fullstack-tutorial\start\server\src\resolvers.js:67:46)",
" at field.resolve (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql-extensions\dist\index.js:140:26)",
" at resolveFieldValueOrError (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\execution\execute.js:467:18)",
" at resolveField (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\execution\execute.js:434:16)",
" at C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\execution\execute.js:244:18",
" at C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\jsutils\promiseReduce.js:23:10",
" at Array.reduce ()",
" at promiseReduce (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\jsutils\promiseReduce.js:20:17)",
" at executeFieldsSerially (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\execution\execute.js:241:37)",
" at executeOperation (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\execution\execute.js:219:55)",
" at executeImpl (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\execution\execute.js:104:14)",
" at Object.execute (C:\laragon\www\fullstack-tutorial\start\server\node_modules\graphql\execution\execute.js:64:35)",
" at C:\laragon\www\fullstack-tutorial\start\server\node_modules\apollo-server-core\dist\requestPipeline.js:239:46",
" at Generator.next ()",
" at C:\laragon\www\fullstack-tutorial\start\server\node_modules\apollo-server-core\dist\requestPipeline.js:7:71",
" at new Promise ()",
" at __awaiter (C:\laragon\www\fullstack-tutorial\start\server\node_modules\apollo-server-core\dist\requestPipeline.js:3:12)",
" at execute (C:\laragon\www\fullstack-tutorial\start\server\node_modules\apollo-server-core\dist\requestPipeline.js:218:20)",
" at Object. (C:\laragon\www\fullstack-tutorial\start\server\node_modules\apollo-server-core\dist\requestPipeline.js:156:42)",
" at Generator.next ()",
" at fulfilled (C:\laragon\www\fullstack-tutorial\start\server\node_modules\apollo-server-core\dist\requestPipeline.js:4:58)"
]
}
}
}
],
"data": {
"login": null
}
}

[Question] Using Typescript, what type should the { dataSources } context resolver argument be?

Hi, I'm following the tutorial using typescript. Please let me know if this is not the place to be asking this question.

In page 2 of the tutorial, we write and define the launchAPI and userAPI classes as contexts.

That way, in the resolver of a query, we take as an argument { dataSources }, a context object that has two members: one is an instance of launchAPI and the other of userAPI. We can then use dataSources.launchAPI or dataSources.userAPI to retrieve REST or database data.

What I don't understand is: how could I define this argument as a custom GraphQL context type?

Query: {
    launches: async (parent: any, args: any, { dataSources }: <How to define this>) => {
...
   }
}

I think I should define the type as:

type GQLContext = {
  dataSources: <How to define this as object with instances of LaunchAPI and UserAPI>
}

`npm i` fails when installing dependencies in `final` folder

โžœ  server git:(master) npm i
WARN tar ENOENT: no such file or directory, open '/Users/chang/work/apollo/fullstack-tutorial/final/server/node_modules/.staging/minipass-649afe36/package.json'
WARN tar ENOENT: no such file or directory, open '/Users/chang/work/apollo/fullstack-tutorial/final/server/node_modules/.staging/minipass-649afe36/index.js'
WARN tar ENOENT: no such file or directory, open '/Users/chang/work/apollo/fullstack-tutorial/final/server/node_modules/.staging/minipass-649afe36/LICENSE'
WARN tar ENOENT: no such file or directory, open '/Users/chang/work/apollo/fullstack-tutorial/final/server/node_modules/.staging/minipass-649afe36/README.md'
npm WARN [email protected] No description
npm WARN [email protected] No repository field.

npm ERR! code E404
npm ERR! 404 Not Found: [email protected]

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/chang/.npm/_logs/2018-11-26T21_48_50_251Z-debug.log

Using fragment in `launches.js` stops data from being loaded.

Are you sure that presented fragment is correct? I mean it looks right but when changing from

const GET_LAUNCHES = gql`
  query launchList($after: String) {
    launches(after: $after) {
      cursor
      hasMore
      launches {
        id
        isBooked
        rocket {
          id
          name
        }
        mission {
          name
          missionPatch
        }
      }
    }
  }
`;

to solution with fragments:

export const LAUNCH_TILE_DATA = gql`
  fragment LaunchTile on Launch {
    __typename
    id
    isBooked
    rocket {
      id
      name
    }
    mission {
      name
      missionPatch
    }
  }
`;

const GET_LAUNCHES = gql`
  query GetLaunchList($after: String) {
    launches(after: $after) {
      cursor
      hasMore
      launches {
        ...LaunchTile
      }
    }
  }
  ${LAUNCH_TILE_DATA}
`;

Data is never properly loaded into the component:
screenshot 2018-11-20 at 10 16 16

When using the fragments I can't see any POST request performed against my graphql server.

Add tests to cover 'logout-button.js' container

In the final version of the client app, I found that 'logout-button.js' container does not have implemented tests.

// TODO it('', () => {});

I would like to add tests to this container.

Error when fetching past end of Launches

Cursor is defined as non-nullable:

type LaunchConnection { # add this below the Query type as an additional type.
  cursor: String!
  hasMore: Boolean!
  launches: [Launch]!
}

But if no launches are retrieved (for example if you pass in a cursor for which hasMore was false), then the code will carefully return null for the cursor:

      return {
        launches,
        cursor: launches.length ? launches[launches.length - 1].cursor : null,

Resulting in INTERNAL_SERVER_ERROR:
Screen Shot 2019-07-13 at 8 22 12 PM

Wrong order of the actions performed in the tutorial

i believe in https://www.apollographql.com/docs/tutorial/production.html you are showing the wrong order of actions needed to properly deploy the apollo service to the engine.

To set up a service we need to provide endpoint. I assume this endpoint should be coming from Zeit Now. Yet deployment of the service to Now is described further down the road.
Wouldn't it make more sense to describe it first and then go to deploying the service to the engine?

[Question]Why are no `async` on some resolver methods?

Hi, I'm very new to Apollo graphql and reading through the tutorial.
I noticed that launch method in resolver.js does not have async and wondering why even though the request is asynchronous. In fact, if I add async it works as expected. Could someone tell me why async is not required in this case?

module.exports = {
  Query: {
    launches: async (_, __, { dataSources }) =>
      dataSources.launchAPI.getAllLaunches(),
    launch: (_, { id }, { dataSources }) =>  // no async
      dataSources.launchAPI.getLaunchById({ launchId: id }),
    me: async (_, __, { dataSources }) =>
      dataSources.userAPI.findOrCreateUser(),
  },
};

database connection?

To make a fullstack tutorial complete don't we need some kind of a connector to a database such as Mongo or Postgres?

Bug in cancelTrip method from User datasource

return !!this.store.trips.destroy({ where: { userId, launchId } });

Due to this line cancelTrip throws an error.

{
  "errors": [
    {
      "message": "Cannot read property 'flight_number' of undefined",
      "locations": [
        {
          "line": 2,
          "column": 3
        }
      ],
      "path": [
        "cancelTrip"
      ],
      "extensions": {
        "code": "INTERNAL_SERVER_ERROR",
        "exception": {
          "stacktrace": [
            "TypeError: Cannot read property 'flight_number' of undefined",
      // ....

Following change will fix the error.

async cancelTrip({ launchId }) {
    const userId = this.context.user.id;
    const numberOfDeletedTrips = await this.store.trips.destroy({ where: { userId, launchId } });
    return numberOfDeletedTrips !== 0;
  }

As per the doc of destroy it returns number of deleted resources wrapped in Promise. So it should be resolved to get the count to decide if resources are deleted or not.

Add step to add `apollo.config.js`

Have had a few intercom users saying they ran npx apollo service:check && npx apollo service:push and got Error: No service found to link to Engine

The tutorial page doesn't currently mention anything about configs

https://www.apollographql.com/docs/tutorial/production.html

There are docs for service settings from the apollo-tooling readme that can be used as reference - https://github.com/apollographql/apollo-tooling#service-settings

Related: apollographql/apollo-tooling#771

new Buffer is deprecated

in server/src/resolvers.js in part 3 of the tutorial:

if (user) return new Buffer(email).toString('base64'); should be changed to:
if (user) return Buffer.from(email).toString('base64');

Cart is empty after page reload

After adding an item to the cart, then clicking on cart, the item appears as expected. But when you reload the web page in the browser the cart becomes empty.

Also, after adding an item to the cart, the button becomes "REMOVE FROM CART". Then when that web page is reloaded, the same button reverts to "ADD TO CART".

Types mismatch: ApolloServer/ApolloServerBase

Following the example of an integration test:

const server = new ApolloServer({
typeDefs,
resolvers,
dataSources: () => ({ userAPI, launchAPI }),
context,
});

const {query} = createTestClient(server);

Environment

The issue

The output type of new ApolloServer is ApolloServer, while the input type to createTestClient is ApolloServerBase. This makes these functions not compatible.

I'm using TypeScript, therefore I can experience this error.

Expected behavior

a) createTestClient(server: ApolloServer)
b) Change the example of creating a server instance to return expected ApolloServerBase.

Types mismatch: ApolloClient

I set isInCart is Boolean and I try to return some value is string type in this function. It work. I think should be show some error because type mismatch

image

image

Getting error when first starting server in the tutorial

I'm sure it's something I'm doing wrong, but I've just started the tutorial and when I first try to start the server I get

type Launch {
^^^^^^

SyntaxError: Unexpected identifier
at new Script (vm.js:74:7)
at createScript (vm.js:246:10)
at Object.runInThisContext (vm.js:298:10)
at Module._compile (internal/modules/cjs/loader.js:657:28)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
at Module.load (internal/modules/cjs/loader.js:599:32)
at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
at Function.Module._load (internal/modules/cjs/loader.js:530:3)
at Module.require (internal/modules/cjs/loader.js:637:17)
at require (internal/modules/cjs/helpers.js:20:18)
[nodemon] app crashed - waiting for file changes before starting...

My schema.js file is

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

const typeDefs = gql``

module.exports = typeDefs;


type Launch {
  id: ID!
    site: String
  mission: Mission
  rocket: Rocket
  isBooked: Boolean!
}

type Rocket {
  id: ID!
    name: String
  type: String
}

type User {
  id: ID!
    email: String!
    trips: [Launch]!
}

type Mission {
  name: String
  missionPatch(size: PatchSize): String
}

enum PatchSize {
  SMALL
  LARGE
}

type Mutation {
  # if false, booking trips failed -- check errors
  bookTrips(launchIds: [ID]!): TripUpdateResponse!

    # if false, cancellation failed -- check errors
  cancelTrip(launchId: ID!): TripUpdateResponse!

    login(email: String): String # login token
}

type Query {
  launches: [Launch]!
    launch(id: ID!): Launch
  # Queries for the current user
  me: User
}

and index.js is


const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');

const server = new ApolloServer({ typeDefs });

server.listen().then(({ url }) => {
  console.log(`๐Ÿš€ Server ready at ${url}`);
});

Not sure where the error lies as I was simply copying code from the tutorial....thanks for any clues.

Dependencies not installing properly

I tried to install the packages from client in the start folder. This worked, but I was told that there were 8 vulnerabilities, 4 of them being high. I went to npm audit fix, although it failed due to ENOENT: no such file or directory for a sourcemap file. I tried it again, and it worked with some warnings. When i went to start the client server (after placing the starter code into index.tsx), my compiler indicated:

Could not find a required file.
Name: index.js
Searched in: /mnt/c/Users/User/documents/apollo-tut/start/client/src
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] start: react-scripts start
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /home/User/.npm/_logs/2020-02-21T15_24_19_779Z-debug.log

Thanks in advance!

Launches pagination implementation is a bad example for reference

The GraphQL server-side cursor pagination example should be discarded. While the intent of the paginateResults function in final/server/src/utils.js is good, there are a number of significant flaws with this implementation.

The lowest hanging fruit is that there is a line of code at the end of the function - results.slice(cursorIndex >= 0 ? cursorIndex + 1 : 0, cursorIndex >= 0); which is unreachable.

However, the most egregious error is how the launches function is defined in final/server/src/resolvers.js - which gives the impression that data is being paged responsibly. It is not

Every time pagination is invoked, the API request loads ALL THE DATA from the API and then passes it to the pagination function. For the example SpaceX data, there are approximately 76 results that get loaded and then processed to return the 20 results the user is expecting:

  Query: {
    launches: async (_, { pageSize = 20, after }, { dataSources }) => {
      const allLaunches = await dataSources.launchAPI.getAllLaunches();
      // we want these in reverse chronological order
      allLaunches.reverse();

      const launches = paginateResults({
        after,
        pageSize,
        results: allLaunches,
      });

      return {
        launches,
        cursor: launches.length ? launches[launches.length - 1].cursor : null,
        // if the cursor of the end of the paginated results is the same as the
        // last item in _all_ results, then there are no more results after this
        hasMore: launches.length
          ? launches[launches.length - 1].cursor !==
            allLaunches[allLaunches.length - 1].cursor
          : false,
      };
    },
    ...

If that API endpoint were to return a massive amount of data (imagine 40,000 results), this resolver would load all 40,000 results and then find 20 to return. When the user would click load more, all 40,000 results would be loaded into memory again and then the next 20 results would be returned...effectively processing 80,000 results to display 40 to the user. EEK!

This is definitely something that should be revisited. Imagine a scenario with 30 users following a simple workflow of viewing the first 20 results and then loading an additional 20 results.

Additionally, if the result set grew (imagine 40,001 records), the newest record would never be displayed to the user because it would have been in a spot the cursor presumably has already visited, right?

Running `npx now` doesn't work

In the production#deploy section. Running npx now is returning,
Screenshot_2019-05-05 502 An error occurred with your deployment

I tried both running npx now, now from the cli, and also adding the [now.json](https://github.com/apollographql/fullstack-tutorial/blob/master/final/server/now.json) file from the final server version. No luck. Anyone know how that works? Thanks.

client's action button text doesn't change after pressing "Remove from Cart"

I run the client with my local server.

After pressing the button "Remove from Cart", the text of the button doesn't change back to "Add to cart".

In the beginning I thought the local resolver doesn't work. However, I tried to console.log the cartItems array and found the mutation works, the item has been removed from the array, and the result of isInCart also changed.

"Cancel this trip" and "Add to cart" work fine.

Missing step to uncomment dotenv configuration

We should mention somewhere around here that this line should be uncommented in order for dotenv configuration to take effect. Without this, metrics are not sent to Apollo Engine since the Apollo server does not actually have the ENGINE_API_KEY set. Also, some acknowledgement of how this works via the dotenv module seems like it would be appropriate.

querying `launches` returns errors on "final" repo.

It seems the tutorial is out of date, as even the final returns errors, so I know it isn't with my implementation after going through the tutorial.

The playground returns the following after running the GetLaunches query from the tutorial:

{
  "error": {
    "errors": [
      {
        "message": "Cannot query field \"id\" on type \"LaunchConnection\".",
        "locations": [
          {
            "line": 3,
            "column": 5
          }
        ],
        "extensions": {
          "code": "GRAPHQL_VALIDATION_FAILED",
          "exception": {
            "stacktrace": [
              "GraphQLError: Cannot query field \"id\" on type \"LaunchConnection\".",
              "    at Object.Field (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:64:31)",
              "    at Object.enter (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:333:29)",
              "    at Object.enter (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:384:25)",
              "    at visit (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:251:26)",
              "    at Object.validate (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/validation/validate.js:63:22)",
              "    at validate (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:172:32)",
              "    at Object.<anonymous> (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:113:38)",
              "    at Generator.next (<anonymous>)",
              "    at fulfilled (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)",
              "    at process._tickCallback (internal/process/next_tick.js:68:7)"
            ]
          }
        }
      },
      {
        "message": "Cannot query field \"mission\" on type \"LaunchConnection\".",
        "locations": [
          {
            "line": 4,
            "column": 5
          }
        ],
        "extensions": {
          "code": "GRAPHQL_VALIDATION_FAILED",
          "exception": {
            "stacktrace": [
              "GraphQLError: Cannot query field \"mission\" on type \"LaunchConnection\".",
              "    at Object.Field (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/validation/rules/FieldsOnCorrectType.js:64:31)",
              "    at Object.enter (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:333:29)",
              "    at Object.enter (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:384:25)",
              "    at visit (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/language/visitor.js:251:26)",
              "    at Object.validate (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/graphql/validation/validate.js:63:22)",
              "    at validate (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:172:32)",
              "    at Object.<anonymous> (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:113:38)",
              "    at Generator.next (<anonymous>)",
              "    at fulfilled (/home/petty/Github/apollo-graphql/fullstack-tutorial/final/server/node_modules/apollo-server-core/dist/requestPipeline.js:4:58)",
              "    at process._tickCallback (internal/process/next_tick.js:68:7)"
            ]
          }
        }
      }
    ]
  }
}

Me Resolver on final is misleading

This is the resolver for me on final

me: async (_, __, { dataSources }) =>
      dataSources.userAPI.findOrCreateUser(),

However it could (and probably should) be

me: async (_, __, context) => context.user

which is the logged in user authenticated by the authorization headers.

Possible Invalid Return Type from bookTrips

Hello GraphQL astronauts,

Following this well written tutorial, am just so thankful. However from section 3. Write your graph's resolvers, I am hitting a bug at line 45 here...

id => !results.includes(id),

"message": "Cannot read property 'includes' of undefined",

I get the above error from the playground and from inspection, I think its caused by the return statement from the user dataSource bookTrips which returns undefined when no user has been found.

Possible fix would be returning an empty array instead, such that results.includes does not throw up.

if (!userId) return [];

Maybe I am missing something, does anyone face this bug too?

TypeError: Cannot read property 'trips' of null

The first time i visit the profile tab i get this error. It also happens when i empty the cache and hard reload.

TypeError: Cannot read property 'trips' of null
(anonymous function)
src/pages/profile.js:30
  27 | 
  28 | return (
  29 |   <Fragment>
> 30 |     <Header>My Trips</Header>
     | ^  31 |     {data.me.trips.length ? (
  32 |       data.me.trips.map(launch => (
  33 |         <LaunchTile key={launch.id} launch={launch} />

Query.render
node_modules/react-apollo/react-apollo.browser.umd.js:693
finishClassComponent
node_modules/react-dom/cjs/react-dom.development.js:14897
updateClassComponent
node_modules/react-dom/cjs/react-dom.development.js:14861
beginWork
node_modules/react-dom/cjs/react-dom.development.js:15727
performUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js:18742
workLoop
node_modules/react-dom/cjs/react-dom.development.js:18783
HTMLUnknownElement.callCallback
node_modules/react-dom/cjs/react-dom.development.js:147
invokeGuardedCallbackDev
node_modules/react-dom/cjs/react-dom.development.js:196
invokeGuardedCallback
node_modules/react-dom/cjs/react-dom.development.js:250
replayUnitOfWork
node_modules/react-dom/cjs/react-dom.development.js:17984
renderRoot
node_modules/react-dom/cjs/react-dom.development.js:18895
performWorkOnRoot
node_modules/react-dom/cjs/react-dom.development.js:19800
performWork
node_modules/react-dom/cjs/react-dom.development.js:19710
performSyncWork
node_modules/react-dom/cjs/react-dom.development.js:19684
requestWork
node_modules/react-dom/cjs/react-dom.development.js:19539
scheduleWork
node_modules/react-dom/cjs/react-dom.development.js:19346
enqueueForceUpdate
node_modules/react-dom/cjs/react-dom.development.js:12826
Query.push../node_modules/react/cjs/react.development.js.Component.forceUpdate
node_modules/react/cjs/react.development.js:373
Query._this.updateCurrentData
node_modules/react-apollo/react-apollo.browser.umd.js:507
next
node_modules/react-apollo/react-apollo.browser.umd.js:486
notifySubscription
node_modules/zen-observable/lib/Observable.js:152
onNotify
node_modules/zen-observable/lib/Observable.js:196
SubscriptionObserver.next
node_modules/zen-observable/lib/Observable.js:248
(anonymous function)
node_modules/apollo-client/core/ObservableQuery.js:422
next
node_modules/apollo-client/core/ObservableQuery.js:421
(anonymous function)
node_modules/apollo-client/core/QueryManager.js:693
(anonymous function)
node_modules/apollo-client/core/QueryManager.js:1125
(anonymous function)
node_modules/apollo-client/core/QueryManager.js:1124
QueryManager.broadcastQueries
node_modules/apollo-client/core/QueryManager.js:1120
QueryManager.
node_modules/apollo-client/core/QueryManager.js:1271
step
node_modules/apollo-client/core/QueryManager.js:139
next
node_modules/apollo-client/core/QueryManager.js:69
(anonymous function)
node_modules/apollo-client/core/QueryManager.js:41
push../node_modules/apollo-client/core/QueryManager.js.__awaiter
node_modules/apollo-client/core/QueryManager.js:18
next
node_modules/apollo-client/core/QueryManager.js:1227
notifySubscription
node_modules/zen-observable/lib/Observable.js:152
onNotify
node_modules/zen-observable/lib/Observable.js:196
SubscriptionObserver.next
node_modules/zen-observable/lib/Observable.js:248
(anonymous function)
node_modules/apollo-link-dedup/lib/dedupLink.js:94
next
node_modules/apollo-link-dedup/lib/dedupLink.js:93
notifySubscription
node_modules/zen-observable/lib/Observable.js:152
onNotify
node_modules/zen-observable/lib/Observable.js:196
SubscriptionObserver.next
node_modules/zen-observable/lib/Observable.js:248
(anonymous function)
node_modules/apollo-link-http/lib/httpLink.js:133

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.