Do we face any issues with creating apollo server and converting it to express server using apollo/server npm package? - express

pls check the below code,
// npm install #apollo/server express graphql cors body-parser
import { ApolloServer } from '#apollo/server';
import { expressMiddleware } from '#apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '#apollo/server/plugin/drainHttpServer';
import express from 'express';
import http from 'http';
import cors from 'cors';
import bodyParser from 'body-parser';
import { typeDefs, resolvers } from './schema';
// Required logic for integrating with Express
const app = express();
// Our httpServer handles incoming requests to our Express app.
// Below, we tell Apollo Server to "drain" this httpServer,
// enabling our servers to shut down gracefully.
const httpServer = http.createServer(app);
// Same ApolloServer initialization as before, plus the drain plugin
// for our httpServer.
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
// Ensure we wait for our server to start
await server.start();
// Set up our Express middleware to handle CORS, body parsing,
// and our expressMiddleware function.
app.use(
'/',
cors(),
bodyParser.json(),
// expressMiddleware accepts the same arguments:
// an Apollo Server instance and optional configuration options
expressMiddleware(server, {
context: async ({ req }) => ({ token: req.headers.token }),
}),
);
// Modified server startup
await new Promise((resolve) => httpServer.listen({ port: 4000 }, resolve));
console.log(`🚀 Server ready at http://localhost:4000/`);
The code is from official documentation of apollo server, My question is, here we are first creating an apollo server and converting it to express server using expressMiddleware(server),
Will there be any issues with this conversion ?
Will we face any lack of control over the converted express server ?

My question is, here we are first creating an apollo server and converting it to express server using expressMiddleware(server),
That's not what you're doing at all.
You created an express server (const app = express()).
You created a separate http server from that app.
You created a running executable GraphQL Server.
You created an express middleware ((req, res, next) => void) that generates a context of { token?: string }, parses the body of your request into a GraphQL payload and then executes against the GraphQL Server with that context and with that payload.
You then added that express middleware to a route you created at "/", along with other middleware you attached before it.
You started the httpServer you created in #2
Will there be any issues with this conversion ?
Will we face any lack of control over the converted express server ?
This is no conversion, as mentioned. Hopefully you now understand that.
You created all of those things. Your express app is a variable called app. Do whatever you want with it. Your http server is a variable called httpServer. Do whatever you want with it.

Related

Handling endpoints APIs on client side instead of serverMiddleware in Nuxt

I'm on Nuxt 2.15.8 and trying to build an offline app with electron.js and prisma+sqlite for local DB.
In nuxt to hit a local endpoint there is a common way of using serverMiddleware and express like this:
// api.js that will be added to nuxt.config.js file as serverMiddleware
import express from 'express'
const app = express()
app.use(express.json())
export default {
path: '/api',
handler: app
}
which send endpoints beginning with api/ through app handler which I can use to access my BD (the common way to access sqlite3 DB is the same)
// added to api.js
import { PrismaClient } from '../../resources/prisma/client'
const prisma = new PrismaClient()
app.get(`/user/info`, async (req, res) => {
const result = await prisma.user.findUnique({
where: {
id: 1,
},
})
console.console.log(res);
res.json(result)
})
this will work fine on nuxt, also fine on nuxt-electron dev mode. but on built exe file serverMiddleware won't be called. So as it has be done by others (nuxt-electron accessing offline local DB) there must be a way to define endpoints on client side. any idea??
Updated:
as I changed my Nuxt-Electron boilerplate I could access serverMiddleware in exe file but it wont hit the endpoints yet!

Supertest and jest: cannot close express connection

