I am using the NuGet package Hl7.Fhir.R4 to connect to the NHS ERS API. Part of the "CreateReferral" method requires an extension like this:
"extension": [
{
"url": "https://fhir.nhs.uk/STU3/StructureDefinition/Extension-eRS-Shortlist-SearchCriteria-1",
"valueReference": {
"reference": "#ServiceSearchCriteria-1"
}
}
]
I can't seem to find a model class that will create this output. Any ideas?
You should be able to add an extension to an element/resource with the AddExtension method. As parameters, you fill in the extension's url and a value of any FHIR datatype. For your extension, that would be a Reference, which is modelled by the ResourceReference class:
element.AddExtension("https://fhir.nhs.uk/STU3/StructureDefinition/Extension-eRS-Shortlist-SearchCriteria-1",
new ResourceReference("#ServiceSearchCriteria-1"));
When looking at the referral API, it seems to use FHIR STU3, so you may need to change your library to Hl7.Fhir.Stu3 as well to avoid mismatches in the resource's fields and other version differences. The above method should still work for adding your extension though.
Related
I have got a requirement of building an azure function which transforms data in our COSMOS DB based on the value posted by a calling service.
So consider this JSON template
{
"processExecutionId": 1000,
"processId": "$PID",
"parentProcessId": 10,
"objectNameTag": "$ObjectName",
"objectName": "bbps.fx",
"processStartedOn": "$startedOn",
"processCompletedOn": "$CompletedAt",
"processExecutionStatusId": 2,
"configurationPayload": "Actual Config Payload with replaced values by the orchestrator or payload read service",
"objectMetadata": {
"jsonPayLoadRead": {
"messages": "$Message"
},
"writeToDB": "$IsWrite"
}
}
This is something we in COSMOS corresponding to a key.
So when a requester application posts that Key it has a JSON object in its body like this
{
"processStartedOn": "2022-01-25 10:10:32",
"processCompletedOn": "2022-01-25 10:20:25",
"objectMetadata": {
"jsonPayLoadRead": {
"messages": "Data uploaded"
},
"writeToDB": "True"
}
}
So the method posting parameters for the template expecting a response from the API after replacing those variables in the template with the values.
The JSON template is not always the same structure. Otherwise we can atleast define a class and can deserialize into it. So what ever the key posted our service needs to take the corresponding JSON template from COSMOS and do the transformation.
So dont know how to handle it the best way or is there is any way to handle this process within COSMOS itself rather than trying using C#.
Please share your thoughts
You can always add a TemplateType property in your class so that you know the various options you have and based on that you know what class to use, there are also ways to stream from cosmos directly without using classes at all but it depends a little what you are trying to achieve if you just need to hand over to another app or not then you can stream from cosmos without even knowing what the structure is
I am trying to generate a C# client for the Trello API. Therefore I have downloaded the Open API specification from https://developer.atlassian.com/cloud/trello/swagger.v3.json and run the following nswag command from the bash.
nswag openapi2csclient /input:swagger.v3.json \
/classname:TrelloClient \
/namespace:Integrations.Trello \
/output:TrelloClient.cs \
/GenerateClientInterfaces:True \
/GenerateExceptionClasses:True \
/GenerateClientClasses:True \
/DisposeHttpClient:False \
/OperationGenerationMode:SingleClientFromOperationId
The code generation completes without errors, but the generated code does not compile because it contains many errors. For example, some of the generated method names contain invalid expressions like =idAsync, or method signatures have ambiguous parameters (for instance, multiple key and token parameters of type string). The following method declaration has been generated for the GetMembers method, which is obviously the wrong syntax.
System.Threading.Tasks.Task<Member> GetMembers=idAsync(
string key, string token, string id, string actions, string boards, BoardBackgrounds? boardBackgrounds,
BoardsInvited? boardsInvited, BoardFields? boardsInvited_fields, bool? boardStars, string cards,
CustomBoardBackgrounds? customBoardBackgrounds, CustomEmoji2? customEmoji, CustomStickers? customStickers,
MemberFields? fields, string notifications, Organizations? organizations,
OrganizationFields? organization_fields, bool? organization_paid_account,
OrganizationsInvited? organizationsInvited, OrganizationFields? organizationsInvited_fields,
bool? paid_account, bool? savedSearches, Tokens? tokens);
Are there any special options that need to be set when processing an Open API specification document of version 3?
I was able to solve syntax issues regarding the get-members method in the generated code by changing the OperationGenerationMode from SingleClientFromOperationId to SingleClientFromPathSegments. This works as a workaround because the =id term only appears in the operationId.
I inspected Trello´s Open API specification document and found out that the definition of get-members contained the =id term in the operationId; not sure if this is wrong in the spec, or the generator is not able to handle that case correctly. The definition of the get-members method looks like that (foreshortened):
... "/members/{id}":
{
"get":
{
"tags": [],
"operationId":"get-members=id",
"parameters" ...
}
}
As a sidenote, the reason why I use the SingleClient... operation modes is that Nswag also adds GeneratedCode attributes to any partial class and interface which also results in invalid code (this attribute can only be applied once). The SingleClient... operation mode solves that.
What remains is the problem that NSwag generates methods with duplicated parameters, which has been reported as an issue, but is not solved yet; see https://github.com/RicoSuter/NSwag/issues/2560 for further information. Last but not least, I tried to remove the =id from the operationId and switched back to the SingleClientFromOperationId operation mode to check whether this does the trick, which is not the case.
I assume that NSwag is used by a broad audience which makes me think that this must be more related to the processed spec than Nswag. Thus, I looked up the spec for methods that have been reported by the C# compiler to have duplicated parameters. Here is an example.
...
{
"name": "token",
"in": "query",
"description": "The API token to use",
"required": true,
"schema": {
"$ref": "#/components/schemas/APIToken"
}
},
{
"name": "token",
"in": "path",
"description": "",
"required": true,
"schema": {
"type": "string"
}
}
...
So it seems that a method can have parameters of the same name, but they can appear in different places such a the query-string, or be part of the URL path. Then, it might be Nswag that produces the wrong output; if it is intended that both parameters can be sent to the API, then the generator should just prefix the names to avoid ambiguities, for instance, queryToken and pathToken, leaving it up to the developer to decide what parameter to use or to give a hint to the expected value (in case both parameters are required and expect different values).
I have a serverless web API (API Gateway + Lambda) that I have built in C# and deployed via Visual Studio. This is achieved via a serverless.yml file that auto-creates a CloudFormation template, then that template is applied to create the API stack.
Once my stack is deployed, I have gone into the AWS Console to enable caching on one of the path parameters, but get this error:
!https://ibb.co/B4wmRRj
I'm aware of this post https://forums.aws.amazon.com/thread.jspa?messageID=711315򭪓 which details a similar but different issue where the user can't uncheck caching. My issue is I can't enable it to begin with. I also don't understand the steps provided to resolve the issue within that post. There is mention of using the AWS CLI, but not what commands to use, or what to do exactly. I have also done some reading on how to enable caching through the serverless.yml template itself, or cloud formation, but the examples I find online don't seem to match up in any way to the structure of my serverless file or resulting CF template. (I can provide examples if required). I just want to be able to enable caching on path parameters. I have been able to enable caching globally on the API stage, but that won't help me unless I can get the caching to be sensitive to different path parameters.
serverless.yml
"GetTableResponse" : {
"Type" : "AWS::Serverless::Function",
"Properties": {
"Handler": "AWSServerlessInSiteDataGw::AWSServerlessInSiteDataGw.Functions::GetTableResponse",
"Runtime": "dotnetcore2.0",
"CodeUri": "",
"MemorySize": 256,
"Timeout": 30,
"Role": null,
"Policies": [ "AWSLambdaBasicExecutionRole","AWSLambdaVPCAccessExecutionRole","AmazonSSMFullAccess"],
"Events": {
"PutResource": {
"Type": "Api",
"Properties": {
"Path": "kata/table/get/{tableid}",
"Method": "GET"
}
}
}
}
}
},
"Outputs" : {
"ApiURL" : {
"Description" : "API endpoint URL for Prod environment",
"Value" : { "Fn::Sub" : "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/" }
}
}
--Update Start--
The reason, you are getting Invalid cache key parameter specified error because you did not explicitly highlighted the path parameters section.
This is because, although the UI somehow extrapolated that there is a
path parameter, it has not been explicitly called out in the API
Gateway configuration.
I tested with below and was able to replicate the behavior on console. To resolve this, follow my Point 1 section full answer.
functions:
katatable:
handler: handler.katatable
events:
- http:
method: get
path: kata/table/get/{tableid}
--Update End--
Here you go. I still don't have your exact serverless.yml so I created a sample of mine similar to yours and tested it.
serverless.yml
functions:
katatable:
handler: handler.katatable
events:
- http:
method: get
path: kata/table/get/{tableid}
request:
parameters:
paths:
tableid: true
resources:
Resources:
ApiGatewayMethodKataTableGetTableidVarGet:
Properties:
Integration:
CacheKeyParameters:
- method.request.path.tableid
Above should make tableid path parameter is cached.
Explanation:
Point 1. You have to make sure in your events after your method and path, below section is created otherwise next resources section of CacheKeyParameters will fail. Note - boolean true means path parameter is required. Once you explicitly highlight path parameter, you should be able to enable caching via console as well without resources section.
request:
parameters:
paths:
tableid: true
Point 2. The resources section tells API Gateway to enable caching on tableid path parameter. This is nothing but serverless interpretation of CloudFormation template syntax. How did I get that I have to use ApiGatewayMethodKataTableGetTableidVarGet to make it working?. Just read below guidelines and tip to get the name.
https://serverless.com/framework/docs/providers/aws/guide/resources/
Tip: If you are unsure how a resource is named, that you want to
reference from your custom resources, you can issue a serverless
package. This will create the CloudFormation template for your service
in the .serverless folder (it is named
cloudformation-template-update-stack.json). Just open the file and
check for the generated resource name.
What does above mean? - First run serverless package without resources section and find .serverless folder in directory and open above mentioned json file. Look for AWS::ApiGateway::Method. you will get exact normalized name(ApiGatewayMethodKataTableGetTableidVarGet) syntax you can use in resources section.
Here are some references I used.
https://medium.com/#dougmoscrop/i-set-up-api-gateway-caching-here-are-some-things-that-surprised-me-7526d954fbe6
https://serverless.com/framework/docs/providers/aws/events/apigateway#request-parameters
PS - If you still need CLI steps to enable it, let me know.
I am trying to use OneSignal API. My problem isn't specific to OneSignal but I think that referencing it might make it easier to explain.
OneSignal is an SAAS for delivering notifications to phones and browsers and I am trying to hook it up to my server. The problem is that the request to OneSignal API returns:
{
"id": "458dcec4-cf53-11e3-add2-000c2940e62c",
"recipients": 5
}
or
{
"errors": {
"invalid_player_ids" : ["5fdc92b2-3b2a-11e5-ac13-8fdccfe4d986", "00cb73f8-5815-11e5-ba69-f75522da5528"]
}
}
or
{
"id": "",
"recipients": 0,
"errors": ["All included players are not subscribed"]
}
while I am trying to deserialize the request using DataContracts and DataContractJsonSerializer.
My question is: how do I parse a JSON where a property can be empty, can be an object or an array of strings? Is there a way to do that using just standard DataContract attributes or do I have to write my own serializer? If so, could you point me to some resources or to any tutorial since I couldn't find anything resolving my problem so far?
I followed this asp.net tutorial by Mike Wasson, and managed to set up the related entities just fine, but when I applied this logic to my project the more complex entity relations (in that there are more of them; that's the only difference) wouldn't succeed in an OData call, I got a 404 with this payload:
{
"error": {
"code": "",
"message": "No HTTP resource was found that matches the request URI 'http://localhost:19215/Menus(c94f7f98-6987-e411-8119-984be10349a2)/MenuPermissions'.",
"innererror": {
"message": "No routing convention was found to select an action for the OData path with template '~/entityset/key/unresolved'.",
"type": "",
"stacktrace": ""
}
}
}
The tutorial doesn't mention having to set up EdmModel navigations and Mike Wasson makes a point of pointing out that "asp.net is official documentation :-)"; so, I have spent a while trying to get these related entities working, thinking I had set up the project incorrectly.
I thought it might have something to do with the version of ASP.NET OData libraries that NuGet was installing (the NuGet Console installs 6.9.x, whereas the NuGet Dialog installs 6.5.x). I also wondered if it was because I set the project up as a completely empty project and then use OWIN, so I tried it with a pure ASP.NET templated solution. I also tried a couple of other possible solutions: OData-route-attributes on my controller methods; and including my data layer and models all in the same library (I have them separated out to keep DRY); I even attempted to use the WebApi route debugger by Rick Anderson - I wouldn't attempt to use this again!
All to no avail.
There was a brief moment when they worked, but I don't know why; they ceased to work on the next build/run - I guess I changed something in between, but it was very minor and I was losing confidence at every step.
Then I decided that Mike Wasson must've just taken the path of least resistance in his tutorial and so I reverted to this SO question/answer and modified it for use with ODataConventionModelBuilder and reuse, as I will explain in my answer below.
If anyone knows of a simpler way of getting this to work, please let me know, otherwise I recommend just biting the bullet and writing those EdmModel-Navigations in my answer below.
As I mention in the question, I tried many solutions to get this to work, but none were consistent in actually solving the problem and I kept avoiding the solution laid out in this SO question/answer because the tutorial is specifically for v4 and I figured that answer must be for an older version (how unwise).
So that answer does solve the problem, but requires some work to fit directly into OData v4 and an ODataConventionModelBuilder; this is why I have posted this question and answer; to provide a solution, specifically for OData v4 and ODataConventionModelBuilder, in the hope that others won't lose the time I have looking into this.
First, set up your EdmModel:
private static IEdmModel GetEdmModel()
{
var builder = new ODataConventionModelBuilder();
builder.EnableLowerCamelCase();
builder.EntitySet<Menu>("Menus");
builder.EntitySet<MenuPermission>("MenuPermissions");
var edmModel = builder.GetEdmModel();
AddNavigations(edmModel); //see below for this method
return edmModel;
}
Second AddNavigations:
private static void AddNavigations(IEdmModel edmModel)
{
AddMenuPermissionsNavigation(edmModel);
}
private static void AddMenuPermissionsNavigation(IEdmModel edmModel)
{
var menus = (EdmEntitySet) edmModel.EntityContainer.FindEntitySet("Menus");
var menuPermissions = (EdmEntitySet)edmModel.EntityContainer.FindEntitySet("MenuPermissions");
var menuType = (EdmEntityType) edmModel.FindDeclaredType("iiid8.cms.data.models.Menu"); //"iiid8.cms.data.models" is the C# namespace
var menuPermissionType = (EdmEntityType)edmModel.FindDeclaredType("iiid8.cms.data.models.MenuPermission"); //as above, "iiid8.cms.data.models" is the C# namespace
AddOneToManyNavigation("MenuPermissions", menus, menuPermissions, menuType, menuPermissionType);
AddManyToOneNavigation("Menu", menus, menuPermissions, menuType, menuPermissionType);
}
private static void AddOneToManyNavigation(string navTargetName, EdmEntitySet oneEntitySet, EdmEntitySet manyEntitySet,
EdmEntityType oneEntityType, EdmEntityType manyEntityType)
{
var navPropertyInfo = new EdmNavigationPropertyInfo
{
TargetMultiplicity = EdmMultiplicity.Many,
Target = manyEntityType,
ContainsTarget = false,
OnDelete = EdmOnDeleteAction.None,
Name = navTargetName
};
oneEntitySet.AddNavigationTarget(oneEntityType.AddUnidirectionalNavigation(navPropertyInfo), manyEntitySet);
}
private static void AddManyToOneNavigation(string navTargetName, EdmEntitySet oneEntitySet, EdmEntitySet manyEntitySet,
EdmEntityType oneEntityType, EdmEntityType manyEntityType) {
var navPropertyInfo = new EdmNavigationPropertyInfo {
TargetMultiplicity = EdmMultiplicity.One,
Target = oneEntityType,
ContainsTarget = false,
OnDelete = EdmOnDeleteAction.None,
Name = navTargetName
};
manyEntitySet.AddNavigationTarget(manyEntityType.AddUnidirectionalNavigation(navPropertyInfo), oneEntitySet);
}
Finally, call GetEdmModel from WebApiConfig.Register
config.MapODataServiceRoute("odata", null, GetEdmModel());
Now call your OData service's one-to-many and many-to-one navigations from your client and all should be good with your world. In my case the calls look like this:
One-to-many:
http://localhost:19215/Menus(c94f7f98-6987-e411-8119-984be10349a2)/MenuPermissions
Many-to-one:
http://localhost:19215/MenuPermissions(ba0da52a-6c87-e411-8119-984be10349a2)/Menu
This answer assumes you set up the rest of your project just like Mike Wasson suggests in the tutorial linked in the question (that link is to Part 3 - you will need to follow Part 1 first!).
I am using ASP.NET 5, Web API 2.2, and Entity Framework.
Another developer and I have also spent hours trying to figure out why, after following that same tutorial to a T, we couldn't get a relational route like the following to return anything other than a 404:
/odata/Supplier(1)/Products
We also tried the route debugger referenced in the OP, and it failed to produce anything other than a blank screen.
Luckily, for our needs, one of our random experiments worked, and that was to use the ODataRoute attribute like such:
[EnableQuery]
[ODataRoute("Suppliers({key})/Products")]
public IQueryable<Product> GetProductsForSupplier([FromODataUri] int key)
{
...
}