Best practice to send only required fields in REST API in Symfony - symfony

We need to send certificates list to another application using REST API. So Object response contains
[
{
"id":1,
"orderId":123,
"certificateStatus":true,
"certificateNo":"xyz123abc",
"customer":{
"id":36,
"email":"abc#cc.com",
"firstName":"abc",
"lastName":"dfg",
"user":{
"id":23,
"username":"abc#cc.com",
"enabled":true,
"kycStatus":false
},
"_links":{
"self":{
"href":"\/app_dev.php\/api\/v1\/customers\/36"
}
}
},
"orderItem":{
"id":60,
"quantity":2,
"unitPrice":177581,
"total":355162,
"units":[
{
"id":1711,
"adjustments":[
],
"adjustmentsTotal":0
},
{
"id":1712,
"adjustments":[
],
"adjustmentsTotal":0
}
],
"unitsTotal":355162,
"adjustments":[
],
"adjustmentsTotal":0,
"variant":{
"id":334,
"code":"pool-gold-1oz",
"optionValues":[
],
"position":0,
"translations":{
"en_US":{
"locale":"en_US",
"id":334
}
},
"version":2,
"tracked":false,
"channelPricings":{
"UK_WEB":{
"channelCode":"UK_WEB",
"price":177582
},
"US_WEB":{
"channelCode":"US_WEB",
"price":177581
}
},
"_links":{
"self":{
"href":"\/app_dev.php\/api\/v1\/products\/pool-gold-1oz\/variants\/pool-gold-1oz"
}
}
},
"_links":{
"order":{
"href":"\/app_dev.php\/api\/v1\/orders\/29"
},
"product":{
"href":"\/app_dev.php\/api\/v1\/products\/pool-gold-1oz"
},
"variant":{
"href":"\/app_dev.php\/api\/v1\/products\/pool-gold-1oz\/variants\/pool-gold-1oz"
}
}
}
}
]
I want JSON response something like below sample response
- which need extra custom fields
- status code and message
- extra fields
- remove unwanted fields
{
"code":"custom_code_xxx",
"message":"Successful",
"data":[
{
"custom_extra_fields1":"asd",
"custom_extra_fields2":"xyz",
"id":1,
"orderId":123,
"certificateStatus":true,
"certificateNo":"xyz123abc",
"customer":{
"id":36,
"email":"abc#xyz.com",
"firstName":"abc",
"lastName":"dfg",
"user":{
"id":23,
"username":"abc#xyz.com",
"enabled":true,
"kycStatus":false
}
},
"orderItem":{
"id":60,
"quantity":2,
"unitPrice":177581,
"total":355162,
"unitsTotal":355162
}
}
]
}
Any best practice we can use to simplify JSON response ? or we need to construct an array in the required format

When you use something like e.g. JMS Serializer Bundle you can use
Virtual Properties for additional custom fields.
And Groups and/or Exclusion Policies to get rid of unwanted fields.
When using the Symfony Serializer you have at least the option of Groups to exclude some fields.
To add additional fields I'd either use simply an additional Getter in your Entity (no clean approach but helps) or work with custom normalizers and/or encoders.

Stefun,
You should create a new data transfer object containing the properties that you want as response. Then return that object as a json.
You then create an assembler class that builds your DTO based on the original object.

Related

Semantic-release release-notes-generator how to teach new types

Can anyone give us a hint how to configure #semantic-release/release-notes-generator to take extra commit types (those additional to preset ones) while generating release-notes?
Our commits-analyzer config:
"#semantic-release/commit-analyzer",
{
"preset": "angular",
"releaseRules": [
{
"type": "refactor",
"release": "patch"
},
{
"type": "minfeat",
"release": "patch"
}
]
}
At this moment we have no extra configuration for #semantic-release/release-notes-generator, and surely it requires some as new types don't show up in changelog that is generated by #semantic-release/changelog after release-notes-generator runs
You will have to implement your own conventional-changelog preset in order to handle those new commit type.
For example the default angular preset handles only certain commit types: https://github.com/conventional-changelog/conventional-changelog/blob/e865af4df8d06795cebc7af09364ade19119e089/packages/conventional-changelog-angular/writer-opts.js#L36

AppSync BatchDeleteItem not executes properly

