Cloud Endpoints API does not authorise Google APIs Explorer after upgrading to App Engine 1.9.0 - google-app-engine

I use the Google APIs Explorer to test my Cloud Endpoint API running on the local dev server. I have authentication turned on:
#Api(
name = "testapi",
version = "1.0",
description = "Test API",
clientIds = { ApiConstants.WEB_CLIENT_ID, ApiConstants.ANDROID_CLIENT_ID,
ApiConstants.IOS_CLIENT_ID, ApiConstants.EXPLORER_ID },
audiences = { ApiConstants.ANDROID_AUDIENCE })
public class TestAPI
{
#ApiMethod(name = "TextObject.get", path = "testobject/{id}")
public TestObject get(#Named("id") Long id, User user) throws OAuthRequestException
{
if (user == null)
{
throw new OAuthRequestException(
"No User specified when calling protected API method.");
}
...
where ApiConstants.EXPLORER_ID is set to:
public static final String EXPLORER_ID = com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID;
Everything worked fine in 1.8.9, and it works fine again when downgrading to 1.8.9. In 1.9.0, I get a null user in the code, and the "This method requires you to be authenticated." message in the explorer, even after logging in on the slider.
For now, I'll just hold off upgrading to 1.9.0, but I do want to upgrade at some stage to try out the Modules API.
Any ideas? Many thanks in advance.

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.

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.

My Google cloud endpoint API is not visible on the api explorer

I am very new to google app engine and endpoints and have been writing basic endpoint functions and deploying to the cloud. I succesfully deployed a HelloWorld endpoint and tested it over the API explorer: http://localhost:8080/_ah/api/explorer
But now when I have created a new endpoint API and followed the same steps (i.e deployed using new APP engine application name in the appengine-web.xml, run as appengine:update), the api explorer still shows my HelloWorld endpoint instead of my new API "yourfirstendpoint".
I've searched and tried to find an answer to no avail - and im sorry if this is a very basic and stupid question on my part (im sure it is) but i would realy appreciate if somebody could point me in the right direction on what i should be doing.
My API
package com.example.zinglife;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiMethod.HttpMethod;
import com.google.api.server.spi.response.NotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
/**
*
* Defines endpoint functions APIs.
*/
#Api(name = "yourfirstapi", version = "v1",
scopes = {Constants.EMAIL_SCOPE },
clientIds = {Constants.API_EXPLORER_CLIENT_ID},
description = "API for hello world endpoints.")
public class YourFirstAPI
{
#ApiMethod(name = "storeUserModel")
private User storeUserModel(User user) throws NotFoundException
{
String email = user.getEmail();
Key key = KeyFactory.createKey("User",email);
User userEntity = null;
try
{
if (userEntity==null)
{
userEntity = new User();
userEntity.setName(user.getName());
userEntity.setEmail(user.getEmail());
userEntity.setCountry(user.getCountry());
//
}
return userEntity;
}//*endtry
finally
{
}
}
}
The App engine Administrator Log after running the code:
Please let me know if any other information is needed :)
Make sure you have added your new service as one of the values for the 'services' parameter of the EndPointsServlet.
<servlet>
<!-- This is version 2.0 of the endpoints framework. -->
<servlet-name>EndpointsServlet</servlet-name>
<servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<!-- Comma separated classes that provide endpoints -->
<param-value>
com.mycompany.myproduct.endpoint.SomeServiceV1,
com.mycompany.myproduct.endpoint.SomeServiceV2,
com.mycompany.myproduct.endpoint.SomeOtherServiceV1,
com.mycompany.myproduct.endpoint.SomeOtherServiceV2,
com.mycompany.myproduct.endpoint.SomeOtherServiceV3
</param-value>
</init-param>
</servlet>

Access remote service using GWTP Rest Dispatch

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.

Generate Google Cloud Endpoints - Android studio

I've been trying to add a Google Cloud Backend to my android application using Android Studio. I've been following along with this I/O talk: http://youtu.be/lmv1dTnhLH4?t=37m2s and I realise that things have changed a bit from back then. In the video, he generates an endpoint be right clicking on a java file like the one below then selecting 'Generate Cloud Endpoint' which produces an endpoint java class he can then use in his app. I'm using Android Studio v0.5.6 and that option doesn't seem to be there any more. It seems all of the Android studio documentation relating to App Engine integration I've found on the internet hasn't been updated. Could anyone point me in the right direction to get this set up using the latest versions of Android Studio.
To add the backend I selected Tools > Google Cloud Tools > Add App Engine Backend:
Class I am trying to create an endpoint for:
User class:
package com.test.lol;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import java.util.Date;
#Entity
public class User {
#Id
private String mID;
private String mFirstName;
private String mLastName;
private String mEmail;
private String mBirthday;
private Date mLastSeen;
public String getID() {
return mID;
}
public void setID(String ID) {
this.mID = ID;
}
public String getFirstName() {
return mFirstName;
}
public void setFirstName(String firstName) {
mFirstName = firstName;
}
public String getLastName() {
return mLastName;
}
public void setLastName(String lastName) {
mLastName = lastName;
}
public String getEmail() {
return mEmail;
}
public void setEmail(String email) {
mEmail = email;
}
public String getBirthday() {
return mBirthday;
}
public void setBirthday(String birthday) {
mBirthday = birthday;
}
public Date getLastSeen() {
return mLastSeen;
}
public void setLastSeen(Date lastSeen) {
mLastSeen = lastSeen;
}
}
Google have acknowledged this feature is missing and are working to implement it.
Source: https://code.google.com/p/android/issues/detail?id=68223
Edit: This feature has been implemented in the beta version of Android Studio
In the mean time, I:
Was able to use the Google Endpoint documentation to figure out
which annotations to use for the Endpoint API.
Checked out the Objectify Documentation to figure out which
annotations to use for Entities and Datastore persistance.
Uploaded my code to app engine using the terminal command: gradlew appengineUpdateAll
Installed the android client libraries to my local Maven repository using the terminal command: gradlew appengineEndpointsInstallClientLibs
Followed this tutorial on how to add the google API client to my Gradle project.
Added the local Maven repo to my projects build.gradle file and the client library as a dependency in my app's build.gradle
Used the Endpoint in my app.
Double fist pumped the air with great elation and proclaimed "I am the master commander!"
Finally Google Cloud Backend has been added again in Android Studio 0.6.1:
http://android-developers.blogspot.it/2014/06/new-ways-to-connect-your-app-to-the-cloud-android-studio.html

Resources