How to configure emberjs routes in SpringMVC? - spring-mvc

We have an Ember frontend and Spring Boot backend.
When Ember runs standalone on port 4200 and the Spring Boot backend on 8080, then everything works. But this scenario is somewhat unusual for production environments, not only because of CORS problem. The URL of the backend must be known already on build time (!) of the Ember application, because it's integrated within the compiled ember app. This is not possible for many projects. Therefore, we want to integrate the frontend Ember App in the Spring Boot backend, which is usual for e.g. SPA with AngularJS.
The Ember app (from /dist) is thus copied to src/main/resource/static. After adjusting the rootURL and API.host with the Ember app that works very well.
The problem arises now, when a manual reload for an URL is made in the browser. Such a URL is now an Ember route. The http-request arrives at the Spring Boot backend which don't knows the route and we got a 404 error.
How should SpringMVC (as part of the Spring Boot backend) answers the httpRequest for such a route, so that the Ember app continue their work and handle the request ?
HTML Page request (by browser)
http://host/springBootAppContext/index.html => src/main/resource/static/index.html (ember app)
REST API request (by Ember App)
http://host/springBootAppContext/users => RESTController mapped for /users
Ember Routing (by Ember App)
http://host/springBootAppContext/user-list => ???
You can't provide a normal Spring MVC #Controller class because the ModelView response is interpretet as user-list.html or similar which doesn't exist

after tests with different solutions I came up with a really simple one.
Provide a normal, non-REST controller with request mappings for every route defined by the ember app. Every such request have to be answered with the view name of the ember app start page (index.html in most cases). The browser loads that html page and starts the containing ember app. The ember app detects the route (because the route was part of the http request) and work according all specified route configurations (template, model, controller).
No 404 NotFound any more.
#Controller
public class EmberRouteController {
public static final String INDEX = "index.html";
#RequestMapping(value = "/ember-route-1", method = RequestMethod.GET)
public String emberRoute1() {
return INDEX;
}
#RequestMapping(value = "/ember-route-2", method = RequestMethod.GET)
public String emberRoute2() {
return INDEX;
}
}

The previous answer helped me a lot. But I was still thinking of better solution than creating backend APIs for each route. And I feel the better solution would be to put '#' in before ember route then ember routes serves the request rather than going to the backend server.
Router.reopen({
location: 'hash'
});
Ex: http://localhost:8008/#/first
Here first is my route. And I have put # in the URL, now reload of the page is working.
Hope this will help.

Related

Asp .Net Identity Server - Allow wildcard redirect URLs for Vercel

I'm using Duende IdentityServer with RestApi as back-end and I'm using Vercel to test the front-end but can't login to the IdentityServer with vercel because of the redirectUrl of vercel is not allowed.
I did see some information about it in other questions but it is from few years back and not really covering the issue, I wonder if someone manage to implement a solution for that in identityserver and can share the information and code.
I know wildcard redirect URLs are bad because of security reasons but this is just for develop environment and not going to be part of release.
I'm just starting to get into Asp .Net and any help will be appreciate!
One option is to use the AddAppAuthRedirectUriValidator extension method which:
Adds a an “AppAuth” (OAuth 2.0 for Native Apps) compliant redirect URI
validator (does strict validation but also allows http://127.0.0.1
with random port).
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddAppAuthRedirectUriValidator();
If this is still not enough, you can register your own redirect URI validator using the AddRedirectUriValidator extension method:
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddRedirectUriValidator<MyRedirectUriValidator>();
MyRedirectUriValidator.cs:
// allows arbitrary redirect URIs - only for demo purposes. NEVER USE IN PRODUCTION
public class MyRedirectUriValidator : IRedirectUriValidator
{
public Task<bool> IsPostLogoutRedirectUriValidAsync(string requestedUri, Duende.IdentityServer.Models.Client client)
{
return Task.FromResult(true);
}
public Task<bool> IsRedirectUriValidAsync(string requestedUri, Duende.IdentityServer.Models.Client client)
{
return Task.FromResult(true);
}
}
Duende IdentityServer DI Extension Methods

Service Fabric Web API Versioning issue