I am using jest and supertest to raise instance of express and run tests on it.
I faced with the problem of busy port that cannot still solve.
In my test I do the next:
import supertest from 'supertest';
const agent = supertest(app);
Then I go requests with agent and everything works fine.
Until I am running another test.
In app.js I have:
var app = express();
app.post('/auth/changePassword',VerifyToken, auth.changePassword);
app.listen(4001, function () {
console.log('Server is running');
});
So first spec runs perfect. But second tries to listen to the port that is already in use.
I really do not know how to close the connection here.
I tried app.close() but got error that such method. This is clear, that I have to assign
server = app.listen(4001, function () {
console.log('Server is running');
});
server.close();
But do not know how can I do that.
I also tried to preset agent in jest.setup and assign it to global variable
import app from "../../server/app";
import supertest from 'supertest';
const agent = supertest(app);
global.agent = agent;
But situation is the same, first test passed, second tries to raise express on the same port.
Supertest is able to start and stop your app for you - you should never need to explicitly kill the express server during the tests (even when running in parallel)
The problem is that in app.js your server is actually started - this means that when the app tests are run your server is started every time app.js is read (or once per test case)
You can remedy this by splitting the server start logic into a seperate file, so that importing app.js doesn't start the app (rather returns an express server instance) The pattern I normally use for this is:
// app.js
import express from 'express'
export const app = express();
app.get("/example", (req,res) => {
return res.status(200).json({data: "running"})
})
// server.js
import app from "./app"
app.listen(3000, () => console.log("listening on 3000"));
// app.spec.js
import app from "./app"
import request from "supertest"
it("should be running", async () => {
const result = await request(app).get("/example");
expect(result.body).toEqual({data: "running"});
});

Mocking API calls with Detox and Nock

I'm trying to mock API calls from Detox tests and nothing seems to be working. Nock in theory would do exactly what I want but there when I run my tests with nock debugging it isn't seeing any of the requests being made from my app. I'm using axios to make requests and I've tried setting the adapter on my axios instance to the http adapter.
Any suggestions on how to get nock working with Detox or if there is another mocking library you have had success with is appreciated, thanks!
What I ended up doing was leveraging the mocking specified in Detox docs (a separate *.e2e.js file hitting a different endpoint during tests). You define these special files that only run during e2e, I've set mine up to only hit localhost:9091 -- I then run an Express server on that port serving the endpoints I need.
Maybe an ugly way to do it, would love suggestions!
My mock file:
// src/helpers/axios.e2e.js
import axios from 'axios';
const instance = axios.create({
baseURL: `http://localhost:9091/api`,
});
export default instance;
Here's how I am running an express server during tests:
// e2e/mytest.e2e.js
const express = require('express');
let server;
beforeAll(async () => {
const app = express();
app.post('/api/users/register/', (req, res) => {
res.status(400)
res.send({"email": ["Test error: Email is required!"]})
})
await new Promise(function(resolve) {
server = app.listen(9091, "127.0.0.1", function() {
console.log(` Running server on '${JSON.stringify(server.address())}'...`);
resolve();
});
});
})
afterAll(() => {
server.close()
})

Hooking up React Native to back-end (with Express)

