How to Integrate Rest Api with GraphQL Gateway and send Context - rest

I use GraphQL Gateway to integrate with GraphQL Federation Microservices .
but I use some Rest API code for some reason. like(refresh token , Upload Images with rest)
The Question is : how to communicate with Rest API for the other services from graphql gateway and how to send context to the controller(rest api) server.
import { IntrospectAndCompose, RemoteGraphQLDataSource } from '#apollo/gateway';
import { ApolloGatewayDriver, ApolloGatewayDriverConfig } from '#nestjs/apollo';
import { Module } from '#nestjs/common';
import { GraphQLModule } from '#nestjs/graphql';
import { AppController } from './app.controller';
#Module({
imports: [
GraphQLModule.forRoot<ApolloGatewayDriverConfig>({
driver: ApolloGatewayDriver,
server: {
// ... Apollo server options
context: ({ req, res }) => ({
authorization:req.headers.authorization,
req,
res,
url: req.protocol + '://' + req.headers.host,
}),
cors: true,
},
gateway: {
buildService({ name, url }) {
return new RemoteGraphQLDataSource({
url,
willSendRequest({ request, context }) {
request.http.headers.set('authorization',context['authorization'] );
}
});
},
supergraphSdl: new IntrospectAndCompose({
subgraphs: [
{ name: 'Service1', url: 'http://localhost:3001/graphql' },
{ name: 'Service2', url: 'http://localhost:3002/graphql' },
{ name: 'Service3' , url: 'http://localhost:3003/graphql' }
],
}),
},
}),
],controllers:[AppController]
})
export class AppModule { }
Note: if I removed '/graphql' from Url to access origin url , it gives me error[Couldn't load service definitions for service1] .
This code works fine with GraphQL but didn't work with Rest.
Server : NestJS.
Thanks..

Your question is not super clear but let me take a stab at it.
You can use a service like WunderGraph on top of your existing gateway or you can create a new gateway and ingest the GraphQL Federated Microservices. You can then introspect the REST API and ingest it into your gateway. .

Related

MERN Project Deploy to Heroku, axios function fail

I tried to deploy my local running MERN stack project to Heroku. The UI is showing fine, but the axios calls continue to fail. Here is how I wrote the axios URL.
axiosConfig.js:
import axios from "axios";
const api = axios.create({
baseURL: process.env.REACT_APP_BASE_URL // or process.env.BASE_URL if not using CRA
});
export default api
Arrival.js:
import api from '../../axiosConfig';
const Arrivals = () => {
const baseURL = api || "http://localhost:5000";
useEffect(() => {
axios.get(baseURL + '/flights/arrivals/' + timeDuration)
.then((response) => {
setData(response.data);
console.log(data)
})
.catch(err => {
console.log(err)
})
}, [timeDuration]);//eslint-disable-line
When I call the api, the network showing it's tring to get from:
https://minions-airport-202.herokuapp.com/function()%7Breturn%20e.apply(t,arguments)%7D/flights/arrivals/28800000
And it is getting 500 Internal Server Error. Any idea why?

Nuxt vuex - moving store from Vue

I have been fiddling with moving a tutorial I did in Vue to Nuxt. I have been able to get everything working, however I feel I'm not doing it the "proper way". I have added the Nuxt axios module, but wasnt able to get it working, so I ended up just using the usual axios npm module. Here is my store:
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(Vuex)
Vue.use(VueAxios, axios)
export const state = () => ({
events: []
})
export const mutations = {
setEvents: (state, events) => {
state.events = events
}
}
export const actions = {
loadEvents: async context => {
let uri = 'http://localhost:4000/events';
const response = await axios.get(uri)
context.commit('setEvents', response.data)
}
}
I would like to know how to re-write this store using the #nuxtjs/axios module. I also didnt think I'd need to import vuex here, but if I dont, my app doesn't work.
Thanks for any help!
Using the #nuxtjs/axios module, you can configure axios inside your nuxt.config.js:
// nuxt.config.js
export default {
modules: [
'#nuxtjs/axios',
],
axios: {
// proxy: true
}
}
You can use it inside your store (or components) with this.$axios
// In store
{
actions: {
async getIP ({ commit }) {
const ip = await this.$axios.$get('http://icanhazip.com')
commit('SET_IP', ip)
}
}
}

Automatic request signing with API Gateway REST API and Amplify

This https://aws-amplify.github.io/docs/js/api#signing-request-with-iam says AWS Amplify provides the ability to sign requests automatically ..is this the same with API gateway REST requests that are restricted by Cognito?
auth.currentSession().then(token => {
console.log('>>>>', token.getIdToken().getJwtToken());
authToken = token.getIdToken().getJwtToken();
const myInit = { // OPTIONAL
headers: {
Authorization: authToken
},
response: true,
};
api.get(apiName, path, myInit).then(response => {
// Add your code here
console.log(response);
}).catch(error => {
console.log(error.response);
});
}
);
but I get Authorization header requires 'Credential' parameter. Authorization header requires 'Signature'
But in angular this does not work as Auth.currentSession() does not compile
endpoints: [
{
name: 'test',
endpoint: 'https://xyz.execute-api.us-west-2.amazonaws.com/test',
custom_header: async () => {
// Alternatively, with Cognito User Pools use this:
return {Authorization: (await Auth.currentSession()).idToken.jwtToken};
}
}
]
}
Resolved had typo with the request url it had to be /items/:test where test was the partition name in dynamo, also the
headers: {
Authorization: token
},
is not required:
https://github.com/aws-amplify/amplify-js/issues/2810#issuecomment-470213459

Angular 2 & ionic 2 http request with basic authentification error

I have some problems with Angular 2 http get request in a ionic 2 application.
In fact I have a website (made with the Jalios CMS) which is running currently with an Apache tomcat on localhost:8080 and I want to access data from my ionic app with RESTful Web services. To access to this website the users need to log in, and their passwords can contain special charactere like #,#.:?
When I use the cURL command, I can access data without any problems. Data are returned in xml.
curl -u username:p#ssword http://localhost:8080/jcms/rest/data/Article
However in my ionic 2 application I have the following errors:
OPTIONS http:/ /localhost:8080/jcms/rest/data/Article 401 (Non-Autoris%E9). polyfills.js:3
XMLHttpRequest cannot load http:/ /localhost:8080/jcms/rest/data/Article. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http:/ /localhost:8100' is therefore not allowed access. The response had HTTP status code 401. (index):1
ERROR Response {_body: ProgressEvent, status: 0, ok: false, statusText: "", headers: Headers…}. core.es5.js:1084
my http provider: rest-service.ts
import { Injectable } from '#angular/core';
import { Http, Headers } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class RestService {
constructor(public http: Http) {
console.log('Hello RestService Provider');
}
httpGet(username: string, password: string, resource: string){
let url = 'http://localhost:8080/jcms/rest/data/' + resource;
let headers: Headers = new Headers();
headers.append("Authorization", "Basic " + btoa(username + ":" + password));
return this.http.get(url, {headers: headers});
}
}
my Ionic page (component): home.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import {RestService} from "../../providers/rest-service";
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
result: Array<any>;
constructor(public navCtrl: NavController, private restService: RestService) {
this.restServiceGet();
}
restServiceGet(){
this.restService.httpGet('username', 'p#ssword', 'Article')
.map(res => res.json())
.subscribe(data => this.result = data);
}
}
Normally all have been correctly imported in the app.module.ts file. I also try to change the special character by URL Encoding (%40 for #), and replace the btoa directly by the base 64 equivalence of username:p#assword.
Can you help me to correct this errors? Especially the 401 unauthorized because I d'ont understand why it happen whereas I implemented the headers with the basic authentification. Where are my mistakes?
Thank you

Using Grunt to Mock Endpoints

I'm using Yeoman, Grunt, and Bower, to construct a platform for building a frontend independently of a a backend. The idea would be that all of my (AngularJS) controller, services, factories, etc live in this project, and get injected afterwards into my serverside codebase based off the result of grunt build.
My question is:
How can I mock endpoints so that the Grunt server responds to the same endpoints as my (Rails) App will?
At the moment I am using:
angular.module('myApp', ['ngResource'])
.run(['$rootScope', function ($rootScope) {
$rootScope.testState = 'test';
}]);
And then in each of my individual services:
mockJSON = {'foo': 'myMockJSON'}
And on every method:
if($rootScope.testState == 'test'){
return mockJSON;
}
else {
real service logic with $q/$http goes here
}
Then after grunt build, testState = 'test' gets removed.
This is clearly a relatively janky architecture. How can I avoid it? How can I have Grunt respond to the same endpoints as my app (some of which have dynamic params) apply some logic (if necessary), and serve out a json file (possibly dependent on path params)?
I've fixed this issue by using express to write a server that responds with static json.
First I created a directory in my project called 'api'. Within that directory I have the following files:
package.json:
{
"name": "mockAPI",
"version": "0.0.0",
"dependencies": {
"express": "~3.3.4"
}
}
Then I run npm install in this directory.
index.js:
module.exports = require('./lib/server');
lib/server.js:
express = require('express');
var app = express();
app.get('/my/endpoint', function(req, res){
res.json({'foo': 'myMockJSON'});
});
module.exports = app
and finally in my global Gruntfile.js:
connect: {
options: {
port: 9000,
hostname: 'localhost',
},
livereload: {
options: {
middleware: function (connect, options) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
require('./api')
];
}
}
},
Then the services make the requests, and the express server serves the correct JSON.
After grunt build, the express server is simply replaced by a rails server.
As of grunt-contrib-connect v.0.7.0 you can also just add your custom middleware to the existing middleware stack without having to manually rebuild the existing middleware stack.
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
],
middleware: function(connect, options, middlewares) {
// inject a custom middleware into the array of default middlewares
middlewares.push(function(req, res, next) {
if (req.url !== '/my/endpoint') {
return next();
}
res.writeHead(200, {'Content-Type': 'application/json' });
res.end("{'foo': 'myMockJSON'}");
});
return middlewares;
}
}
},
See https://github.com/gruntjs/grunt-contrib-connect#middleware for the official documentation.
Alternatively you can use the grunt-connect-proxy to proxy everything that is missing in your test server to an actual backend.
It's quite easy to install, just one thing to remember when adding proxy to your livereload connect middleware is to add it last, like this:
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
proxySnippet
];
}
grunt-connect-prism is similar to the Ruby project VCR. It provides an easy way for front end developers to record HTTP responses returned by their API (or some other remote source) and replay them later. It's basically an HTTP cache, but for developers working on a Single Page Application (SPA). You can also generate stubs for API calls that don't exist, and populate them the way you want.
It's useful for mocking complex & high latency API calls during development. It's also useful when writing e2e tests for your SPA only, removing the server from the equation. This results in much faster execution of your e2e test suite.
Prism works by adding a custom connect middleware to the connect server provided by the grunt-contrib-connect plugin. While in 'record' mode it will generate a file per response on the filesystem with content like the following:
{
"requestUrl": "/api/ponies",
"contentType": "application/json",
"statusCode": 200,
"data": {
"text": "my little ponies"
}
}
DISCLAIMER: I'm the author of this project.
You can use Apache proxy and connect your REST server with gruntjs.
Apache would do this:
proxy / -> gruntjs
proxy /service -> REST server
you would use your application hitting Apache and angular.js application would think that is talking with itself so no cross domain problem.
Here is a great tutorial on how to set this up:
http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/
Just my alternative way that based on Abraham P's answer. It does not need to install express within 'api' folder. I can separate the mock services for certain files. For example, my 'api' folder contains 3 files:
api\
index.js // assign all the "modules" and then simply require that.
user.js // all mocking for user
product.js // all mocking for product
file user.js
var user = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'role' : 'admin'
})
);
}
else {
next();
}
}
module.exports = user;
file product.js
var product = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'name' : 'test',
'category': 'test'
})
);
}
else {
next();
}
}
module.exports = product;
index.js just assigns all the "modules" and we simply require that.
module.exports = {
product: require('./product.js'),
user: require('./user.js')
};
My Gruntfile.js file
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app),
require('./api').user,
require('./api').product,
];
}
}
}