I'm working on a service fabric project with multiple stateless services. When i try to add versioning as in the code below
[Authorize]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class SessionController : Controller
{
...
}
it's not working when calling the service later using Postman or using some client winforms app i made just to call this service. And when i say it's not working i mean it's not looking for a specific version i placed in the controller.
e.g.
I'm calling http://localhost:1234/api/v1.0/session/set-session and as you can see in my controller i only have version 2.0. Now my API gets hit this way or another no matter what version number i put in.
I added code to the Startup.cs
services.AddApiVersioning(options => {
options.DefaultApiVersion = new ApiVersion(2, 0);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
options.ApiVersionReader = new HeaderApiVersionReader("x-api-version");
});
Specific API call looks like this:
[HttpPost]
[Route("set-session")]
public async Task<IActionResult> SetSession([FromBody] SessionModel model)
{ ... }
Can anyone tell me what am i missing or maybe api versioning is not supported in service fabric at all?
Thanks.
Does your solution work locally? Based on what I see, I would suspect - no. This should have nothing to do with Service Fabric at all.
Issue 1
I see that your base class inherits from Controller, which is allowed, but is usually ControllerBase. No concern there, just FYI. The crux of the problem is likely that your controller has not applied the [ApiController] attribute. API Versioning defines IApiControllerSpecification and IApiControllerFilter, which is used to filter which controllers should be considered an API. This is important for developers building applications that have the UI and API parts mixed. A controller is a controller in ASP.NET Core and it was difficult to distinguish these two in the early days. There is now a built-in IApiControllerSpecification that considers any controller with [ApiController] applied to be an API. This can be changed, replaced, or completely disabled using ApiVersioningOptions.UseApiBehavior = false.
If your library/application is only APIs, you can decorate all controllers at once using:
[assembly: ApiController]
Since your controller is not currently being considered an API, all requests matching the route are being directed there. The value 1.0 is being considered an arbitrary string rather than an API version. This is why it matches at all instead of HTTP 400. I suspect you must only have one API and it is defined as 2.0; otherwise, I would expect an AmbiguousActionException.
Issue 2
Your example shows that you are trying to version by URL segment, but you've configured the options to only consider the header x-api-version. This option should be configured with one of the following:
URL Segment (only)
options.ApiVersionReader = new UrlSegmentApiVersionReader();
URL Segment and Header
// registration order is irrelevant
options.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new HeaderApiVersionReader("x-api-version"));
Default (Query String and URL Segment)
// NOTE: this is the configuration
// options.ApiVersionReader = ApiVersionReader.Combine(
// new QueryStringApiVersionReader(),
// new UrlSegmentApiVersionReader());
Side Note
As defined, using the URL segment and header versioning methodologies don't make sense. You have a single route which requires an API version. A client will always have to include the API version in every request so there is no point to also supporting a header.
If you define 2 routes, then it makes sense:
[Route("api/[controller]")] // match by header
[Route("api/v{version:apiVersion}/[controller]")] // match by url segment
Versioning by URL segment, while common, is the least RESTful. It violates the Uniform Interface constraint. This issue demonstrates yet another problem with that approach. Query string, header, media type, or any combination thereof will all work with the single route template of: [Route("api/[controller]")]
Observation 1
You have configured options.AssumeDefaultVersionWhenUnspecified = true. This will have no effect when versioning by URL segment. It is impossible to provide a default value of route parameter in the middle of a template. The same would be true for api/value/{id}/subvalues if {id} is not specified.
This option will have an effect if you:
Add a second route template that doesn't have the API version parameter
You update your versioning strategy to not use a URL segment
It should be noted that is a highly abused feature. It is meant to grandfather in existing services that didn't previously have explicit versioning because adding it will break existing clients. You should be cognizant of that if that isn't your use case.

ServletUriComponentsBuilder.fromRequest return http scheme instead of https

I have a web application composed by frontend code that invokes the same api implemented by two backend modules. This api returns a url in a JSON object. The backend modules are both written with spring mvc but in different versions.
The url-building is the same and it is something like this:
#GetMapping(path = "/app1/menu", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public JsonObject getMenu(HttpServletRequest req) throws IOException {
JsonObject menu = new JsonObject();
menu.addProperty("href", ServletUriComponentsBuilder.fromRequest(req)
.replacePath(req.getContextPath())
.path("/index.html")
.toUriString());
return menu;
}
As you can see this code simply adds a constant to the incoming request and returns it.
The first app uses spring mvc 4 (4.3.5.RELEASE precisely).
The second module uses the 5.1.4.RELEASE version.
When all these apps are deployed on a load balanced server (2 tomcat instance with a load balancer upfront) and https the problem shows up.
Say that the request url is, for app1, something like this:
https://example.com/context/app1/menu
The app1 returns correctly
https://example.com/context/index.html
For the app2 the request issued by the frontend is
https://example.com/context/app2/menu
And the answer is
http://example.com/context/another_index.html
So it looses the https scheme
It seems that the ServletUriComponentsBuilder.fromRequest has changed behaviour?
I have taken a (quick I admit) look at the commits in the git repo but haven't
found anything ....

React routing with spring mvc

I'm making an webapp using react and spring mvc. I've got 2 questions while making it.
How do you request mapping?
I want to map all the uris but resources and apis into index.jsp, react SPA entry.
resouce uris start with /res
api uris start with /api
How do you response url that react recognize. I mean If you put /examples/1 on your browser, then the web server retutns index.jsp with uri /examples/1 so that react redirects itself to /examples/1.
Thanks.
I've made a controller like this,
#RequestMapping("/api/**")
public ApiResult api(HttpServletRequest request, HttpServletResponse response){
return apiProxy.proxy(request, reponse);
}
#RequestMapping(value="/**", method=HTTPMethod.GET)
public String index(){
return "index"
}
and setup spring config like this.
<mvc:resource mapping="/res/**" location="/res/" order="-1"/>
order -1 is very important.
It makes spring to check first the request url matches with resource mapping.

Restful Web API from Browser

I am using ASP.NET MVC 4 WEB API to create a Restful API service. This is my first go at it, so if you feel I am taking a wrong approach please feel free to correct.
I want to create a rest API (only & not a website, the consumer of the api can decide where they want to consume it), in the past I have used Restful WCF service to achieve this.
I have created a new ASP.NET MVC 4 Web Application and chose the WebAPI project template. I have added a controller class 'CatalogueController.cs' the purpose is on Get() operation I want to return the Catalogue list. The CatalogueDo contains only one property 'Service' of type string.
[System.Web.Http.HttpGet()]
public HttpResponseMessage Get()
{
return Request.CreateResponse(HttpStatusCode.OK, Catalogue);
}
When I run the application the browser loads with the URL http://localhost:5502/ resource not found, if I add the controller name http://localhost:5502/Catalogue/ the browser pops open a notepad with,
[{"Service":"Exchange"},{"Service":"Holidays"}]
The data is correct but
the browser keeps showing resource not found and after my request has been served the URL changes to http://localhost:5502/.
Question,
Am I doing something wrong? Should the response that pops up in the
notepad not be shown as xml in the browser it self?
Why does the controller name get removed from the URL once the request has been served?
Is it at all possible to invoke this REST service from Excel or Power Pivot?

Resources