In the FHIR REST API, there are some standard parameters for all resources that can be used in the 'search' endpoints.
I need to use the '_profile' parameter on a search operation: https://www.hl7.org/fhir/search.html#profile
The HAPI FHIR documentation on implementing search operations (https://hapifhir.io/hapi-fhir/docs/server_plain/rest_operations_search.html) has a lot of examples, none mention the parameters that apply to all the resources, like '_profile'.
I also checked their test server online (http://hapi.fhir.org/resource?serverId=home_r4&pretty=true&resource=Observation) and I can't find a way to specify the '_profile' there, to see how it works.
At the code level, what I'm trying to do is this:
#Search
public List<Observation> getObservationsByProfile(??? profile)
{
...
if (profile == '...')
{
...
}
else
{
...
}
...
}
I don't know how to specify the annotations and type of the parameter so it binds to the value provided in the '_profile' param un the requested URL.
Is there any sample code or documentation I can refere to? Thanks.
The way to make the search work with the "_profile" parameters is this:
#Search
public List<Observation> getObservationsByProfile(#OptionalParam(name="_profile) UriParam profile)
{
...
if (profile == '...')
{
...
}
else
{
...
}
...
}
Even though the _xxx parameters apply to all the FHIR resources, the HAPI FHIR documentation doesn't include an example on how to use those in the search. Hope this helps as reference for others.
Related
My issue is similar to Web Api Routing : Multiple controller types were found that match the URL but I want to keep them in separate controllers.
From the comments, 2 preexisting answers are good workarounds but do not solve the actual issue I'm trying to resolve.
The URLs I'm making up are similar to nested directories in a file system OR are very similar to Firebase URLs.
/BiggestSet/{BiggestSetCode}/Subset1/{Subset1Code}/SubsetOfSubset1/{SubsetOfSubset1}
... etc all the way down to where ever the tree stops. Think of it as a tree of data.
/Collection/{Instance}/Collection/{Instance}
The issue I have is that at the /Collection level I want to also provide specific collection level operations. Like Add and search and other collection specific Operations Collection/ProccessData
Collection Controller:
/Collection/Add
/Collection/ProcessDataOnTheColleciton
Instance Controller:
/Collection/{InstanceCode}
/Collection/{InstanceCode}/ProcessOnTheInstance
The problem I'm having is the Collection/ProcessData clashes with the instance Collection/{InstanceCode}
NOTE: 1 is an parameter and the other is a constant.
If you setup the controllers so that collection and Instance are in the same controller. the /{InstanceCode} doesn't clash with the /ProcessData
BUT
If you setup so the controllers are split into logical functions WebAPI gives the error Multiple controller types were found that match the URL.
Does anyone know how to modify attribute routing to somehow behave as if they are in the same controller OR to prioritize the constant over the parameter across controllers?
To keep two separate controllers and still have such routes you can use regular expression route constraints. This way you can specify for the instanceCode you accept everything except the actions from the other controller.
Here is a sample of how to configure routes like that:
public class CollectionController : ApiController
{
[HttpGet]
[Route("Collection/Add")]
public string Add()
{
return $"CollectionController = Collection/Add";
}
[HttpGet]
[Route("Collection/Process")]
public string Process()
{
return $"CollectionController = Collection/Process";
}
}
public class InstanceController : ApiController
{
[HttpGet]
[Route("Collection/{instanceCode:regex(^(?!Add$|Process$).*)}")]
public string Get(string instanceCode)
{
return $"InstanceController = Collection/{instanceCode}";
}
[HttpGet]
[Route("Collection/{instanceCode:regex(^(?!Add$|Process$).*)}/Process")]
public string Process(string instanceCode)
{
return $"InstanceController = Collection/{instanceCode}/Process";
}
}
Here is also a link to the post that explains the regular expression used in the sample.
An even better option would be if you have a specific format for the instanceCode and set the regular expression to accept only this specific format. Then you would not need to modify the regular expression for every new action added. I include also a link to the documentation for all available Route constraints. There you can see all the available options. For example if your instance code is a number you don't even need a regular expression you can just restrict with the int constraint like this [Route("Collection/{instanceCode:int}")].
In one of my use case, i have all my route information in a json file and i want to read the file and create the routes accordingly.
for example,
if i have declared route like this in my json config file
{
"config": [
{
"routeSrcSystem": "System1",
"routes": [
{
"fromRoute": {
"type": "default",
"typeValue": "direct:CMStart"
},
"toRoute": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System1/inboundMessage"
}
}
]
}
]
}
then i able to create the routes as below dynamically. but here though its dynamic,the route definition is not dynamic because i have used one "from" and one "to" definition but parameter for this definition i am passing dynamically.
public class GenerateRouter extends RouteBuilder {
private RoutesMetadata routesMetadata;
public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
super(context);
this.routesMetadata=routesMetadata;
}
#Override
public void configure() throws Exception {
from(routesMetadata.getFromRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue());
}
}
But i would like to do the route definition itself dynamically. for example, i have route config like this,
{
"config": [
{
"routeSrcSystem": "System1",
"routes": [
{
"fromRoute": {
"type": "default",
"typeValue": "direct:CMStart"
},
"toRoute1": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System1/inboundMessage"
}
"toRoute2": {
"type": "http"
"typeMethod": "POST",
"typeContent": "application/json",
"typeValue": "http://localhost:8080/v1/System2/inboundMessage"
}
}
]
}
]
}
then in my route definition i need to add one more "to" definition dynamically. its just example. it could be more dynamic. for example, configuration can be changed to introduce "process" or "bean" or "class" definition. so based on the config, we need to decide how many "to" to be created and how many "process" to be created and etc. I might need to call the next rest end point after some validation and etc and some times i need to call kafka to put the message in queue. i do see an option to list all routes in a list and execute it but i think we need to have flexibility to add process or to or class definition before we call next end point and this has to be based on configuration.
public class GenerateRouter extends RouteBuilder {
private RoutesMetadata routesMetadata;
public GenerateRouter(CamelContext context,RoutesMetadata routesMetadata) {
super(context);
this.routesMetadata=routesMetadata;
}
#Override
public void configure() throws Exception {
from(routesMetadata.getFromRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue())
.setHeader(Exchange.HTTP_METHOD, simple(routesMetadata.getToRoute().getTypeMethod()))
.setHeader(Exchange.CONTENT_TYPE, constant(routesMetadata.getToRoute().getTypeContent()))
.to(routesMetadata.getToRoute().getTypeValue());
}
}
I saw some information where route definition itself can be defined dynamically and i am doing research on it. but meantime i would like to post this here to get experts opinion. Also, please suggest whether I am using the camel on right way? because in my use case i am thinking to add "to" definition to which pass the class name dynamically based on configuration file, so that application developer can do their logic for transformation, enrich or manipulation in this class on the fly before deliver to target system. please let me know if we have any better approach. also, let me know whether XML way of doing is good way or defining own config file in json format is a good way to create dynamic route.
i am planning to read the json file and create a router definition as a string dynamically. but i would need to load this string as a definition in context it seems. i think i am missing this part.
.to("class:com.xxx.camel.layoutTransform?method=layout()")
if we provide all these configurations in xml file and if camel supports to create the route definition automatically using this file then we can consider this option as well.
Below is the one of the way from another source to create the router definition using XML file. within the XML, we have router information defined and this xml considered as a string and this string is converted as router-definition object and finally added into context.
<routes
xmlns=\"http://camel.apache.org/schema/spring\">
<route>
<from uri='direct:c'/>
<to uri='mock:d'/>
</route>
</routes>
CamelContext context = new DefaultCamelContext();
context.setTracing(true);
String xmlString = "<routes xmlns=\"http://camel.apache.org/schema/spring\"><route><from uri='direct:c'/><to uri='mock:d'/></route></routes>";
InputStream is = new ByteArrayInputStream(xmlString.getBytes());
RoutesDefinition routes = context.loadRoutesDefinition(is);
context.addRouteDefinitions(routes.getRoutes());
context.start();
ProducerTemplate template = null;
template = context.createProducerTemplate();
template.start();
template.sendBody("direct:c", "HelloC");
Thread.sleep(10000);
context.stop();
I would like to do the similar concept using java dsl definition as a string.
for example, if i have string as below then can this be converted as a router definition?
String dslString = "from("direct:starting").to("seda:end")";
Here is my use case. Sometime, we want to call 2 http services as below
from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2")
Somtimes we might need to call 3 services as like below
from("direct:start").to(http://localhost:8080/service1).to("http://localhost:8080/service2").to("http://localhost:8080/service3")
sometimes we need to do transformation before we invoke service2 as like below.
from("direct:start").to(http://localhost:8080/service1).to("class:com.xxx.yyy").to("http://localhost:8080/service2").to("http://localhost:8080/service3")
In the even driven architecture, we will have set of routes must be defined for each event types. so the idea is, if we define these routes in a table for each event type, then at the time of service start up all the routes will be loaded in context and will be started. I am able to do the same in XML DSL way but trying to do the same in java DSL.
Thanks in advance!
Camel supports defining all details about routes in a particular XML-based format. This page has links to that (and other) DSLs.
You could definitely come up with your own DSL and build routes dynamically, but that's a lot of work if you want to support all the things a full Camel DSL would support. I would suspect that is not the right solution for whatever your use-case.
If you have certain patterns to your routes, you can create fairly dynamic Camel route-builders that are driven by some configuration. To make this concrete, let's say you have many use cases that follow a very similar pattern... say, consumer data from files in a folder, do a few transformations from a menu of (say) 10-15 transformations, and then sends output to one of many queues.
Since you have various possible combinations, it could make sense to configure those details in file etc. and then build some routes off that. The trade-off is not different from any other place where you have to decide if it is clearer to just code the 10 things you want, or to make something more complex but generic.
Essentially, you would still be creating a DSL or sorts, but one that is closer to your use case.
Spring Boot (Java) here. Does Swagger have any customizable/configurable fields that allows you to specify specific String values that an endpoint either accepts or returns?
For instance I might have an endpoint like so:
POST /v1/{accountId}/preferences
{
"notificationTypes" : [
]
}
...that accepts an array of notificationTypes in its request entity. Perhaps my server only allows AdminNotification and SimpleAlert as the possible values for this notificationTypes, meaning:
POST /v1/{accountId}/preferences
{
"notificationTypes" : [
"SimpleAlert"
]
}
is valid but:
POST /v1/{accountId}/preferences
{
"notificationTypes" : [
"Hello"
]
}
throws a 400 Bad Request. I'd like to be able to communicate this in my Swagger docs. Is this configuration possible via annotations?
I think a good solution would be to create an ENUM with the accepted values. This way, it will be automatically described in Swagger:
#ApiModelProperty(value= "Accepted values are :")
public NotificationTypes notificationTypes;
public enum NotificationTypes {SimpleAlerts, AdminNotifications}
In the generated specifications, it gives the following:
Have fun !
You can use something like -
notificationTypes:
type: string
example: ["SimpleAlert", "otherValue"]
look - https://gyazo.com/1c8774fbf08410c19df0506a52a767d6
ref - https://swagger.io/docs/specification/adding-examples/
I have looked all over the net, trolled through spring-data-rest source code and tried to decipher how the JS for the hal-browser is trying to retrieve 'title' and 'doc' details for a resource. I have also discovered that there are
#RepositoryRestResource(
collectionResourceRel = "roles",
path = "roles",
itemResourceDescription = #Description("This is a test description")
)
Annotations I can put in the #Repostitory, but it doesn't seem to do anything.
Specifically, if you look at this example, how do I get "title|doc" to fill in"
I filed a ticket with spring and haven't heard back.
From what I can see the HAL Browser expects the link to contain the title property. In the example you linked:
{
"motd": "Welcome to the OSDI Example Action Platform OSDI API endpoint!!",
"_links": {
"osdi:people": {
"href": "http://api.opensupporter.org/api/v1/people",
"title": "The collection of people in the system"
}
...
}
The org.springframework.hateoas.Link class does not support that property as of version 0.19.0.RELEASE. No idea about the docs though...
Our Grails 2.4.4 application is using RESTful URLs throughout. Given the following URL:
/stores/123/products/456
I'd like to validate that there is a store with an ID of 123, and if not, redirect to a 404 on every request to the Product controller. I don't want to have to put that store lookup code in each action method, nor do I want to create a controller base class, because then I have to put a method call in every action method.
Can this be done with a interceptor somehow?
Interceptors are introduced in Grails 3.0. You would need filters in Grails 2.4.4.
before = { } is what will be needed here.
Also look at the docs which variable are available to filters by default (eg: params, request, response etc). If this is still unclear, I can add an answer as an example. But I hope docs will be self explanatory. As an example i would do it as
class EntityCheckFilters {
def filters = {
storeExistCheck( controller:'product' ) {
before = {
if ( !params.storeId || !Store.exists( params.sotreId as Long ) ) {
response.sendError(404)
// or for example if you have a separate action to handle 404
// redirect(action: 'handle404')
// this is important,
// because we do not want to pass through with the original call
return false
}
}
}
}
}
I think you can do this using:
URL Mapping
Filters
But I dont think putting a logic (checking if there is a valid store with the given id) in URL Mapping is good idea, so better to use Filters.
So you url mapping will look like this:
"/stores/$storeId/products/$productId" (controller = "product")
And your filter:
class YourFilterNameFilters {
def filters = {
secureReports(controller:'*', action:'*') {
before = {
if(parmas.controller == "product" && params.storeId){
Store store = Store.get(params.sotreId)
if(!store){
response.sendError(404)
}
}
}
}
}