I'm working on a React Native application with AppSync, and following is my schema to the problem:
type JoineeDeletedConnection {
items: [Joinee]
nextToken: String
}
type Mutation {
deleteJoinee(ids: [ID!]): [Joinee]
}
In 'request mapping template' to resolver to deleteJoinee, I have following (following the tutorial from https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-batch.html):
#set($ids = [])
#foreach($id in ${ctx.args.ids})
#set($map = {})
$util.qr($map.put("id", $util.dynamodb.toString($id)))
$util.qr($ids.add($map))
#end
{
"version" : "2018-05-29",
"operation" : "BatchDeleteItem",
"tables" : {
"JoineesTable": $util.toJson($ids)
}
}
..and in 'response mapping template' to the resolver,
$util.toJson($ctx.result.data.JoineesTable)
The problem is, when I ran the query, I got empty result and nothing deleted to database as well:
// calling the query
mutation DeleteJoinee {
deleteJoinee(ids: ["xxxx", "xxxx"])
{
id
}
}
// returns
{
"data": {
"deleteJoinee": [
null
]
}
}
I finally able to solve this puzzle, thanks to the answer mentioned here to point me to some direction.
Although, I noticed that JoineesTable does have trusted entity/role to the IAM 'Roles' section, yet it wasn't working for some reason. Looking into this more, I noticed that the existing policy had following actions as default:
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
]
Once I added following two more actions to the list, things have started working:
"dynamodb:BatchWriteItem",
"dynamodb:BatchGetItem"
Thanks to #Vasileios Lekakis and #Ionut Trestian on this appSync quest )

JSON Path not working properly with athena

I have a lambda function that converts my logs to this format:
{
"events": [
{
"field1": "value",
"field2": "value",
"field3": "value"
}, (...)
]
}
When I query it on S3, I get in this format:
[
{
"events": [
{ (...) }
]
}
]
And I'm trying to run a custom classifier for it because the data I want is inside the objects kept by 'events' and not events itself.
So I started with the simplest path I could think that worked in my tests (https://jsonpath.curiousconcept.com/)
$.events[*]
And, sure, worked in the tests but when I run a crawler against the file, the table created includes only an events field with a struct inside it.
So I tried a bunch of other paths:
$[*].events
$[*].['events']
$[*].['events'].[*]
$.[*].events[*]
$.events[*].[*]
Some of these does not even make sense and absolutely every one of those got me an schema with an events field marked as array.
Can anyone point me to a better direction to handle this issue?

FHIR : adding a custom extension

I would like to add to add a custom extension to my Schedule resource.
In my app, Schedule have visit motives (reasons). I know there's a list of classified appointments / encounter reasons but I would like to use mine.
I have something like this :
{
"resourceType":"Schedule",
"identifier":"logical_id",
"type":"schedule_speciality",
"actor":{
"practioner_id":"identifier",
"practioner_name":"practioner name"
},
"external_id":{
"extension":[
{
"url":"http://api.test.com/fhir/schedule/external_id",
"valueIdentifier":"external_id"
}
]
},
"visit_motives":{
"extension":[
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive1"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive2"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive3"
}
]
},
"practice_id":{
"extension":[
{
"url":"https://api.test.com/fhir/schedule/practice_id",
"valueIdentifier":"practice_id"
}
]
}
}
I'm not sure about this part :
"visit_motives":{
"extension":[
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive1"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive2"
},
{
"url":"https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"valueString":"vist_motive3"
}
]
}
Is it correct to add an extension this way ? There are always multiple visit motives for a specific schedule so I have to list them.
I also have seen this kind of things :
"visit_motives": {
"coding": [
{
"system": "https://api.test.com/fhir/ValueSet/schedule#visit_motives",
"code": "visit_motive1"
}
]
}
Which one is the correct one or am I wrong ?
There are several issues here:
It seems odd to capture a "reason" on a schedule. A schedule says when a particular clinician or clinic or other resource is available. E.g. "Dr. Smith takes appointments Mon/Wed/Fri from 1pm-4pm". So if you were to capture a reason on the resource, it would reflect "Why does Dr. Smith have a schedule?" Typically reasons are captured for an individual Appointment. That's the resource that reserves a particular slot for a planned visit. And Appointment already has an element for reason where you're free to use your own codes or just send text.
You have extensions to convey identifiers, but Schedule already has an element for identifiers. Why would you use extensions instead of the standard element? Note that you can use the "system" and/or "type" components to differentiate different kinds of identifiers.
You're sending "identifier", "type", "name", etc. as simple strings - but they're complex data types, so you need to communicate the child elements
actor is of type Reference - that means you need to point to the Practitioner resource. You can't send the properties in-line. (If the Practitioner only exists in the context of the Schedule, you could use the "contained" approach which would use an internal reference, but containment doesn't seem to make sense in this use-case.
The URL for your extension contains ValueSet, which isn't correct - extensions are all structure definitions. Also, there shouldn't be a # symbol in the URL.
Your syntax for extensions is incorrect. You can't introduce new properties in FHIR. The property name for all extensions is just "extension". You differentiate by the URL. So your syntax should be:
{
"resourceType":"Schedule",
"id":"logical_id",
"extension": [
{
"url":"https://api.test.com/fhir/StructureDefinition/schedule-visit_motive",
"valueString":"vist_motive1"
},
{
"url":"https://api.test.com/fhir/StructureDefinition/schedule-visit_motive",
"valueString":"vist_motive2"
},
{
"url":"https://api.test.com/fhir/StructureDefinition/schedule-visit_motives",
"valueString":"vist_motive3"
}
],
"identifier": [
{
"system": http://api.test.com/fhir/NamingSystem/external_id",
"value": "external_id"
}
{
"system": http://api.test.com/fhir/NamingSystem/practice_id",
"value": "practice_id"
}
]
"type": {
"coding": {
"system": "http://somewhere.org/fhir/CodeSystem/specialties",
"code": "schedule_speciality"
},
"text": "Some text description of specialty"
},
"actor":{
"reference": "http://myserver.org/fhir/Practitioner/12345"
"display": "Dr. smith"
}
}

Google Cloud Datastore runQuery returning 412 "no matching index found"

** UPDATE **
Thanks to Alfred Fuller for pointing out that I need to create a manual index for this query.
Unfortunately, using the JSON API, from a .NET application, there does not appear to be an officially supported way of doing so. In fact, there does not officially appear to be a way to do this at all from an app outside of App Engine, which is strange since the Cloud Datastore API was designed to allow access to the Datastore outside of App Engine.
The closest hack I could find was to POST the index definition using RPC to http://appengine.google.com/api/datastore/index/add. Can someone give me the raw spec for how to do this exactly (i.e. URL parameters, what exactly should the body look like, etc), perhaps using Fiddler to inspect the call made by appcfg.cmd?
** ORIGINAL QUESTION **
According to the docs, "a query can combine equality (EQUAL) filters for different properties, along with one or more inequality filters on a single property".
However, this query fails:
{
"query": {
"kinds": [
{
"name": "CodeProse.Pogo.Tests.TestPerson"
}
],
"filter": {
"compositeFilter": {
"operator": "and",
"filters": [
{
"propertyFilter": {
"operator": "equal",
"property": {
"name": "DepartmentCode"
},
"value": {
"integerValue": "123"
}
}
},
{
"propertyFilter": {
"operator": "greaterThan",
"property": {
"name": "HourlyRate"
},
"value": {
"doubleValue": 50
}
}
},
{
"propertyFilter": {
"operator": "lessThan",
"property": {
"name": "HourlyRate"
},
"value": {
"doubleValue": 100
}
}
}
]
}
}
}
}
with the following response:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "FAILED_PRECONDITION",
"message": "no matching index found.",
"locationType": "header",
"location": "If-Match"
}
],
"code": 412,
"message": "no matching index found."
}
}
The JSON API does not yet support local index generation, but we've documented a process that you can follow to generate the xml definition of the index at https://developers.google.com/datastore/docs/tools/indexconfig#Datastore_Manual_index_configuration
Please give this a shot and let us know if it doesn't work.
This is a temporary solution that we hope to replace with automatic local index generation as soon as we can.
The error "no matching index found." indicates that an index needs to be added for the query to work. See the auto index generation documentation.
In this case you need an index with the properties DepartmentCode and HourlyRate (in that order).
For gcloud-node I fixed it with those 3 links:
https://github.com/GoogleCloudPlatform/gcloud-node/issues/369
https://github.com/GoogleCloudPlatform/gcloud-node/blob/master/system-test/data/index.yaml
and most important link:
https://cloud.google.com/appengine/docs/python/config/indexconfig#Python_About_index_yaml to write your index.yaml file
As explained in the last link, an index is what allows complex queries to run faster by storing the result set of the queries in an index. When you get no matching index found it means that you tried to run a complex query involving order or filter. So to make your query work, you need to create your index on the google datastore indexes by creating a config file manually to define your indexes that represent the query you are trying to run. Here is how you fix:
create an index.yaml file in a folder named for example indexes in your app directory by following the directives for the python conf file: https://cloud.google.com/appengine/docs/python/config/indexconfig#Python_About_index_yaml or get inspiration from the gcloud-node tests in https://github.com/GoogleCloudPlatform/gcloud-node/blob/master/system-test/data/index.yaml
create the indexes from the config file with this command:
gcloud preview datastore create-indexes indexes/index.yaml
see https://cloud.google.com/sdk/gcloud/reference/preview/datastore/create-indexes
wait for the indexes to serve on your developer console in Cloud Datastore/Indexes, the interface should display "serving" once the index is built
once it is serving your query should work
For example for this query:
var q = ds.createQuery('project')
.filter('tags =', category)
.order('-date');
index.yaml looks like:
indexes:
- kind: project
ancestor: no
properties:
- name: tags
- name: date
direction: desc
Try not to order the result. After removing orderby(), it worked for me.

Resources