Apollo Studio | apollo-server | "Error: Unable to use introspection, make sure it is enabled" (but introspection is set to true) - apollo-server

I've got Apollo Server properly serving my GraphQL API on http://localhost:4000. However, Apollo Studio is unable to properly see the underlying schema, despite introspection: true being set.
//index.ts
import { AppDataSource } from "./database/data-source"
import startApolloServer from './server'
AppDataSource.initialize()
.then(async dataSource => {
startApolloServer(dataSource)
}).catch(error => console.log(error))
//server.ts
import 'dotenv/config'
import typeDefs from './graphql/typeDefs'
import resolvers from './graphql/resolvers';
import { ApolloServer } from 'apollo-server'
export default async function startApolloServer(AppDataSource) : Promise<void> {
const server : ApolloServer = new ApolloServer({
typeDefs,
resolvers,
introspection: true,
cors: {
origin: '*',
credentials: true
},
dataSources: () => {
return {
AppDataSource
}
}
});
server.listen()
.then( ({url}) => console.log(`\n
********************************
Apollo Server is ready at ${url}
********************************
`))
}
```[enter image description here][1]
[1]: https://i.stack.imgur.com/X7KO9.png

Related

GraphQL Shield Type Validation Performed After Resolver Executed, Not Before

I'm using Apollo GraphQL Server with GraphQL shield. When I implement rule on GraphQL type, the Shield authorization performed after the resolver executed. Is that how GraphQL Shield works or is it caused by misconfiguration?
Here's the server configuration
import { ApolloServer } from 'apollo-server-express';
import { ApolloServerPluginDrainHttpServer } from 'apollo-server-core';
import http from 'http';
import { applyMiddleware } from 'graphql-middleware';
import schema from './schema';
import shield from './shield';
(async () => {
const httpServer = http.createServer(app);
const server = new ApolloServer({
schema: applyMiddleware(schema, shield),
csrfPrevention: true,
cache: 'bounded',
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })]
});
await server.start();
server.applyMiddleware({ app });
await new Promise<void>((resolve) =>
httpServer.listen({ port: 80 }, resolve)
);
console.log(`Server ready at http://localhost:80${server.graphqlPath}`);
})(schema);
Thankyou

There is no matching message handler error in NestJs TCP E2E test

I'm playing around with Microservice architecture using NestJs. I've made a simplified repository with a few services that communicate over TCP with a mix of message and event patterns.
I have moved on to writing E2E tests for the using Supertest, and while I'm able to run the needed microservice, the requests respond with {"error": "There is no matching message handler defined in the remote service.", "statusCode": 500}
GatewayService: HTTP Rest Api where the E2E tests are run. Calls the service
AuthService: NestJs microservice running on 0.0.0.0:3001 by default
configService: a simple service that returns information needed to set up the services, like host and port. I have tried eliminating it from the test and hardcoding the values.
The E2E test file
import { INestApplication, ValidationPipe } from '#nestjs/common';
import { ClientProxy, ClientsModule, Transport } from '#nestjs/microservices';
import { Test, TestingModule } from '#nestjs/testing';
import * as request from 'supertest';
import { configService } from '../src/config.service';
import { RpcExceptionFilter } from '../src/filters/rpc-exception.filter';
import { AppModule } from './../src/app.module';
describe('AuthenticationController (e2e)', () => {
let app: INestApplication;
let authClient: ClientProxy;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
AppModule,
ClientsModule.register([
{
...configService.getServiceConfigs().authService,
transport: Transport.TCP,
},
]),
],
}).compile();
// Setup the app instance
app = moduleFixture.createNestApplication();
// Setup the relevant micorservice(s)
app.connectMicroservice({
transport: Transport.TCP,
name: configService.getServiceConfigs().authService.name,
options: configService.getServiceConfigs().authService.options,
});
app.startAllMicroservices();
// Add request validation
app.useGlobalPipes(
new ValidationPipe({
transform: true,
whitelist: true,
forbidNonWhitelisted: true,
forbidUnknownValues: true,
}),
);
// Add needed filters
app.useGlobalFilters(new RpcExceptionFilter());
await app.init();
authClient = app.get(configService.getServiceConfigs().authService.name);
await authClient.connect();
console.log('authClient', authClient);
});
describe('POST /auth/login', () => {
it('Should return status 200 and a user object with access token', () => {
return (
request(app.getHttpServer())
.post('/auth/login')
.send({ username: 'exmple#user.com', password: 'password' })
// .expect(200)
.expect((response) => {
console.log('response', response.body);
expect(response.body).toHaveProperty('id');
expect(response.body).toHaveProperty('username');
expect(response.body).toHaveProperty('accessToken');
})
);
});
});
afterAll(async () => {
await app.close();
await authClient.close();
});
});
I have attempted adding a provider which I've used before when working with Grpc as the transport layer (this is TCP). Didn't change anything.
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
...
providers: [
{
provide: 'AUTH_SERVICE',
useFactory: () => {
return ClientProxyFactory.create({
transport: Transport.TCP,
options: { host: 'localhost', port: 3001 },
});
},
},
],
I know that the microservice starts up and the gateway service is able to connect to it since when printing the authClient: Client proxy it returns a correct object with URL 0.0.0.0:3001. If I change the URL, or the name of the service in any part of the setup then errors about missing providers show, further confirming that it is supposedly correctly set up.
One of the best guides I've found on this matter. Sadly it doesn't work for my code.

