Access remote service using GWTP Rest Dispatch - google-app-engine

I want to separate packages for UI and backend development of my GWTP app.
Currently my UI access the backend using Rest dispatch configured like this:
bindConstant().annotatedWith(RestApplicationPath.class).to("/MyProject/api");
I want to access remote service using localhost UI (running GWT app using eclipse plugin). I changed the above line to:
bindConstant().annotatedWith(RestApplicationPath.class).to("http://my-app.appspot.com/MyProject/api");
Using this, call successfully reaches server ( I can see this in appengine logs) but UI always gets back status code 0.
What is wrong with above setup? Do I have to do something else to access remote service using GWT ui ?

If you want to have a solution that works both on localhost/App Engine, you'd want to use something like this:
import com.google.gwt.core.client.GWT;
import com.google.gwt.inject.client.AbstractGinModule;
import com.google.inject.Provides;
import com.gwtplatform.dispatch.rest.client.RestApplicationPath;
import com.gwtplatform.dispatch.rest.client.gin.RestDispatchAsyncModule;
public class ServiceModule extends AbstractGinModule {
#Override
protected void configure() {
install(new RestDispatchAsyncModule.Builder().build());
}
#Provides
#RestApplicationPath
String getApplicationPath() {
String baseUrl = GWT.getHostPageBaseURL();
if (baseUrl.endsWith("/")) {
baseUrl = baseUrl.substring(0, baseUrl.length() - 1);
}
return baseUrl + "/MyProject/api";
}
}
The string returned by getApplicationPath will be bound to #RestApplicationPath and used seamlessly by GWTP's RestDispatch.
In your case, the string will resolve to http://localhost:8080/MyProject/api or "http://my-app.appspot.com/MyProject/api" depending on the app running locally or on App Engine.

Related

Axios API request from React Native frontend to local spring backend service not working

I develop a React Native mobile app and for the backend I want to use Java Spring.
Now I have a standalone backend server running locally on port 8080 and my react native app is runned via Expo Go app with npm start.
For this question I have built a very simple example.
In the frontend application I want to do a GET request to retrieve a string back from the backend and I am using axios to send API requests.
The problem is that I get a Network Error error whenever I send the GET request to http://localhost:8080/
// dont bother func name
const loginUser = () => {
axios.get("http://localhost:8080/").then(value => {
console.log(value)
}).catch(err => {
console.log("REQUEST FAILED")
console.log(err)
})}
This is the handler when user presses a button axios request is send, Expected output: "Hello World"
output:
REQUEST FAILED
Network Error
at node_modules\axios\lib\core\createError.js:17:22 in createError
at node_modules\axios\lib\adapters\xhr.js:120:6 in handleError
at node_modules\event-target-shim\dist\event-target-shim.js:818:20 in EventTarget.prototype.dispatchEvent
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:600:10 in setReadyState
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:395:6 in __didCompleteResponse
at node_modules\react-native\Libraries\vendor\emitter\EventEmitter.js:189:10 in emit
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:416:4 in __callFunction
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:109:6 in __guard$argument_0
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:364:10 in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:108:4 in callFunctionReturnFlushedQueue
#RestController
//#CrossOrigin(origins = "*")
public class TestController {
#GetMapping("/")
public String hello(){
return "Hello World";
}
}
Simple Spring REST Controller
#SpringBootApplication
public class JpaApplication {
public static void main(String[] args) {
SpringApplication.run(JpaApplication.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedMethods("GET","POST","PUT","DELETE").allowedHeaders("*").allowedOrigins("*");
}
};
}
}
CORS Config just allowing all
I have tried putting the annotation #CrossOrigin(origins = "*") above the controller but it did not help (seen from: React and Axios : Axios Can't Access Java/SpringBoot REST Backend Service Because of CORS Policy). I have allowed all access from all locations in the CORS config but I get the same output. The example is very simple. I just want to get a simple string back and the solution is probably also very simple but after so many tries I can't come up with a solution. If I visit the URL on the browser I get the expected value, but via axios request it does not seem to work.
After some more searching I found it is not possible to send requests directly to localhost on a Android emulator, on IOS there is no problem. So the problem was after all on the React Native side.
So the fix was relatively easy and also found on stackoverflow, the following thread helped a lot: React Native Android Fetch failing on connection to local API.
I Installed ngrok and this generates a URL which I can use to temporary test my backend till I have hosted it.

How Do I Configure REST Urls When Running React With Azure API-Management?

I have a reactjs front end that gets data from a spring boot backend via rest calls.
Running locally the code for this looks like:
axios.defaults.baseURL = 'http://localhost:8080/api';
axios.get('/devices').then((resp) => {
this.setState({devices: resp.data});
}).catch(() => {
console.log('Failed to retrieve device details');
});
When I build the code to deploy with npm run build I still have localhost as the url.
How do I build it so that developing locally it uses localhost but deploying it uses a different url?
Once I am in Azure I will have one front end and multiple back ends that need to be pointed to depending on who is logged in.
How do I configure the API-Management layer to route the calls to the correct back end depending on who is logged in (using AD for auth)?
Since I am using APIM for the routing, what should the baseURL be?
Manage those variables in a config file and load based on the environment.
Local Values
you can hardcode local variable directly in a config file
Production Values
- keep place holders and set them from build pipeline or
- hard code them also
E.g:
config.js
const serverVars = {
authUrl: '#{authUrl}#',
apiUrl: '#{apiUrl}#',
};
const localVars = {
authUrl: 'local_auth_url',
apiUrl: 'local_api_url',
};
export function getConfiguration() {
if (process.env.NODE_ENV === 'production') {
return serverVars;
}
return localVars;
}
when you call apiUrl
import axios from 'axios';
import { getConfiguration } from 'config';
axios.defaults.baseURL = getConfiguration().apiUrl;
One approach can be using environment variable. You can have different url based on the environment variable.
Another way is just removing the domain from base url, but this will work only when your backend and frontend domain & port are identical.

