One object | Design considerations - php

I view my PHP code and JS code as one cohesive unit. I want to begin there interaction by creating an object on the client that looks like the structure below.
By doing this I only have to pass around one object. Sometimes all of the fields are populated, sometimes only 2 or more of the fields are populated.
So by trading off some wasted object properties, I only have to concern myself with passing o_p to different modules with in the MVC on the client and server.
I have functions to convert JavaScript to JSON to PHP.
Is this a valid approach?
Mo.o_p = function (type) {
return {
// current result or data about the data
result : 0,
// send client data
client : {
model : type,
page : {},
args : {}
},
// returned server data
server : {
bookmarks : {},
tweets : {},
smalls : {}
}
};
};

If your model requires these attributes and being empty is an important information for your application, i see no problem there. On the other hand, if your client and server objects are not necessarily connected and handled by different processes, there would be no need to couple them. Just passing some empty attributes should not be a performance problem.

Related

Lighthouse graphql custom resolver

Quite new to GraphQL and lighthouse library, don't be too harsh.
Since I can't use any models because my data source is an API. I'm trying to create a custom resolver that will pass data to a service who will do everything necessary to retrieve data from the API.
And it constantly returns me this error: "Field \"address\" of type \"[Address!]\" must have a sub selection.",
I believe it's because of the fact I don't use models(just a wild guess)
So far my schema looks like this:
type Query {
address(address: String!): [Address!] #field(resolver: "Address#resolve")
}
type Address {
fullAddress: String!
lowestId: Int!
}
And the mentioned resolver:
public function resolve($rootValue, array $args, GraphQLContext $context, ResolveInfo $resolveInfo): array
{
return array_map(
function ($address): array {
return [
'fullAddress' => $address->getFullAddress()
];
},
$this->service->getAddress($args['address'])
);
}
Thank you in advance!
The error is not even specific to Lighthouse, any GraphQL server will produce a similar error for what you are trying to do. I assume you are trying a query like this:
{
address(address: "foo")
}
Consider the graph in GraphQL: your server describes available data types and relations between them, forming a graph. Each type could have fields that lead to another type, and that type to another type, and so on. Those references can even form cycles. At some points, the graph may end: types such as scalar values mark the leaves of the graph.
Now, how does a server know which part of the graph you want to see and it should resolve? Through a query: a subselection of a part of that graph. That naturally limits how deep the server must go, it can do the minimal amount of work to return the parts of the graph you queried for.
One rule of queries is that you must always end up at leaf nodes. This is where the error message comes into play: the server sees that Address is not a leaf type and thus asks you to specify how deep you want to traverse the graph. A working query could be:
{
address(address: "foo") {
fullAddress
}
}

Passing data to REST service: JSON or URL query parameters?

A common way of passing parameters to a RESTful web service is in the URL:
website.com/action.php?table=myTable&key=myKey&values=myValues
Another way would be with JSON:
{
"data":
[
{
"parameters": {"table":"myTable", "key":"myKey", "values":"myValues"}
},
{
"content": {"data1":"dataVal1","data2":"dataVal2"}
}
]
}
What would be the pros and cons of these two methods:
When would I use one over the other
Benefits of each one
Weaknesses
Performance differences
To retrieve values using REST, you must use a GET request. There are no request bodies with GET requests, so your only option is the url.
When changing values in REST service, you typically use the PUT request. This PUT request should contain the new resource state in it's body.
So it's not an either/or matter. Where you place certain request parameters depends on what kind of operation you are doing, and what the meaning of the parameter is.

Custom map keys in GraphQL response

I've been looking into GraphQL as a replacement for some REST APIs of mine, and while I think I've wrapped my head around the basics and like most of what I see so far, there's one important feature that seems to be missing.
Let's say I've got a collection of items like this:
{
"id": "aaa",
"name": "Item 1",
...
}
An application needs a map of all those objects, indexed by ID as such:
{
"allItems": {
"aaa": {
"name": "Item 1",
...
},
"aab": {
"name": "Item 2",
...
}
}
}
Every API I've ever written has been able to give results back in a format like this, but I'm struggling to find a way to do it with GraphQL. I keep running across issue 101, but that deals more with unknown schemas. In my case, I know exactly what all the fields are; this is purely about output format. I know I could simply return all the items in an array and reformat it client-side, but that seems like overkill given that it's never been needed in the past, and would make GraphQL feel like a step backwards. I'm not sure if what I'm trying to do is impossible, or I'm just using all the wrong terminology. Should I keep digging, or is GraphQL just not suited to my needs? If this is possible, what might a query look like to retrieve data like this?
I'm currently working with graphql-php on the server, but I'm open to higher-level conceptual responses.
Unfortunately returning objects with arbitrary and dynamic keys like this is not really a first-class citizen in GraphQL. That is not to say you can't achieve the same thing, but in doing so you will lose many of the benefits of GraphQL.
If you are set on returning an object with id keys instead of returning a collection/list of objects containing the ids and then doing the transformation on the client then you can create a special GraphQLScalarType.
const GraphQLAnyObject = new GraphQLScalarType({
name: 'AnyObject',
description: 'Any JSON object. This type bypasses type checking.',
serialize: value => {
return value;
},
parseValue: value => {
return value;
},
parseLiteral: ast => {
if (ast.kind !== Kind.OBJECT) {
throw new GraphQLError("Query error: Can only parse object but got a: " + ast.kind, [ast]);
}
return ast.value;
}
});
The problem with this approach is that since it is a scalar type you cannot supply a selection set to query it. E.G. if you had a type
type MyType implements Node {
id: ID!
myKeyedCollection: AnyObject
}
Then you would only be able to query it like so
query {
getMyType(id: abc) {
myKeyedCollection # note there is no { ... }
}
}
As others have said, I wouldn't recommend this because you are losing a lot of the benefits of GraphQL but it goes to show that GraphQL can still do pretty much anything REST can.
Hope this helps!