I made a UI with React Native, as well as a Cheerio.js scraper (with Cron Job to activate it once every day) I'll use to grab certain data from the web, so it can render in the UI. However, I have no idea how to link the two of them.
I am pretty sure I can do this with Express (which I am most comfortable with for the back-end), but can someone tell me exactly what I need to do to connect my front-end to a back-end?
Just in case, I am a junior dev (better on the front-end than the back-end) so please keep your answers simple. Even if your answers are more conceptual, rather than code-based, I'd really appreciate it.
API
I'm quite happy with GraphQL as an alternative to REST. However, there are many ways to connect through an api. Your client needs the link to where your server is running, and your server needs to enable that.
Tutorials
I think I couldn't explain it better than this tutorial (with example on Github): https://medium.com/react-native-training/react-native-with-apollo-server-and-client-part-1-efb7d15d2361
https://medium.com/react-native-training/react-native-with-apollo-part-2-apollo-client-8b4ad4915cf5
And following Stephen Grider's tutorial on Udemy for deeper understanding of GraphQL. He is using React and not React Native in his tutorial but the syntax remains very close.
https://www.udemy.com/graphql-with-react-course/learn/v4/overview
Important notice - The first tutorials use "apollo-server" while udemy's tutorial uses graphql. apollo-server changes quite often and graphql may be clearer.
Example
Here's how my bridge between the two looks like. The biggest difficulty was dealing with Cors for the front-end version of the app (Next.js) and finding out that the server can be accessed on http://10.0.3.2:8080/graphql (may vary) instead of localhost:8080.
My index.android.js (client side):
import React from 'react'
import { AppRegistry } from 'react-native'
import App from './app'
import ApolloClient, { createNetworkInterface } from 'apollo-client';
import { ApolloProvider } from 'react-apollo'
const Client = () => {
const networkInterface = createNetworkInterface({
uri: 'http://10.0.3.2:8080/graphql'
})
const client = new ApolloClient({
networkInterface
});
return (
<ApolloProvider client={client}>
<App />
</ApolloProvider>)
}
AppRegistry.registerComponent('apolloclient', () => Client);
My app.js server side
const express = require('express');
// const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const cors = require('cors');
const chalk = require('chalk');
// New imports
// NEVER FORGET to require the models,
// in which schemas are registered for a certain model
// forgetting it would throw "Schema hasn't been registered for model..."
const models = require('./models');
const expressGraphQL = require('express-graphql');
const schema = require('./schema/schema');
const app = express();
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
// My mongoLab URI
const MONGO_URI = 'mongodb://xxx:xxx#xxx.mlab.com:xxx/xxx';
// mongoose's built in promise library is deprecated, replace it with ES2015 Promise
mongoose.Promise = global.Promise;
// Connect to the mongoDB instance and log a message
// on success or failure
mongoose.connect(MONGO_URI);
mongoose.connection.once('open', () => console.log(`${chalk.blue(`🗲 Connected to MongoLab instance 🗲`)}`));
mongoose.connection.on('error', error => console.log(`${chalk.yellow(`âš  Error connecting to MongoLab: ` + error + ` âš `)}`));
app.use(cors());
// We pass the schema as an option to our expressGraphQL middleware
app.use('/graphql', expressGraphQL({
schema,
graphiql: true
}))
module.exports = app;
my index.js (server side):
const app = require('./app');
const chalk = require('chalk');
const PORT = 8080;
app.listen(PORT, () => {
console.log(`${chalk.green(`✔ Server started on http://localhost:${PORT} ✔`)}`);
});
Assuming you're communicating with an API built with Express then use fetch as described in the docs: https://facebook.github.io/react-native/docs/network.html

React Router, pushState with an Express Server

quick question regarding using React-Router. I'm having trouble getting my server to handle pushState (if this is the correct term). Originally, I was using a module called connect-history-api-fallback, which was a middleware that enabled me to only server up static files form my dist directory. Visiting the client www.example.com obviously worked and I could navigate throughout the site, additionally, refreshing at any route like www.example.com/about - could also work.
However, I recently added one simple API endpoint on my Express server for the React app/client to ping. The problem now is that while I can get the initial page load to work (and thus the /api/news call to work, to fetch data from a remote service), I can no longer do a refresh on any other routes. For example, now going to www.example.com/about will result in a failed GET request for /about. How can I remediate this? Really appreciate the help! PS - not sure if it matters, but I'm considering implementing Server Side Rendering later on.
import express from 'express';
import historyApiFallback from 'connect-history-api-fallback';
import config from '../config';
import chalk from 'chalk';
import fetch from 'node-fetch';
import path from 'path';
const app = express();
// FIXME: Unsure whether or not this can be used.
// app.use(historyApiFallback({
// verbose : true
// }));
//// DEVELOPMENT MODE ONLY - USING EXPRESS + HMR ////
/* Enable webpack middleware for hot module reloading */
if (config.get('globals').__DEV__) {
const webpack = require('webpack');
const webpackConfig = require('../build/webpack/development_hot');
const compiler = webpack(webpackConfig);
app.use(require('./middleware/webpack-dev')({
compiler,
publicPath : webpackConfig.output.publicPath
}));
app.use(require('./middleware/webpack-hmr')({ compiler }));
}
//// PRODUCTION MODE ONLY - EXPRESS SERVER /////
if (config.get('globals').__PROD__) {
app.use(express.static(__dirname + '/dist'));
}
//// API ENDPOINTS FOR ALL ENV ////
app.get('/api/news', function (req, res) {
fetch('http://app-service:5000/news')
.then( response => response.json() )
.then( data => res.send(data) )
.catch( () => res.sendStatus(404) );
});
// Wildcard route set up to capture other requests (currently getting undexpected token '<' error in console)
app.get('*', function (req, res) {
res.sendFile(path.resolve(__dirname, '../dist', 'index.html'));
});
export default app;
Express works by implementing a series of middleware that you "plug in" in order via .use. The cool thing is your routes are also just middlware — so you can separate them out, have them before your history fallback, and then only requests that make it past your routes (e.g., didn't match any routes) will hit the fallback.
Try something like the following:
const app = express();
// ...
var routes = exprss.Router();
routes.get('/api/news', function (req, res) {
fetch('http://app-service:5000/news')
.then( response => response.json() )
.then( data => res.send(data) )
.catch( () => res.sendStatus(404) );
});
app.use(routes);
app.use(historyApiFallback({
verbose : true
}));