Updating index.android.bundle from remote server in react native [Android]

I am creating a demo react native app that is implementing aeroFS https://github.com/redbooth/react-native-auto-updater library
[An aerofs library is nothing but each time when app opens it will check for update from remote server and if update is available it will download and ask the user to apply for the update without play store].
So far the app is able to download the file but after download i am not able to see any changes in the app.I'm sure the newly downloaded bundle is not used in the activity.
On further checking inside the library i found the following method in ReactNativeAutoUpdaterActivity class (main class):-
#Override
#Nullable
public String getJSBundleFile() {
updater=ReactNativeAutoUpdater.getInstance(this.getApplicationContext());
updater.setMetadataAssetName(this.getMetadataAssetName());
return updater.getLatestJSCodeLocation();
}
The ReactNativeAutoUpdaterActivity extends from ReactActivity which does not have this method.I think this is moved to ReactNativeHost so i knew this is the problem but now should i implement my own react native host class to over ride the method so that once new bundle file is downloaded i can apply it to app.
MainApplication.java
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
.
.
.
#Override
public void onCreate(){
super.onCreate();
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
preferences.edit().putString("debug_http_host", "128.xxx.xxx.xxx:1234").apply();
}
When using a remote VM, port 8081 is not exposed, so:
npm start -- --reset-cache --port=1234
AppDelegate.m (iOS):
jsCodeLocation = [NSURL URLWithString:#"http://128.xxx.xxx.xxx:1234/index.js"];

Spring-boot: add application to tomcat server

I have a back-end which is build on spring-boot and then some custom code from my school built upon that.
The front-end is pure angular application which I serve from a different server trough a gulp serve.
They're only connected by REST calls.
There's already an authentication module running on the backend and to now I need to serve this angular application from the same tomcat server the back-end is running on so it can also use this authentication module.
I've found this about multiple connectors so I copied it as following class to set up multiple connectors:
#ConfigurationProperties
public class TomcatConfiguration {
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();
//tomcat.addAdditionalTomcatConnectors(createSslConnector());
return tomcat;
}
private Connector createSslConnector() {
Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
try {
File keystore = new ClassPathResource("keystore").getFile();
File truststore = new ClassPathResource("keystore").getFile();
connector.setScheme("https");
connector.setSecure(true);
connector.setPort(8443);
protocol.setSSLEnabled(true);
protocol.setKeystoreFile(keystore.getAbsolutePath());
protocol.setKeystorePass("changeit");
protocol.setTruststoreFile(truststore.getAbsolutePath());
protocol.setTruststorePass("changeit");
protocol.setKeyAlias("apitester");
return connector;
} catch (IOException ex) {
throw new IllegalStateException("can't access keystore: [" + "keystore"
+ "] or truststore: [" + "keystore" + "]", ex);
}
}
}
Problem is that I don't see or find how I should setup these connectors so they serve from my angularJS build folder.
Upon searching I came upon Spring-Boot : How can I add tomcat connectors to bind to controller but I'm not sure if in that solution I should change my current application or make a parent application for both applications.
My current application main looks like this:
#Configuration
#ComponentScan({"be.ugent.lca","be.ugent.sherpa.configuration"})
#EnableAutoConfiguration
#EnableSpringDataWebSupport
public class Application extends SpringBootServletInitializer{
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
If possible I'd like some more info about what connectors are in the spring-boot context.
If this is not the way to go I'd like someone to be able to conform this second solution or suggest a change in my code.
I'm really not sure enough about these solution that I want to go breaking my application over it. (though it's backed up with github)
Just place your AngularJS + other front-end assets into src/main/resources/static folder, Spring Boot will serve them automatically.

Spring + Angular set up and security

I am wondering what the best way is to setup a project that contains a Spring RESTful API along with the ability to serve up static Angularjs pages to consume the RESTful web service. The below implementation works but I am now looking to add security into the application and I am unsure how to apply Spring Security to both the REST Api and the static pages.
Is the below setup correct for my end goal?
How do I secure both the REST Api && the static pages?
I have the following project structure
Servlet Config
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
#ComponentScan
public class WebAppInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addFilter("corsFilter", new CORSFilter());
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(WebMvcConfig.class);
ctx.setServletContext(servletContext);
Dynamic dynamic = servletContext.addServlet("dispatcher", new DispatcherServlet(ctx));
dynamic.addMapping("/api/*");
dynamic.setLoadOnStartup(1);
}
}
I would follow the series of articles on spring.io blog that explains exactly what you are looking for: Spring + Security + Angular JS.
Here the articles:
http://spring.io/blog/2015/01/12/spring-and-angular-js-a-secure-single-page-application
https://spring.io/blog/2015/01/12/the-login-page-angular-js-and-spring-security-part-ii
http://spring.io/blog/2015/01/20/the-resource-server-angular-js-and-spring-security-part-iii
http://spring.io/blog/2015/01/28/the-api-gateway-pattern-angular-js-and-spring-security-part-iv
http://spring.io/blog/2015/02/03/sso-with-oauth2-angular-js-and-spring-security-part-v

Resources