-
Notifications
You must be signed in to change notification settings - Fork 471
Disable optional parameters in links #535
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Just expand the |
thanks for the hint @olivergierke |
@christophlingg Are you able to expand on how you handled this? Were you building links via the ControllerLinkBuilder? |
@jalati-paychex I used |
Just call |
@christophlingg @odrotbohm Thanks to both of you for the quick responses. I am using the ControllerLinkBuilder in the following way to generate some "baseHrefs" to create some paging links:
Where the first argument is the requestBody and the second is the optional query parameter. I really just need the href out of the self link, is there another way to get that without building the link? |
No.
|
@gregturn Thanks, I'll just modify the string value to remove the '{...}' for my purposes. |
Hi @jalati-paychex, What do you mean by 'modify the string value to remove the '{...}''? I have the same issue in my code. |
Hi @benweizhu, In my paged responses, I have a self link and then any next or prev links that apply. When creating the next and prev links, I take the self link's href and essentially apply a replace all to remove the optional query parameters that the libraries add by default:
From there, I can add my offset and limit parameters (which is what use for paging). |
All you need to do is sprinkle an String selfHref = linkTo(methodOn(MyController.class).search(myPathVariable))
.withSelfRel()
.expand() // <- important bit!
.getHref(); |
I think I just misunderstood @gregturn's reply, then. Now I can remove that work-around. Thanks! |
@odrotbohm, this seems to be a breaking change in the behavior because my client is now receiving URI templates instead of URIs even though I specified all the parameters for the controller method. When I use the linkTo(methodOn(...)) invocation I pass in nulls for the parameters that are not relevant to the link I want to generate. In order to get back to the original behavior of the library I need to call expand() everywhere that I used linkTo(methodOn(...)). I understand what the code is doing and how it is generating a URI template. I don't understand why I would want a URI template when I call the method to get a link, I would expect to get a link, not a template. Should my clients be able to accept a URI template as a HATEAOS link? Is that normal nowadays? Should my servers always expand all Link objects at some point before sent back to the client? I am mainly trying to figure out if this feature is a breaking change for my applications because my applications are written incorrectly, or if it really is a breaking change to the library. @RestController
@Api(value="student MSR projects", description="Med Scholar Research Project operations")
@RequestMapping(value=ApiUrls.API_ROOT)
public class ProjectController {
@ApiOperation(value = "Get Project list for user", notes = "Returns projects")
@RequestMapping(method = RequestMethod.GET, value = PROJECTS_URI, produces = { MediaType.APPLICATION_JSON_VALUE })
@ApiImplicitParams({
@ApiImplicitParam(name = "p", value = "Page number", required = false, dataType = "long", paramType = "query"),
@ApiImplicitParam(name = "ps", value = "Page size", required = false, dataType = "long", paramType = "query"),
})
public ResponseEntity<PagedResources<ProjectViewResource>> getProjectList(@PageableDefault(size = 2000, page = 0) Pageable pageable,
PagedResourcesAssembler<ProjectView> assembler,
@ApiParam(value = "optional parameter to request view of the response.", allowableValues = "compact") @RequestParam(value = "view", required = false, defaultValue = "compact") String view,
@ApiParam(value = "optional parameter to filter results by user id.") @RequestParam(value="userId", required=false) String userId,
@ApiParam(value = "optional parameter to filter results by mentor id.") @RequestParam(value="mentorId", required=false) String mentorId,
@ApiParam(value = "optional parameter to filter results by mentor status.") @RequestParam(value="mentorStatus", required=false) MentorStatus mentorStatus,
@ApiParam(value = "optional parameter to filter results by Committee Date (starting with).") @RequestParam(value="startCommitteeMeetingDate", required=false) @DateTimeFormat(pattern="MM/dd/yyyy") Date startCommitteeMeetingDate,
@ApiParam(value = "optional parameter to filter results by Committee Date (ending with).") @RequestParam(value="endCommitteeMeetingDate", required=false) @DateTimeFormat(pattern="MM/dd/yyyy") Date endCommitteeMeetingDate,
@ApiParam(value = "optional parameter to filter results by Project Status") @RequestParam(value="projectStatus", required=false) List<ProjectStateCode> projectStates,
@ApiParam(value = "optional parameter to filter results by Parent projects") @RequestParam(value="onlyParentProjectsFlag", required=false) Boolean onlyParentProjectsFlag,
@ApiParam(value = "optional parameter to filter results by Term") @RequestParam(value="termCode", required=false) List<String> termCode,
@ApiParam(value = "optional parameter to filter results by Area Ids") @RequestParam(value="areaIds", required=false) List<Long> areaIds
) {
// ...
}
}
// Code that generates a link a list of projects for a specific committee meeting date
Link projectsLink = linkTo(methodOn(ProjectController.class).getProjectList(null, null, null, null, null, null, startCommitteeMeetingDate, startCommitteeMeetingDate, null, null, null, null))
.withRel(PROJECT_LIST_REL);
// spring-hateaos 0.17 generates the following link URL
// .../api/v1/projects?startCommitteeMeetingDate=03/07/2019&endCommitteeMeetingDate=03/07/2019
// spring-hateaos 0.25 generates the following link URL
// ...api/v1/projects?startCommitteeMeetingDate=03/07/2019&endCommitteeMeetingDate=03/07/2019{&view,userId, mentorId, mentorStatus, projectStatus,onlyParentProjectsFlag,termCode,areaIds}
// If I call projectsLink.expand() in 0.25 I get the following link URL
// .../api/v1/projects?startCommitteeMeetingDate=03/07/2019&endCommitteeMeetingDate=03/07/2019
// I am struggling with what appears to be the requirement that I must ALWAYS call expand() for every link. In this
// case the REST endpoint has optional parameters so spring-hateaos generates a URI template that needs to be expanded.
// But for a REST endpoint without request parameters I don't need to expand the resulting Link object.
@RequestMapping(method = RequestMethod.GET, value = PROJECTS_URL + "/{projectId}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<ProjectResource> getProject(
@ApiParam(value = "id of the Project.") @PathVariable("projectId") Long projectId){ }
// Link to project without query parameters
Link projectLink = linkTo(methodOn(ProjectController.class).getProject(123l).withSelfRel();
// Resulting URL
// .../api/v1/projects/123
// Now if some developer decides to add an optional query parameter
@RequestMapping(method = RequestMethod.GET, value = PROJECTS_URL + "/{projectId}", produces = { MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<ProjectResource> getProject(
@ApiParam(value = "id of the Project.") @PathVariable("projectId") Long projectId,
@ApiParam(value = "filter by active projects") @RequestParam(value="active", required=false) Boolean active) {}
// And the developer updates the call signature to get the code to compile
Link projectLink = linkTo(methodOn(ProjectController.class).getProject(123l, null).withSelfRel();
// Then the resulting URL is
// ../api/v1/projects/123{&active}
// In this case the developer needs to know that when the first optional parameter is added to
// an endpoint that all links generated from the endpoint method must also call expand(). Since
// this is likely to be forgotten, it appears that the best defense is to ALWAYS call expand(),
// and if something ALWAYS needs to be done, then would be nice for my framework to do it for me
// rather that make me do it for the framework. |
It would help if you posted a web method and how you are forming the link along with the JSON output in order to solve this. |
Greg,
I added a code snippet to the original comment. Let me know if that
demonstrates the issue/concern I am having. I am trying to figure out the
"right" way to use spring-hateaos today and in the future.
At the moment, our organization will need to add .expand() to every single
use of linkTo(methodOn(...)) across all of our projects as we upgrade to
the latest spring-hateaos. That seems to be the only way preserve the
behavior of the library right now. Which is fine... we can do that, but I
want to make sure that is the correct long-term answer and not a work
around because we are not using spring-hateaos correctly in the first place.
I'm also wondering if the intent of adding this feature is to allow the URI
templates to be propagated to the REST client and if it is expected that a
modern day REST client should be able to handle URI templates. Which could
be cool... if that is how things work in the real-world now. But I am a
server-side guy, so I am not up to date on things like that. Should the
server be propagating unexpanced URI templates to the client? Is this a
common practice?
Darryl
…On Thu, Feb 21, 2019 at 5:26 PM Greg Turnquist ***@***.***> wrote:
It would help if you posted a web method and how you are forming the link
along with the JSON output in order to solve this.
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#535 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABVjzN539F9Dq6SQmtlaf925PZuZpdx4ks5vP0dBgaJpZM4Lkj1A>
.
|
Yes, it is a breaking change. But that's why where on a 0.x version. From a client point of view it's not really breaking even, as the only media type we really have supported so far is HAL which clearly states that URI templates are valid values for the The use case is pretty simple: when you point to a controller method that takes optional parameters and you don't provide a value for one, how else is the client supposed to learn that this additional, optional parameter is available for the resource? That big list of additional annotations to create out of band documentation is really not a RESTful answer to that question. In general, I think if you find yourself thinking you always need to expand the link on the server, you've put on a non-REST mind set. Have a look at what kind of resource you describe. It's expecting some mandatory parameters and some optional ones. Exactly that is transferred to the client and it's up to the client to make use of those optional parameters. If you hide the existence of those optional parameters by sending an expanded URI, it would have to use some out of band information to reconstruct the URI if it wants to send a parameter value for one of those. That violates rule number one of RESTful APIs: clients must not have any knowledge about URI structure. Clients of course have to expand URI templates before using a link's href as request URI. But that's not something we impose on the client but the way URIs and URI templates are defined. I agree that there are cases in which you'd have to present clients with canonical URIs (like |
This answers my question/concern. Our client applications do not currently handle/expand HAL URI templates. That seems to be the root cause of the problems we experienced as a result of the update. I will pursue a fix for our clients so that they can accept the HAL URI templates. Thank you for the quick response to my questions. |
@odrotbohm After upgrading to the latest version of Spring HATEOAS both the required and optional query parameters are shown as As when I call thanks |
I am suffering same issue, do you have any solution for this? |
We need to drop all template parameters for backwards-compatibility reasons. Do so by expanding all links after withRel|withSelfRel. Reference: spring-projects/spring-hateoas#535 Signed-off-by: Martin Böh <[email protected]>
Hi guys!
I just updated from 0.19 to 0.23 and got to know a new feature introduced with issue #169
Now query parameter request appear in the links, like that:
I know a lot of people were eager to have it, in our case we would like to suppress it, is it possible?
The text was updated successfully, but these errors were encountered: