Solid: correct way to store a JSON object - solid

I want to store a standard JSON object in the user’s Solid pod. After working through the Solid getting started tutorial, I found I could get/set the object in the VCARD.note parameter, but I suspect this is not the right way to do it.
Any advice on how to do this properly? The JSON object will be updated regularly and will typically have ~10-100 key pairs.

There are two options here.
Option 1 - store as RDF (recommended)
Generally, the recommended thing to do is not to store data as a standard JSON object, but rather to save the data as RDF. So for example, if you have a JSON object like
const user = {
name: "Vincent",
};
assuming you're using the JavaScript library #inrupt/solid-client, you'd create what it calls a "Thing" like this:
import { createThing, addStringNoLocale } from "#inrupt/solid-client";
import { foaf } from "rdf-namespaces";
let userThing = createThing();
userThing = addStringNoLocale(userThing, foaf.fn, "Vincent");
You can read more about this approach at https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/read-write-data/
Option 2 - store a JSON blob directly
The other option is indeed to store a JSON file directly in the Pod. This works, although it goes a bit against the spirit of Solid, and requires you to overwrite the complete file every time, rather than allowing you to just update individual properties whenever you update the data. You could do that as follows:
import { overwriteFile } from "#inrupt/solid-client";
const user = {
name: "Vincent",
};
// This is assuming you're working in the browser;
// in Node, you'll have to create a Buffer instead of a Blob.
overwriteFile(
"https://my.pod/location-of-the-file.json",
new Blob([
JSON.stringify(user),
]),
{ type: "application/json" },
).then(() => console.log("Saved the JSON file.}));
You can read more about this approach here: https://docs.inrupt.com/developer-tools/javascript/client-libraries/tutorial/read-write-files/

Related

Using the CfnOutput created inside a LambdaRestApi in AWS CDK

I'm creating a LambdaRestApi as follows
this.gateway = new apigw.LambdaRestApi(this, "Endpoint", {
handler: hello,
endpointExportName: "MainURL"
})
and I'd like to get to the CfnOutput it generates, is it possible? I want to pass it to other functions and I want to avoid creating a new one.
Specifically the situation I'm tackling is this: I have have a post stage that verifies things are working at it uses the CfnOutput:
deployStage.addPost(
new CodeBuildStep("VerifyAPIGatewayEndpoint", {
envFromCfnOutputs: {
ENDPOINT_URL: deploy.hcEndpoint
},
commands: [
"curl -Ssf $ENDPOINT_URL",
"curl -Ssf $ENDPOINT_URL/hello",
"curl -Ssf $ENDPOINT_URL/test"
]
})
)
That deploy.hcEndpoint is a CfnOutput that I'm manually creating after the LambdaRestApi is created:
const gateway = new LambdaRestApi(this, "Endpoint", {handler: hello})
this.hcEndpoint = new CfnOutput(this, "GatewayUrl", {value: gateway.url})
and then making sure that every construct makes it available to its parent.
Using CfnOutputs in the post-deployment step makes sense. I am trying to learn the proper way of doing things, and also have clean stacks. With only one Lambda function it's no big deal, but with tens or hundreds it might. And since LambdaRestApi already creates the output, it does feel like I'm repeating myself by creating an identical one.
Assuming you are using the following code for your LambdaRestApi:
this.gateway = new apigw.LambdaRestApi(this, "Endpoint", {
handler: hello,
endpointExportName: "MainURL"
});
Referencing in same stack as LambdaRestApi
const outputValue = this.gateway.urlForPath("/");
Looking at the source code, the output value is just a call to urlForPath. The method is public, so you can use it directly.
Referencing from another stack
You can use cross stack references to get a reference to the output value of the stack.
import { Fn } from 'aws-cdk-lib';
const outputValue = Fn.importValue("MainURL");
If you try to use the first method in another stack, CDK will just generate a cross stack reference dynamically by adding extra outputs, so it is better to import the value directly.
I'd like to get to the CfnOutput it generates, is it possible?
Yes. Use the escape hatch syntax to get a reference to the CfnOutput that RestApi creates for the endpointExportName:
const urlCfnOutput = this.gateway.node.findChild('Endpoint') as cdk.CfnOutput;
console.log(urlCfnOutput.exportName);
// MainURL
console.log(urlCfnOutput.value);
// https://${Token[TOKEN.258]}.execute-api.us-east-1.${Token[AWS.URLSuffix.3]}/${Token[TOKEN.277]}/
Prefer standard CDK
As their name suggests, "escape hatches" are for "emergencies" when the CDK's standard solutions fail. Your use case may be one such instance, I don't know. But as #Kaustubh Khavnekar points out, you don't need the CfnOutput to get the url token value.
console.log(this.gateway.url)
// https://${Token[TOKEN.258]}.execute-api.us-east-1.${Token[AWS.URLSuffix.3]}/${Token[TOKEN.277]}/

Set Jackson DeserializationContext Attribute in per-request, thread-safe manner

I'm looking to be able to add a request-scoped attribute (a JAX-RS ContainerRequestContext because I would rather use Jackson to convert my parameters to objects than JAX-RS's ill conceived and clunky ParameterConverterProviders) to a DeserializationContext so that it can be obtained from within a JsonDeserializer. I must call convertValue() rather than simply readValue() (not dealing with actual JSON) so I am not able to create an ObjectReader in each thread unless I am willing to serialize my map to a JSON string first and then read it back -which would be incredibly inefficient.
I'd like to be able to do something that accomplishes the following but in a per request manner:
ObjectMapper om = new ObjectMapper();
//in request-scoped context:
om.getDeserializationContext().setAttribute("requestContext",containerRequestContext)
Map<String,Object> mapOfRequestParameters = ...
BeanOfVastImportance bean = om.convertValue(mapOfRequestParameters,BeanOfVastImportance.class)
How can I achieve this without the massive, superfluous overhead of needing to create a new ObjectMapper for each individual request thread?
This may be achieved with:
objectMapper.reader().forType(Request.class)
.withAttribute("key", "value").readValue<Request>("source")

EmberJS client side record management (ember-data)

I have just started trying to use ember-data. I have an ember app for which I need to produce all the data on the client side and then save it all at once. So my object graph has a "Project" as the root object, then a project can have many "Sections" and then each section can have many "Items".
I am up to the stage where I am trying to create Item records on the client side and add them to the correct Section. When I am ready to save the data I just want to use project.save() and have it go and save the object graph instead of saving every time the model changes.
I am trying to look up the section to place the items in by name using store.filter({name:"section1"}) but ember keeps trying to go to the server to look them up. I see this in the console: GET http://localhost:4200/sections?name=Section1 404 (Not Found).
This is what I am trying to do:
store.filter('section', {name:'Section1'}, function(section) {
return section;
}).then(function(section)
{
var record;
//create a record
section.pushObject(record);
});
You are doing server side filtering and you want client side filtering.
Please read this article carefully.
In short, you should do
store.filter('section', function(section) {
return section.get('name') == 'Section1';
});

How to manually set a primary key in Doctrine2

I am importing data into a new Symfony2 project using Doctrine2 ORM.
All new records should have an auto-generated primary key. However, for my import, I would like to preserve the existing primary keys.
I am using this as my Entity configuration:
type: entity
id:
id:
type: integer
generator: { strategy: AUTO }
I have also created a setter for the id field in my entity class.
However, when I persist and flush this entity to the database, the key I manually set is not preserved.
What is the best workaround or solution for this?
The following answer is not mine but OP's, which was posted in the question. I've moved it into this community wiki answer.
I stored a reference to the Connection object and used that to manually insert rows and update relations. This avoids the persister and identity generators altogether. It is also possible to use the Connection to wrap all of this work in a transaction.
Once you have executed the insert statements, you may then update the relations.
This is a good solution because it avoids any potential problems you may experience when swapping out your configuration on a live server.
In your init function:
// Get the Connection
$this->connection = $this->getContainer()->get('doctrine')->getEntityManager()->getConnection();
In your main body:
// Loop over my array of old data adding records
$this->connection->beginTransaction();
foreach(array_slice($records, 1) as $record)
{
$this->addRecord($records[0], $record);
}
try
{
$this->connection->commit();
}
catch(Exception $e)
{
$output->writeln($e->getMessage());
$this->connection->rollBack();
exit(1);
}
Create this function:
// Add a record to the database using Connection
protected function addRecord($columns, $oldRecord)
{
// Insert data into Record table
$record = array();
foreach($columns as $key => $column)
{
$record[$column] = $oldRecord[$key];
}
$record['id'] = $record['rkey'];
// Insert the data
$this->connection->insert('Record', $record);
}
You've likely already considered this, but my approach would be to set the generator strategy to 'none' for the import so you can manually import the existing id's in your client code. Then once the import is complete, change the generator strategy back to 'auto' to let the RDBMS take over from there. A conditional can determine whether the id setter is invoked. Good luck - let us know what you end up deciding to use.

How should I do post persist/update actions in doctrine 2.1, that involves re-saving to the db?

Using doctrine 2.1 (and zend framework 1.11, not that it matters for this matter), how can I do post persist and post update actions, that involves re-saving to the db?
For example, creating a unique token based on the just generated primary key' id, or generating a thumbnail for an uploaded image (which actually doesn't require re-saving to the db, but still) ?
EDIT - let's explain, shall we ?
The above is actually a question regarding two scenarios. Both scenarios relate to the following state:
Let's say I have a User entity. When the object is flushed after it has been marked to be persisted, it'll have the normal auto-generated id of mysql - meaning running numbers normally beginning at 1, 2, 3, etc..
Each user can upload an image - which he will be able to use in the application - which will have a record in the db as well. So I have another entity called Image. Each Image entity also has an auto-generated id - same methodology as the user id.
Now - here is the scenarios:
When a user uploads an image, I want to generate a thumbnail for that image right after it is saved to the db. This should happen for every new or updated image.
Since we're trying to stay smart, I don't want the code to generate the thumbnail to be written like this:
$image = new Image();
...
$entityManager->persist($image);
$entityManager->flush();
callToFunctionThatGeneratesThumbnailOnImage($image);
but rather I want it to occur automatically on the persisting of the object (well, flush of the persisted object), like the prePersist or preUpdate methods.
Since the user uploaded an image, he get's a link to it. It will probably look something like: http://www.mysite.com/showImage?id=[IMAGEID].
This allows anyone to just change the imageid in this link, and see other user's images.
So in order to prevent such a thing, I want to generate a unique token for every image. Since it doesn't really need to be sophisticated, I thought about using the md5 value of the image id, with some salt.
But for that, I need to have the id of that image - which I'll only have after flushing the persisted object - then generate the md5, and then saving it again to the db.
Understand that the links for the images are supposed to be publicly accessible so I can't just allow an authenticated user to view them by some kind of permission rules.
You probably know already about Doctrine events. What you could do:
Use the postPersist event handler. That one occurs after the DB insert, so the auto generated ids are available.
The EventManager class can help you with this:
class MyEventListener
{
public function postPersist(LifecycleEventArgs $eventArgs)
{
// in a listener you have the entity instance and the
// EntityManager available via the event arguments
$entity = $eventArgs->getEntity();
$em = $eventArgs->getEntityManager();
if ($entity instanceof User) {
// do some stuff
}
}
}
$eventManager = $em->getEventManager():
$eventManager->addEventListener(Events::postPersist, new MyEventListener());
Be sure to check e. g. if the User already has an Image, otherwise if you call flush in the event listener, you might be caught in an endless loop.
Of course you could also make your User class aware of that image creation operation with an inline postPersist eventHandler and add #HasLifecycleCallbacks in your mapping and then always flush at the end of the request e. g. in a shutdown function, but in my opinion this kind of stuff belongs in a separate listener. YMMV.
If you need the entity id before flushing, just after creating the object, another approach is to generate the ids for the entities within your application, e. g. using uuids.
Now you can do something like:
class Entity {
public function __construct()
{
$this->id = uuid_create();
}
}
Now you have an id already set when you just do:
$e = new Entity();
And you only need to call EntityManager::flush at the end of the request
In the end, I listened to #Arms who commented on the question.
I started using a service layer for doing such things.
So now, I have a method in the service layer which creates the Image entity. After it calls the persist and flush, it calls the method that generates the thumbnail.
The Service Layer pattern is a good solution for such things.