I'm learning Backbone.js as I feel it will come handy for my projects.
I'm running thru different tutorials and I cant's find the difference and best declaration for a class like:
Person = Backbone.Model.extend({
defaults: {
name: 'Andy',
age: 25,
occupation: 'Whatever...'
}
});
Is it better to initialize a Class this way:
var me = new Person({name: 'Andy'});
or
var me = new Person({'name': 'Andy'});
Why should I use single quotes to set a variable? It takes more time, but what's best? What's right and why?
I'm not sure if is only a JSON matter or if is a backbone matter as actually this is a matter of initialization and use of curly brackets.
In case I use .set(var, value) and the variable has no quotes backbone throws an error as is looking for a variable.
I tried looking in Backbone.js website and JSON website but can't find an answer to this.
If we are being pedantic, then valid JSON requires the single-quotes for all keys. JSLint, for example, will reject JSON without the quotes.
But in Javascript they are not needed, and most people leave them out (as you noted, it's more concise). That is, unless you have reserved characters in the name like -, etc. So for example, { name: 'Andy' } is fine, but { first-name: 'Andy' } will cause the parser to balk.
Related
I'm creating a custom terraform provider and I came across this issue.
I was trying to convert a schema.TypeList field into a struct, the TypeList looks something like this:
"template": {
Type: schema.TypeList,
Required: true,
ForceNew: false,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"lists_test": {
Type: schema.TypeSet,
Required: true,
ForceNew: false,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"name_test": {
Type: schema.TypeString,
Required: true,
ForceNew: false,
},
},},
and the struct that I'm trying to align to looks something like this:
type TestStruct struct {
NameTest string `json:"name_test"`
ListsTests []string `json:"lists_test"`
}
I tried a couple of solutions, for instance I tried unmarshalling it to json. Something like below:
template := d.Get("template").([]interface{})[0].(map[string]interface{})
templateStr, err := json.Marshal(template)
templateConverted := &TestStruct{}
json.Unmarshal(template, templateConverted)
however, I'm getting an error json: unsupported type: SchemaSetFunc, which is probably because it's trying to marshal a schema.Schema type instead of map[string]interface{} type, which confuses me. I also tried to use gohcl.DecodeBody but I abandoned the idea since it's usage seems more inclined into reading direct tf files rather than *schema.ResourceData types.
Does anyone had the same experience dealing with this type of scenario? Any help or suggestion is appreciated. Thank you!
Terraform's older SDK (SDKv2) is not designed around the paradigm of decoding into a tagged structure, and instead expects you to use d.Get and manually type-assert individual values, which in your case would perhaps look something like this:
raw := d.Get("template").([]interface{})[0].(map[string]interface{})
t := &TestStruct{
NameTest: raw["name_test"].(string),
ListsTests: make([]string, len(raw["lists_test"].([]interface{})),
}
for i, itemRaw := range raw["lists_test"].([]interface{}) {
t.ListsTests[i] = itemRaw.(string)
}
The idiomatic style for most Terraform providers is to write logic like this in separate functions for each complex-typed attribute, where each returns an object of the appropriate type in the target platform's SDK. There would typically also be a matching function for going in the opposite direction: given an object from the target platform's SDK, return a map[string]interface{} that can be assigned to this attribute using d.Set.
However, just because there isn't something built in to the SDK to handle this, that doesn't mean you can't use other libraries that are more general utilities for use in any Go programs.
One example library is github.com/mitchellh/mapstructure, which is designed for exactly the goal you have in mind: to take a value of some interface type and try to use reflection to fit it onto a tagged structure type.
If you want to use that library then you would need to annotate your structure with mapstructure:, instead of the json: ones, and then pass your raw value to the mapstructure.Decode function:
raw := d.Get("template").([]interface{})[0].(map[string]interface{})
var t TestStruct
err := mapstructure.Decode(raw, &t)
Since the schema.ResourceData abstraction in SDKv2 guarantees to return specific data types based on the schema you defined, you should not typically get errors from mapstructure.Decode as long as your schema and your target type match, but still a good idea to check for errors anyway because otherwise your t value may not be completely populated, causing confusing broken behavior downstream.
This is not a typical implementation style used in the official providers, but there's no real harm in writing your provider in this way if you find this style more convenient, or easier to maintain.
Alternatively, if you are not already deeply invested in SDKv2 then you may wish to consider using Terraform Plugin Framework instead. As well as being designed around the type system of modern Terraform (whereas SDKv2 was designed for Terraform v0.11 and earlier), it also supports a programming style more like what you are aiming for, with methods like tfsdk.Plan.Get and tfsdk.Plan.GetAttribute that can decode directly into an appropriately-shaped and appropriately tagged "normal" Go value.
I can't easily show an example of that because it would presume a provider written in quite a different way, but hopefully you can see from the signature of those two functions how they might be used. There's some more commentary and examples in Accessing State, Config, and Plan.
I'm redoing the backend of a very basic framework that connects to a completely customizable frontend. It was originally in PHP but for the refactor have been plodding away in F#. Although it seems like PHP might be the more suited language. But people keep telling me you can do everything in F# and I like the syntax and need to learn and this seemingly simple project has me stumped when it comes to JSON. This is a further fleshed out version of my question yesterday, but it got alot more complex than I thought.
Here goes.
The frontend is basically a collection of HTML files, which are simply loaded in PHP and preg_replace() is used to replace things like [var: varName] or [var: array|key] or the troublesome one: [lang: hello]. That needs to be replaced by a variable defined in a translation dictionary, which is stored as JSON which is also editable by a non-programmer.
I can't change the frontend or the JSON files, and both are designed to be edited by non-programmers so it is very likely that there will be errors, calls to language variables that don't exist etc.
So we might have 2 json files, english.json and french.json
english.json contains:
{
"hello":"Hello",
"bye":"Goodbye"
}
french.json:
{
"hello": "Bonjour",
"duck": "Canard"
//Plus users can add whatever else they want here and expect to be able to use it in a template
}
There is a template that contains
<b>[lang: hello]</b>
<span>Favourite Animal: [lang:duck]</span>
In this case, if the language is set to "english" and english.json is being loaded, that should read:
<b>Hello</b>
<span>Favourite Animal: </span>
Or in French:
<b>Bonjour</b>
<span>Favourite Animal: Canard</span>
We can assume that the json format key: value is always string:string but ideally I'd like to handle string: 'T as well but that might be beyond the scope of this question.
So I need to convert a JSON file (called by dynamic name, which gave F# Data a bit of an issue I couldn't solve last night as it only allowed a static filename as a sample, and since these two files have potential to be different from sample and provided, the type provider doesn't work) to a dictionary or some other collection.
Now inside the template parsing function I need to replace [lang: hello] with something like
let key = "duck"
(*Magic function to convert JSON to usable collection*)
let languageString = convertedJSONCollection.[key] (*And obviously check if containsKey first*)
Which means I need to call the key dynamically, and I couldn't figure out how to do that with the type that FSharp.Data provided.
I have played around with some Thoth as well to some promising results that ended up going nowhere. I avoided JSON.NET because I thought it was paid, but just realised I am mistaken there so might be an avenue to explore
For comparison, the PHP function looks something like this:
function loadLanguage($lang='english){
$json = file_get_contents("$lang.json");
return json_decode($json, true);
}
$key = 'duck';
$langVars = loadLanguage();
$duck = $langVars[$key] || "";
Is there a clean way to do this in F#/.NET? JSON seems really painful to work with in comparison to PHP/Javascript and I'm starting to lose my mind. Am I going to have to write my own parser (which means probably going back to PHP)?
Cheers to all you F# geniuses who know the answer :p
open Thoth.Json.Net
let deserialiseDictionary (s: string) =
s
|> Decode.unsafeFromString (Decode.keyValuePairs Decode.string)
|> Map.ofList
let printDictionary json =
json
|> deserialiseDictionary
|> fun m -> printfn "%s" m.["hello"] // Hello
For the question about 'T the question becomes, what can 'T be? For json it very limited, it can be a number of things, string, json-object, number, bool or json array. What should happen if it is bool or a number?
JOI 10 is used to validate calls against an API. I now want to sanitize many (but not all) of the strings that are contained in the JSONs before validating them, namely filter out certain characters. I know that this would be an easy task with a recent JOI version as there's the custom() method that I could use. Unfortunately updating JOI is not an option and so I am currently looking for an elegant way to solve this, preferably using the JOI schemas.
I found that there is the extend() function which allows me to define custom types/validations. However, I am not entirely sure how to use it and where to put the code. Also, I am not sure if it's suited to alter the string at all. Can I use extend() to achieve this? If not, is there another way to do this within JOI?
OK, it's actually pretty easy.
const customJOI = JOI.extend({
name: "sanitizedString",
base: JOI.string(),
pre(value: string, state: any, options: any) {
return value.replace(/yourregex/, "");
}
});
and just use customJOI instead of JOI where the sanitization is needed with .sanitizedString() instead of .string().
Can I map Scala functions to JSON; or perhaps via a different way than JSON?
I know I can map data types, which is fine. But I'd like to create a function, map it to JSON send it via a REST method to another server, then add that function to a list of functions in another application and apply it.
For instance:
def apply(f: Int => String, v: Int) = f(v)
I want to make a list of functions that can be applied within an application, over different physical locations. Now I want to add and remove functions to the list. By means of REST calls.
Let's assume I understand security problems...
ps.. If you downvote, you might as well have the decency to explain why
If I understand correctly, you want to be able to send Scala code to be executed on different physical machines. I can think of a few different ways of achieving that
Using tools for distributed computing e.g. Spark. You can set up Spark clusters on different machines and then select to which cluster you want to submit Spark jobs. There are a lot of other tools for distributed computing that might also be worth looking into.
Pass scala code as a string and compile it either within your server side code (here's an example) or by invoking scalac as an external process.
Send the functions as byte code and execute the byte code on the remote machine.
If it fits with what you want to do, I'd recommend option #1.
Make sure that you can really trust the code that you want to execute, to not expose yourself to malicious code.
The answer is you can't do this, and even if you could you shouldn't!
You should never, never, never write a REST API that allows the client to execute arbitrary code in your application.
What you can do is create a number of named operations that can be executed. The client can then pass the name of the operation which the server can look up in a Map[String, <function>] and execute the result.
As mentioned in my comment, here is an example of how to turn a case class into JSON. Things to note: don't question the implicit val format line (it's magic); each case class requires a companion object in order to work; if you have Optional fields in your case class and define them as None when turning it into JSON, those fields will be ignored (if you define them as Some(whatever), they will look like any other field). If you don't know much about Scala Play, ignore the extra stuff for now - this is just inside the default Controller you're given when you make a new Project in IntelliJ.
package controllers
import javax.inject._
import play.api.libs.json.{Json, OFormat}
import play.api.mvc._
import scala.concurrent.Future
#Singleton
class HomeController #Inject()(cc: ControllerComponents) extends AbstractController(cc) {
case class Attributes(heightInCM: Int, weightInKG: Int, eyeColour: String)
object Attributes {
implicit val format: OFormat[Attributes] = Json.format[Attributes]
}
case class Person(name: String, age: Int, attributes: Attributes)
object Person {
implicit val format: OFormat[Person] = Json.format[Person]
}
def index: Action[AnyContent] = Action.async {
val newPerson = Person("James", 24, Attributes(192, 83, "green"))
Future.successful(Ok(Json.toJson(newPerson)))
}
}
When you run this app with sbt run and hit localhost:9000 through a browser, the output you see on-screen is below (formatted for better reading). This is also an example of how you might send JSON as a response to a GET request. It isn't the cleanest example but it works.
{
"name":"James",
"age":24,
"attributes":
{
"heightInCM":187,
"weightInKG":83,
"eyeColour":"green"
}
}
Once more though, I would never recommend passing actual functions between services. If you insist though, maybe store them as a String in a Case Class and turn it into JSON like this. Even if you are okay with passing functions around, it might even be a good exercise to practice security by validating the functions you receive to make sure they're not malicious.
I also have no idea how you'll convert them back into a function either - maybe write the String you receive to a *.scala file and try to run them with a Bash script? Idk. I'll let you figure that one out.
I'm learning Dart and was reading the article Using Dart with JSON Web Services, which told me that I could get help with type checking when converting my objects to and from JSON. I used their code snippet but ended up with compiler warnings. I found another Stack Overflow question which discussed the same problem, and the answer was to use the #proxy annotation and implement noSuchMethod. Here's my attempt:
abstract class Language {
String language;
List targets;
Map website;
}
#proxy
class LanguageImpl extends JsonObject implements Language {
LanguageImpl();
factory LanguageImpl.fromJsonString(string) {
return new JsonObject.fromJsonString(string, new LanguageImpl());
}
noSuchMethod(i) => super.noSuchMethod(i);
}
I don't know if the noSuchMethod implementation is correct, and #proxy seems redundant now. Regardless, the code doesn't do what I want. If I run
var lang1 = new LanguageImpl.fromJsonString('{"language":"Dart"}');
print(JSON.encode(lang1));
print(lang1.language);
print(lang1.language + "!");
var lang2 = new LanguageImpl.fromJsonString('{"language":13.37000}');
print(JSON.encode(lang2));
print(lang2.language);
print(lang2.language + "!");
I get the output
{"language":"Dart"}
Dart
Dart!
{"language":13.37}
13.37
type 'String' is not a subtype of type 'num' of 'other'.
and then a stacktrace. Hence, although the readability is a little bit better (one of the goals of the article), the strong typing promised by the article doesn't work and the code might or might not crash, depending on the input.
What am I doing wrong?
The article mentions static types in one paragraph but JsonObject has nothing to do with static types.
What you get from JsonObject is that you don't need Map access syntax.
Instead of someMap['language'] = value; you can write someObj.language = value; and you get the fields in the autocomplete list, but Dart is not able to do any type checking neither when you assign a value to a field of the object (someObj.language = value;) nor when you use fromJsonString() (as mentioned because of noSuchMethod/#proxy).
I assume that you want an exception to be thrown on this line:
var lang2 = new LanguageImpl.fromJsonString('{"language":13.37000}');
because 13.37 is not a String. In order for JsonObject to do this it would need to use mirrors to determine the type of the field and manually do a type check. This is possible, but it would add to the dart2js output size.
So barring that, I think that throwing a type error when reading the field is reasonable, and you might have just found a bug-worthy issue here. Since noSuchMethod is being used to implement an abstract method, the runtime can actually do a type check on the arguments and return values. It appears from your example that it's not. Care to file a bug?
If this was addressed, then JsonObject could immediate read a field after setting it to cause a type check when decoding without mirrors, and it could do that check in an assert() so that it's only done in checked mode. I think that would be a nice solution.