SlimPHP route with empty parameter fails - url-routing

I have a route like this
/product/update/{productId}/part/{partId}
If I try to call that with one or more empty parameters, it fails and gives me a HTTP 404 Not Found, for example
https://localhost/product/update//part/xyz123
I can't make them both optional, because I still want to require the full URL, including /part/.
Is it not possible to pass empty parameters to a route using Slim 3? From what I understand, having multiple consecutive slashes is allowed in a URL path?

You can let parameters match empty strings by explicitly defining the regular expression they will match:
$app->get('/product/update/{productId:.*}/part/{partId:.*}', function ($request, $response, $args) {
$productId = !empty($args['productId']) ? $args['productId'] : 'not available';
$partId = !empty($args['partId']) ? $args['partId'] : 'not available';
return (sprintf('Product ID: %s, Part ID: %s', $productId, $partId));
});
// /product/update/1/part/2 -> Product ID: 1, Part ID: 2
// /product/update/1/part/ -> Product ID: 1, Part ID: not available
// /product/update//part/2 -> Product ID: not available, Part ID: 2

Related

How to cope a data to a scope as a backup field in Angularjs to roll back when request failed?

I'm having a block of data, then when i edit one of them, i want to copy the current date of the item to a scope like $scope.backup_field to be able to roll back when the update failed. As my code below, the $scope.backup_field can get the item's data which i'm editing, but when the updated failed, i console log out the $scope.backup_field is also modify following the newest data that i modified.
My code:
$scope.block_data = [
[
{id: 1, name: 'Data 1'},
{id: 2, name: 'Data 2'}
],
[
{id: 3, name: 'Data 3'}
]
];
$scope.backup_field = [[],[],[],[],[],[]];
$scope.editItem = function(_no, index){// _no has value from 0 to 6
$scope.backup_field[_no][index] = $scope.block_data[_no][index];
}
$scope.updateItem = function(_no, index){
$http.post(.....).then(function (response){
var res = response.data;
if (res.status === 200){
//Do something if update successfully
}else {
alert('Failed');
$scope.block_data[_no][index] = $scope.backup_field[_no][index]; //The problem is here, the $scope.backup_field[_no][index] value also change following the data of item that user modified in UI.
}
})
}
you have to use angular.copy for that -
Creates a deep copy of source, which should be an object or an array.
This functions is used internally, mostly in the change-detection
code. It is not intended as an all-purpose copy function, and has
several limitations (see below).
$scope.block_data[_no][index] = angular.copy($scope.backup_field[_no][index]);

Reactjs # symbol in parameter: item.enclosure.#attributes how to fix, that this is possible?