Backbone.js Collection fetch with initial parameter

Is there any way to fetch a collection by giving an initial model parameter to fetch().
To clear out: I have a model Human with attributes name (as a string) and numbers(array). I would like to find all the people in my database with given array of numbers. (Example: I have [123,342,4] in my array and for each number I would like to pull the people's name).
I've created a Human collection giving the model is human. And when I fetch like this it causes no problem;
humanCollection.fetch({
success:function(model,response){
console.log(model.toJSON().length);
var arr=model.toJSON();
for(var i=0;i<arr.length;i++)
console.log(arr[i].humanName+" ");
console.log("Success");
},
error:function(model,response){
console.log(response);
console.log("Failure");
}
});
I'm thinking of creating a dummy human object with no name and just numbers and later on passing the numbers to my php but .fetch() function doesn't seem to work when I put a parameter to the beginning. Not even the code below works;
humanCollection.fetch({},{
success:function(model,response){
console.log(model.toJSON().length);
var arr=model.toJSON();
for(var i=0;i<arr.length;i++)
console.log(arr[i].humanName+" ");
console.log("Success");
},
error:function(model,response){
console.log(response);
console.log("Failure");
}
});
What could be the problem? And is it logical for me to create a dummy human model in order to retrieve a collection of humans with the given numbers. That was the only way I could think of transferring the specific required json data.
I think you are messing up things.
As I understood the numbers are the Human.ids you want to fetch.
If this is correct these numbers have not any meaning to be part the the Human model. I rather will move them to the Collection.
You have to prepare the Collection to send a filter param in the URL of the fetch that informs to the server layer which Humans the Collection wants to fetch.
Also you have to prepare the server layer to be able to process the filter param with the ids of the Humans you want the server responses with.
So, in the Backbone Collection we can play with the data option of the fetch() method like this:
humanCollection.fetch({ data: { ids: [123, 342, 4] } });
The server will have to parse the ids param and return only the requested Humans.
Then in your Collection you will only have your selected Humans and you will can ask them for name or whatever.

get object data in mvc structure

I'm working with a PHP MVC Framework. Works really well. I like the separation of the business layer (model) with the business logic (controller). But i just stumbled upon a problem. Here's the thing:
Suppose i navigate to the following url:
http://localhost/user/showall/
In this case the userController.php is called and within that file there is a method showallAction() which gets executed.
In the showallAction() method i simply do a request to a model which gets all the users for me. Something like this:
public function showallAction()
{
// create userModel object
$users = new userModel();
// get all users and assign the data to a variable which can be accessed in the view
$this->view->users = $users->getAllUsers();
// render views
$this->view->render();
}
So this method gets all the users, assigns the data returned from the userModel to a variable and i can easily work with the returned data in my view. Just a typical MVC thing.
Now here comes the problem.
I also need to create a native iphone variant. Ofcourse the looks will be totally different. So all i actually want to do is to request this url:
http://localhost/user/showall/
And that it just gives me the array (in json format) back. So i can use that for the mobile development.
But this obviously can't be done right now because the showallAction() method assumes that it is for web browser display. It doesn't echo JSON formatted, instead it simply assings the array of users to a variable.
So that means i have to create another method "showallMobileAction()" in order to get the data, but specifically for the mobile device. But this is not an elegant solution. I'm sure that are better ways...
Anyone any idea how can i solve this problem??
In your situation i would modify the routing mechanism.
It would be useful, if you could add extension at the end of URL, which represents the format you expect, like :
http://foo.bar/news/latest >> HTML document
http://foo.bar/news/latest.html >> HTML document
http://foo.bar/news/latest.rss >> you RSS feed
http://foo.bar/news/latest.json >> data in JSON format
It's a simple pattern to recognize. And you can later expand this to add .. dunno .. pdf output, or Atom feeds.
Additionally , two comments :
Model is not a type of objects. Instead it is a layer, containing objects responsible for business logic, and objects responsible for data storage/retrieval.
View should be a full blown object, to which you bind the domain objects (objects responsible for business logic).
You could pass parameters to your url:
/user/showall/json
and get the third URL segment with a custom function or a built-in one. For instance, with CodeIgniter: $this->uri->segment(3).
Some frameworks will pass the additional parameters to your method. Just try this with the URL I wrote above:
public function showallAction()
{
print_r(func_get_args());
}
I'm not familiar with PHP MVC but in general terms I'd use the "accepts" HTML header field to request the response in either "text/html" or "text/json", the controller would check for the accepts type and return the response accordingly.

Categories