How do I get AccountJS working with Fastify and Mercurius? #1190
Replies: 2 comments 11 replies
-
Fixed by downgrading to a specific version of Mongoose I noticed in the example code. (Here's a compatibility matrix but confusingly the I pointed the React Frontend example up to my backend to test, and it seems to be working perfectly now... but I'd still like feedback on whether I've got my ducks in a row, and am understanding things properly. |
Beta Was this translation helpful? Give feedback.
-
What ended up fixing it was having context that resumed the session. I really think the docs should be updated to reflect that in all the examples, I didn't get a user until I did this, since it seems like it's needed, but I'm open to being corrected: async ({ raw }: FastifyRequest): Promise<Context> => {
const ctx = await accountsGraphQL.context({ req: raw });
const { authToken } = ctx;
if (authToken) {
let user;
try {
user = await accountsServer.resumeSession(authToken as string); //<=== this is the key here.
} catch (error) {
if (error instanceof AccountsJsError) {
if (error.code === 'InvalidToken') {
throw new Error('Unauthorized');
}
}
}
return {
...ctx,
user,
userId: user && user.id && user._id, //<-- not sure if this lib maps the `_id` to `id` or not.
};
}
return {
...ctx,
};
}; |
Beta Was this translation helpful? Give feedback.
-
TL;DR
I am using Accounts with Fastify and Mercurius, using
@accounts/password
and@accounts/graphql-api
with mongo as a db, and am having the following problems (most likely due to misconfiguration or a misunderstanding of what this library does for you):createUser
returns session and user asnull
addEmail
andverifyEmail
throw "Cannot read property 'nModified' of undefined"authenticate
by sendingtoken
, oraccess_token
by itself otherwise it gives me "unexpected configuration"authenticate
andverifyAuthenticated
(returns true) work fineBelow I included my configuration, and my
package.json
file. Also links to issues, examples, and library code that have informed me thus far.I really love the API of
accounts-js
and was really excited to learn it when I saw it. I started a project with:I read the documentation front to back a few times. I also downloaded and ran the React Example while running the TypeScript Backend and was instantly sold! This lib is exactly what I'm looking for—hook, line, and sinker.
I'm using Fastify, which uses Mercurius for GraphQL, and quickly ran into an issue where the
userId
wasundefined
in my resolvers—butauthenticate
andverifyAuthentication
worked fine. I didn't check that this was the case in the TypeScript example code mentioned earlier, but the example worked fine.My Accounts configuration code within a Fastify plugin—imports included
I saw in so many different places code that used
accountsGraphQL.context
directly oncontext
, being new to the library, I still don't know if that's my problem. I also didn't know if it was fundamental differences between Mercurius and Apollo Server causing it to not populate or a misunderstanding of what the library actually does for you.Gives me typescript errors, about how the
boolean
s (2nd and 3rd args) were incompatible withreply
. Event when I did just straight return the context,userId
anduser
were always undefined:In one place there was a super vague, no imports or anything (see How to use this package? under "The last step is to add to your
ApolloServer
, the accounts context.") that I thought might be something, so I used that for reference as well. But didn't understand where functions were coming from.I had been passing an
Authorization
header with Bearer token that I got from theauthenticate
mutation:Still not sure if I was implementing it right, I went to the authenticate resolver in code, and saw it called
loginWithService
which I found onAccountsServer
here. I noted it callsauthenticate
(in my case) using password, then returns the result so thatloginWithUser
can be called. Which the documentation warns:But do not see anything about the session in that code. At my lowest, I even resorted to using the
accountsServer.on
event to listen for successful authentication, then calling theloginWithUser
method manually, to no avail.Am I misunderstanding something fundamental about how the library works? How do I get a user from a session when they pass a token? I started to get some good information with this issue but it was vague, and thought I might have the same misunderstanding.
So I built a context function based on this issue, to do this work manually, but I'm not sure if there's a better way or not, but it feels right to me:
The code for the buildContext function
```typescript import { AccountsModuleConfig, AccountsModuleContext, AccountsRequest, } from "@accounts/graphql-api"; import AccountsServer, { AccountsJsError } from "@accounts/server"; import { GraphQLModule, ModuleContext } from "@graphql-modules/core"; import { FastifyRequest } from "fastify"; import { InvalidTokenError } from "jwt-decode"; import { MercuriusContext } from "mercurius"; import { User } from "./types";Now that I have that in place the
me
resolver (as demonstrated here) and thegetUser
queries return data, butcreateUser
still returns session and user asnull
. I poured through the issues and found a suggestion from @vuode to use:And now I get a proper error message when trying to create a user whose username or email already exists.
But then I try to verify an email, or add an email (so far have just tried those two before coming here) I get this error message:
But it successfully persists the data. It verified my email but barfed at me, and when I added an email it added it and then barfed that.
package.json
```json { "name": "user", "version": "1.0.0", "description": "", "main": "./src/server.ts", "scripts": { "test": "jest --runInBand", "clean": "rm -rf dist", "build": "npm run clean && tsc", "dev": "nodemon src/server.ts", "start": "node dist/src/server.js", "lint": "eslint \"src/**/*.ts\"", "lint:write": "eslint \"src/**/*.ts\" --fix", "ts-node": "ts-node --compiler-options \"{\\\"module\\\":\\\"commonjs\\\"}\"", "generate:prisma": "prisma generate", "generate:secret": "uuid v4" }, "devDependencies": { "@tsconfig/node14": "^1.0.1", "@types/jsonwebtoken": "^8.5.5", "@types/jwt-decode": "^3.1.0", "@types/node": "^16.11.6", "@types/supertest": "^2.0.10", "@types/uuid": "^8", "@types/ws": "^7.4.0", "@typescript-eslint/eslint-plugin": "^4.9.1", "@typescript-eslint/parser": "^4.9.1", "eslint": "^7.15.0", "eslint-config-google": "^0.14.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-jest": "^24.1.3", "eslint-plugin-promise": "^4.2.1", "jest": "^26.6.3", "nodemon": "^2.0.15", "prettier-plugin-prisma": "^3.4.1", "prisma": "3.4.1", "supertest": "^6.0.1", "ts-jest": "^26.4.4", "ts-node": "^10.4.0", "ts-node-dev": "^1.1.1", "typescript": "^4.4.4" }, "dependencies": { "@accounts/database-manager": "^0.33.1", "@accounts/graphql-api": "^0.33.1", "@accounts/magic-link": "^0.1.1", "@accounts/mongo": "^0.33.5", "@accounts/password": "^0.32.1", "@accounts/rest-express": "^0.33.1", "@accounts/server": "^0.33.1", "@graphql-modules/core": "^0.7.17", "@graphql-tools/merge": "^8.2.1", "@graphql-tools/schema": "^7.1.2", "@prisma/client": "3.4.1", "argon2": "^0.28.2", "dotenv": "^10.0.0", "fastify": "^3.9.2", "fastify-express": "^0.3.3", "fastify-mongodb": "^4.1.1", "fastify-plugin": "^3.0.0", "graphql": "^15.4.0", "graphql-tag": "^2.12.6", "jsonwebtoken": "^8.5.1", "jwt-decode": "^3.1.2", "mercurius": "^8.9.1", "mercurius-codegen": "^1.2.0", "mongoose": "^6.0.13", "reflect-metadata": "^0.1.13", "tslib": "^2.3.1", "uuid": "^8.3.2", "yup": "^0.32.11", "yup-env": "^1.2.0" }, "author": "Kevin Dench ", "license": "ISC", "prisma": { "seed": "ts-node prisma/seed.ts" } } ```I could really use some help getting this set up properly, it's been a very hard and exasperating experience so far, but I don't want to give up on all the niceities and good design from this library. What am I doing/how am I thinking wrong? I have been using
graphiql
to test all this configuration, haven't built the frontend yet.Thanks for any help ahead of time. It's a great library, even with all these problems I've experienced, I'm thinking it's just me being slow.
Beta Was this translation helpful? Give feedback.
All reactions