How to test nestjs with graphql by end to end?

In the test/posts/posts.e2e-spec.ts file
import { INestApplication } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { Test, TestingModule } from '#nestjs/testing';
import request = require('supertest');
import { PostsModule } from '../../src/posts/posts.module';
describe('Posts (e2e)', () => {
const posts = {
id: 1,
name: 'FirstPost #1',
};
let app: INestApplication;
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
...
}),
PostModule,
],
}).compile();
app = moduleFixture.createNestApplication();
await app.init();
});
afterAll(async () => {
await app.close();
});
describe('post', () => {
it('should retrieve all post data', async () => {
request(app.getHttpServer())
.post('/graphql')
.send({
query:
`{findPosts() {
name
}}`,
})
.expect(200)
.expect((res) => {
console.log(res.body.data)
expect(res.body.data.post.length).toEqual(posts.length)
})
})
})
});
I created migration and inserted data into database first, then run this test, it can't go to the expect items. Even set console log I can't see anything in the output.
So maybe the /graphql can't be access in this way? I can access the endpoint from browser as http://localhost:3000/graphql.
If import supertest as
import * as request from 'supertest';
In the line request it showed:
This expression is not callable. Type ‘typeof supertest’ has no call signatures.
The version of them:
supertest: 6.1.3
#types/supertest: 2.0.11
Check out this very useful link https://github.com/jmcdo29/testing-nestjs/tree/main/apps/graphql-sample. It explains a lot of things regarding tests including graphql nestjs testing along with sample application

AWS Lambda handle authorization headers error

For my project, I'm utilizing AWS Lambda and Graphql. I used apollo-server-lambda for this project. For this project, I created custom headers. And I added a simple condition to throw an error if there is no 'event.headers.authorization'. When the app is launched in a local environment, the error is thrown correctly. But the issue is that I'm not sure how I'm going to put my authorisation in if it's continuously throwing me off. I'm certain my implementation is incorrect. I'm not sure what the best method is for obtaining authorization.
It should be put like this:
.
This is my Lambda
import * as R from 'ramda';
import { AuthenticationError, ForbiddenError } from 'apollo-server-lambda';
export const authToken = (token: string) => {
if (token === 'HELLO') {
return true;
} else {
throw new AuthenticationError('No authorization header supplied');
}
};
const lambda =
(lambdaFunc: AWSLambda.Handler): AWSLambda.Handler =>
(event, context, callback) => {
const { authorization } = event.headers;
if (R.isNil(authorization))
throw new ForbiddenError('You must be authenticated'); // always thorws me error
return authToken(event.headers.authorization);
return lambdaFunc(event, context, callback);
};
export default lambda;
This is my graphql
import { ApolloServerPluginLandingPageGraphQLPlayground } from 'apollo-server-core';
import { ApolloServer} from 'apollo-server-lambda';
import schema from '../graphql/schema';
import resolvers from '../resolvers';
import lambda from '../utils/lambda';
const server = new ApolloServer({
typeDefs: schema,
resolvers,
debug: false,
plugins: [ApolloServerPluginLandingPageGraphQLPlayground()],
introspection: true,
});
export default lambda(
server.createHandler({
expressGetMiddlewareOptions: {
cors: {
origin: '*',
credentials: true,
allowedHeaders: ['Content-Type', 'Origin', 'Accept', 'authorization'],
optionsSuccessStatus: 200,
maxAge: 200,
exposedHeaders: ['authorization'],
},
},
})
);
This is YAML file
functions:
graphql:
handler: src/handlers/graphql.default
events:
- http:
path: ${env:api_prefix}/graphql
method: get
cors: true
- http:
path: ${env:api_prefix}/graphql
method: post
cors: true

How can i set my ApolloServer to open a graphql playground instead of the apollographql sandbox by default?

My question is how can i set this graphql playground extension as my default playground instead of using the default sandbox when i visited http://hocalhost/port/graphql. Is there any option that i can set during the creation of the ApolloServer instance that can configure that?.
...
const apolloServer = new ApolloServer({
schema: await buildSchema({
validate: false,
resolvers: [HelloResolver, UserResolver],
}),
context: ({ req, res }) => ({ em: orm.em, req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({ app });
....
Use the GraphQL Playground plugin and provide it to your Apollo Server constructor. For more info checkout Apollo Docs.
import {
ApolloServerPluginLandingPageGraphQLPlayground
} from "apollo-server-core";
const apolloServer = new ApolloServer({
...
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground(),
],
});

Resources