I have a .map function in my code and Im getting data from a json output but one of the item parameters is: #attribute but I cant have an # symbol in the parameter so is there any way I can fix this?
I coudn't really find anything about this because I'm not sure what to search for except for # symbol in parameter.
this is the code I used to get the data:
this.state.news.channel.item.map(function (item, i) {
console.log(item.enclosure.#attributes)
{#attributes: {…}}
#attributes:
length: "0"
type: "image/jpeg"
url: "https://media.nu.nl/m/aoqxps0aijuy_sqr256.jpg/barnier-eu-niet-onder-de-indruk-van-no-deal-brexit-dreigement.jpg"
__proto__: Object
__proto__: Object
So how can I fix that I can have an # in the parameter and it properly gets the data from the json.
Try this:
this.state.news.channel.item.map(function (item, i) {
console.log(item.enclosure["#attributes"])
});
Retrieving the value of a property
We can retrieve the value of a property using 2 different syntaxes.
const car = {
brand: {
name: 'Ford'
},
color: 'blue',
'the color': 'blue'
}
The first is dot notation:
car.color
The second, which is mandatory for properties with invalid names, is to use square brackets:
car['the color']
or even mixing:
car.brand['name']
car['brand'].name

How to use interface to type function argument in Flow

I'm trying to implement a React component that contains a list of options and shows their id and name. I want this component to be reusable so I define an interface Option to ensure the required fields are always provided.
And here comes the issue: if I pass any type with more fields than those 2 { id, name, /* anything */}, Flow complains. Is it not possible to use interfaces in Flow like this?
Here's the minimal relevant code:
interface Option {
id: string,
name: string
}
const List = (options: Option[]) => {
options.forEach(o => null)
}
type ImplementsOption = {
id: string,
name: string,
description: string
}
const plans: ImplementsOption[] = []
List(plans)
Error:
Cannot call List with plans bound to options because property description is missing in Option 1 but exists in ImplementsOption [2] in array element.
Trying with casting:
List((plans: Option[]))
And also with classes:
class ComplexOption implements Option {
id: string
name: string
}
const complexOptions: ComplexOption[] = []
List(complexOptions)
Nothing seems to work!
There is a playground with all these snippets already.
Imagine we had a list of ImplementsOption: [{ id: 'id', name: 'name', description: 'description' }, ...]. Now we pass it into the List function, which has the signature Option[] => void. This is totally valid from the point of view of List since ImplementOption is a supertype of Option. However, there is no guarantee in the List function that it won't modify the list that is passed in. Thus, the function could add an element of type Option to the list, which would be valid for a Option[] but invalid for a ImplementsOption[].
To fix this, you can type plans as a $ReadOnlyArray<Option>, which tells Flow that the List function will not modify the elements (try flow).
Reference issues #4425, #4483, or #5206 for more information.

How to pass root parameters in the resolver function of a nested query?

I have a query of the following nature
Category1(name: $cat1){
Category2(secondName: $cat2){
secondName
}}
My schema is like so:
const Query = new GraphQLObjectType({
name: 'Query',
fields: {
Category1: {
type: new GraphQLList(Category1Type),
args: { name },
resolve: resolveCategory1
}}
})
And then the Category1Type is defined as:
const Category1Type = new GraphQLObjectType({
name: 'Category1',
description: '<>',
fields: () => ({
name: { type: GraphQLString },
category2: {
type: new GraphQLList(CategoryType2),
args: { secondName },
resolve: resolveCategory2
}
})
});
For simplicity sake, assume category2 is like so:
const Category2Type = new GraphQLObjectType({
name: 'Category2',
description: '<>',
fields: () => ({
name: { type: GraphQLString },
})
});
Now I want to fetch all Category2 items under Category1 with option to filter, like so:
Category1(name: $name){
name
category2(name: $name){
name
}}
My resolvers are defined like so:
# Category1 resolver
function cat1resolve (root, args) {
return SELECT * from data WHERE category1_name = args.name
}
# Category2 resolver
function cat2Resolve (root, args) {
return SELECT * from data WHERE category1_name = rootargs.name and categort2_name = args.secondName }
Now the problem is that the 'resolver' for cat2Resolve is not able to see or receive the rootargs.name for me to do this kind of filtering.
The resolve function signature includes 4 parameters. From Apollo's docs:
obj: The object that contains the result returned from the resolver on the parent field, or, in the case of a top-level Query field, the
rootValue passed from the server configuration. This argument enables
the nested nature of GraphQL queries.
args: An object with the arguments passed into the field in the query. For example, if the field was called with author(name: "Ada"),
the args object would be: { "name": "Ada" }.
context: This is an object shared by all resolvers in a particular query, and is used to contain per-request state, including
authentication information, dataloader instances, and anything else
that should be taken into account when resolving the query. If you’re
using Apollo Server, read about how to set the context in the setup
documentation.
info: This argument should only be used in advanced cases, but it contains information about the execution state of the query, including
the field name, path to the field from the root, and more. It’s only
documented in the GraphQL.js source code.
Note: These docs are for graphql-tools' makeExecutableSchema (which I highly recommend) but the same applies to plain old GraphQL.JS.
The key point here is that a resolver for a particular field is generally agnostic to what other resolvers do or what information is passed to them. It's handed its own parent field value, its own arguments, the context and expected to work with that.
However, there is a workaround utilizing the info parameter. The object passed to info is huge and can be complicated to parse, but contains virtually all the information about the requested query itself. There are libraries out to help with parsing it, but you may want to print the whole thing to console and poke around (it's pretty cool!).
Using something like lodash's get, we can then do:
const category1id = get(info, 'operation.selectionSet.selections[0].arguments[0].value.value')
and utilize that value inside your query. The above is pretty fragile, since it assumes your request only contains the one query, and you only have one argument on the Category1 field. In practice, you'd probably want to utilize Array.find and look up the fields/arguments by name, but this should give you a starting point.

mongoose query: find an object by id in an array

How could I find an image by id in this Schema. I have the id of the User and the id of the image I am looking for. What would be the best way to do this and do all images in this case have different ids or could they have the same id because they don't belong to the same User?
My Schema looks like this:
var userSchema = new Schema({
local: {
email: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
name: String,
about: String,
images: [{
id: Schema.ObjectId,
link: String,
main: Boolean
}]
});
When you are interested in the full object it is a simple find:
.find({"facebook.id":"<id>", "images.id":<image-id>})
I don't think that there is a way to reduce the image array in the result.
To update a single element in the image array you can use this:
.update({"facebook.id":"<id>", "images.id":<image-id>}, {$set : {"images.$.main" :false} } );
userSchema .find({facebook.id: "some ID",{ "images.id": { $in: [ id1, id2, ...idn] }}
since images are inside the document you can have same ID's however every time you query you should keep in mind that you send some other parameters such as facebook.id or facebook.email along with image id's to retrieve them. Otherwise you end up getting all that might be irrelevant only because you decide to keep same ID's for images.
tl;dr
I struggled with this and came up with a solution. Like you, I was trying to query for a deeply nested object by the _id, but I kept coming up empty with the results. It wasn't until I did some type checking that I realized the id value I was getting from my frontend, while directly supplied by mongoose, was in fact a String and not an Object.
I realize this question was already partially answered before, but that person's solution didn't work for me, and the comment on the answer tells me you wanted to update the specific image you queried for, which is exactly what I was trying to do.
The solution
In order to select an object from the nested array by the _id value, first you'll have to install the npm package bson-objectid and use the provided method to convert your string into an objectId in your query.
In your terminal:
npm i bson-objectid
In your code:
const ObjectId = require('bson-objectid')
userSchema.findOneAndUpdate(
{ "facebook.id": <user-id>, "images._id": ObjectId(<image-id>) },
{ "$set": { "images.$.main": false } },
{ new: true }, // an extra options parameter that returns the mutated document
(err, user) => {
if (err) {
handleErr(err)
} else {
console.log(user)
// do something with new user info
}
)

Resources