Symfony - Api-Platform framework: Get all items of a user - rest

I'm a young developer and I recently discover Api-Platform to make a full rest api.
Currently, I'm following the doc, but I don't understand how to get all books of a person by example.
Here I am:
I have Book and Person entities auto generated, I just add a ManyToMany relation between them.
Then I have the following results:
GET api.platform.dev/app_dev.php/
{
#context: "/app_dev.php/contexts/Entrypoint",
#id: "/app_dev.php/",
#type: "Entrypoint",
person: "/app_dev.php/people",
book: "/app_dev.php/books"
}
GET api.platform.dev/app_dev.php/people/3
{
#context: "/app_dev.php/contexts/Person",
#id: "/app_dev.php/people/3",
#type: "http://schema.org/Person",
birthDate: null,
description: "test",
gender: "Femme",
name: "test",
url: null,
books: [
"/app_dev.php/books/1",
"/app_dev.php/books/4"
]
}
Here is my questions, How can I get in the second result an hypermedia to all books of the person, and What is the best option to get all books of a person ?
I have started with create my custom operation:
#services.yml
resource.person.item_operation.custom_get:
class: "Dunglas\ApiBundle\Api\Operation\Operation"
public: false
factory:
- "#api.operation_factory"
- "createItemOperation"
arguments:
- "#resource.person" # Resource
- ["GET"] # Methods
- "/people/{id}/books" # Path
- "AppBundle:Person:custom" # Controller
- "my_custom_route2" # Route name
- # Context (will be present in Hydra documentation)
"#type": "hydra:Operation"
"hydra:title": "A custom operation"
"returns": "xmls:string"
and
// PersonController.php
<?php
namespace AppBundle\Controller;
use Dunglas\ApiBundle\Controller\ResourceController;
use Symfony\Component\HttpFoundation\Request;
class PersonController extends ResourceController
{
public function customAction(Request $request, $id)
{
return parent::getAction($request, $id);
}
}
result on GET api.platform.dev/app_dev.php/people/3/books is the same of the basic api.platform.dev/app_dev.php/people/3, normal I call the parent.
But now what is the best way to have something like this:
# GET api.platform.dev/app_dev.php/people/3/books
{
#context: "/app_dev.php/contexts/Book",
#id: "/app_dev.php/people/3/books",
#type: "hydra:PagedCollection",
hydra:totalItems: 2,
hydra:itemsPerPage: 30,
hydra:firstPage: "/app_dev.php/people/3/books",
hydra:lastPage: "/app_dev.php/people/3/books",
hydra:member: [
{
#id: "/app_dev.php/books/1",
#type: "http://schema.org/Book",
illustrator: [ ],
isbn: null,
numberOfPages: 1230,
author: [ ],
datePublished: null,
description: "Desription",
genre: null,
name: "someone",
publisher: null
},
{
#id: "/app_dev.php/books/2",
#type: "http://schema.org/Book",
illustrator: [ ],
isbn: null,
numberOfPages: 1230,
author: [ ],
datePublished: null,
description: "Desription",
genre: null,
name: "someone",
publisher: null
}
]
}
And when I get api.platform.dev/app_dev.php/people/3 add this IRI /app_dev.php/people/3/books
Thanks you for the help you could give me.

Creating sub collections like this is doable but complex with the v1 of API Platform as it requires to create a lot of custom classes (it will be easier with the v2).
What I would suggest is to use the following structure:
GET /books?people=/people/3: retrieve all books owned bu the people 3
It can be done easily using the builtin API Platform search filter.
Then, if you want hypermedia support (btw do you really need it - I mean, is your client able to dereference such hypermedia links?), you need can create a custom Symfony normalizer decorating the Dunglas\ApiBundle\JsonLd\Serializer\ItemNormalizer (service api.json_ld.normalizer.item) provided by API Platform and adding a link to /books?people=/people/3 for the books property.
If you want to still want to follow the road you started, you need to use the Dunglas\ApiBundle\Hydra\Serializer\CollectionNormalizer to normalize your collection in the Hydra format. You can still decorate the ItemNormalizer to point to your custom collection URL.
I hope this help.

Related

AWS Amplify: How custom Resolver?

I'm learning to use AWS Amplify and need some guidance.
This is my schema.graphql file content (it's the default Queries):
type Blog #model {
id: ID!
name: String!
posts: [Post] #hasMany
}
type Post #model {
id: ID!
title: String!
blog: Blog #belongsTo
comments: [Comment] #hasMany
}
type Comment #model {
id: ID!
post: Post #belongsTo
content: String!
}
After run the command: amplify push
Amplify generate automatic code in the AWS Console (eg Service AppSync):
Example 1: Schema
enter image description here
Example 2: Mutation
enter image description here
My problem is that I don't know how to customize the resolvers because AWS AWS will overwrite my code.
Example: Now there is this code:
## [Start] Initialization default values. **
$util.qr($ctx.stash.put("defaultValues", $util.defaultIfNull($ctx.stash.defaultValues, {})))
#set( $createdAt = $util.time.nowISO8601() )
$util.qr($ctx.stash.defaultValues.put("id", $util.autoId()))
$util.qr($ctx.stash.defaultValues.put("createdAt", $createdAt))
$util.qr($ctx.stash.defaultValues.put("updatedAt", $createdAt))
$util.toJson({
"version": "2018-05-29",
"payload": {}
})
## [End] Initialization default values. **
How can I do that with AWS Amplify:
## [Start] Initialization default values. **
$util.qr($ctx.stash.put("defaultValues", $util.defaultIfNull($ctx.stash.defaultValues, {})))
#set( $createdAt = $util.time.nowISO8601() )
$util.qr($ctx.stash.defaultValues.put("id", "Hello"+$util.autoId()))
$util.qr($ctx.stash.defaultValues.put("createdAt", "2022-06-13T12:43:14.047Z"))
$util.qr($ctx.stash.defaultValues.put("updatedAt", "2022-06-13T12:43:14.047Z"))
$util.toJson({
"version": "2018-05-29",
"payload": {}
})
## [End] Initialization default values. **
How can I custom Resolver without overwriting issue?
Thanks you
Solution here: Override Amplify-generated resolvers
Link: https://docs.amplify.aws/cli/graphql/custom-business-logic/#override-amplify-generated-resolvers
You should create a .vtl file in the amplify/backend/api/<resource_name>/build/resolvers/ folder

how to sync data from ydn-db web app to backend server?

With ydn-dn, i want to automatically synchronise data from my web app with my REST back end.
I read the documentation and searched in examples but i cannot make it work.
https://yathit.github.io/ydn-db/synchronization.html
http://dev.yathit.com/api/ydn/db/schema.html#sync
I tried to define a schema with sync configuration like that :
var schema = {
stores: [ {
name: 'contact',
keyPath: 'id',
Sync: {
format: 'rest',
transport: service,
Options: {
baseUri: '/'
}
}
}
]
};
and created a function for transport :
var service = function(args) {
console.log("contact synch");
};
but my service function is never called.
I certainly misunderstood how YDN-db work, but i didn't found any example.
To complete, here is a jsfiddle :
http://jsfiddle.net/asicfr/y7sL7b3j/
Please see the example http://yathit.github.io/ydndb-demo/entity-sync/app.html
Older example http://yathit.github.io/sprintly-service/playground.html from https://github.com/yathit/sprintly-service

How to access complex REST resources with ExtJS 5

I am using ExtJS 5 and I want to access complex REST resources as discussed in this similar thread using ExtJS 4.
The REST service that I am accessing exposes these resources:
GET /rest/clients - it returns a list of clients
GET /rest/users - it returns a list of all users
GET /rest/clients/{clientId}/users - it returns a list of users from the specified client.
I have these models:
Ext.define('App.model.Base', {
extend: 'Ext.data.Model',
schema: {
namespace: 'App.model'
}
});
Ext.define('App.model.Client', {
extend: 'App.model.Base',
fields: [{
name: 'name',
type: 'string'
}],
proxy: {
url: 'rest/clients',
type: 'rest'
}
});
Ext.define('App.model.User', {
extend: 'App.model.Base',
fields: [{
name: 'name',
type: 'string'
},{
name: 'clientId',
reference: 'Client'
}],
proxy: {
url: 'rest/users',
type: 'rest'
}
});
I did this:
var client = App.model.Client.load(2);
var users = client.users().load();
And it sent, respectively:
//GET rest/clients/2
//GET rest/users?filter:[{"property":"personId","value":"Person-1","exactMatch":true}]
Questions:
Is there any way that I can send my request to "GET rest/clients/2/users" without updating the user proxy url manually with its clientId?
How can I send above request without losing the original url defined in App.model.User, "rest/users"
I think this essentially the same as this question:
Accessing complex REST resources with Ext JS
I don't think much has changed since it was first asked.

Using my Rails app API for iPhone App

I'm learning iOS Development with the Treehouse Library. Building an app that gets information from a json API.
In the Treehouse API page all the posts are under a parent called "Posts" (http://blog.teamtreehouse.com/api/get_recent_summary/)
posts: [
{
id: 22198,
url: "http://blog.teamtreehouse.com/using-github-pages-to-host-your-website",
title: "Using GitHub Pages To Host Your Website",
date: "2013-08-16 09:30:20",
author: "Matt West",
thumbnail: "http://blog.teamtreehouse.com/wp-content/uploads/2013/08/github-pages-feature-150x150.jpg"
},
{
id: 22196,
url: "http://blog.teamtreehouse.com/running-tests-in-ruby-on-rails-treehouse-quick-tip",
title: "Running Tests in Ruby on Rails – Treehouse Quick Tip",
date: "2013-08-15 14:30:48",
author: "Jason Seifer",
thumbnail: null
},
The API from my Rails app doesnt have a Parent (http://www.soleresource.com/releases.json)
[
{
shoe_name: "Air Jordan 4 "Green Glow"",
release_date: "2013-08-17T00:00:00.000Z",
shoe_colorway: "Dark-Grey/Green-Glow",
shoe_price: "160",
url: "http://www.soleresource.com/releases/8.json"
},
{
shoe_name: "Nike Barkley Posite",
release_date: "2013-08-17T00:00:00.000Z",
shoe_colorway: "Gamma-Green/Black",
shoe_price: "235",
url: "http://www.soleresource.com/releases/17.json"
},
In order to get the app to work I have to call the Parent (posts), like this:
self.upcomingReleases = [dataDictionary objectForKey:#"posts"];
How can I "wrap" my API under a Parent? (My model is called "Releases")
IMHO, if you are using your rails app as a REST API, you should definitely use ActiveModel::Serializer. It will let you specify everything for your JSON responses, like metadata or roots
Here is a RailsCast for it: http://railscasts.com/episodes/409-active-model-serializers

How to implement ReST services with Sails.js?

I am quite new to Node. I came across Sails.js. I think it is based on WebSocket, which seems to be really good for building real-time applications. I would like to know that whether Sails can be used to implement REST architecture as it uses WebSocket? And if yes, how?
Yes it can. Sails JS allows you to easily build a RESTful API, essentially with no effort to get started. Also, websockets (through socket.io) are integrated by default into the view and api.
To create a fully RESTful app from the ground up, it actually requires no JS. Try:
sails new testapp
cd testapp
sails generate model user
sails generate controller user
cd <main root>
sails lift
The CRUD (Create, Read, Update, Delete) actions are already created for you. No code!
You can create a user in your browser by doing the following:
HTTP POST (using a tool like PostMan) to http://:1337/user/create
{
"firstName": "Bob",
"lastName": "Jones"
}
Next, do a GET to see the new user:
HTTP GET http://:1337/user/
FYI - Sails JS uses a default disk based database to get you going
Done.
sails new testapp
cd testapp
sails generate api apiName
controller
create: function (req, res) {
var payload = {
name:req.body.name,
price:req.body.price,
category:req.body.category,
author:req.body.author,
description:req.body.description
};
Book.create(payload).exec(function(err){
if(err){
res.status(500).json({'error':'something is not right'})
}else{
res.status(200).json({'success':true, 'result':payload, 'message':'Book Created success'})
}
});
},
readone: async function (req, res) {
var id = req.params.id;
var fff = await Book.find(id);
if(fff.length == 0){
res.status(500).json({'error':'No record found from this ID'})
}else{
res.status(200).json({'success':true, 'result':fff, 'message':'Record found'})
}
},
model
attributes: {
id: { type: 'number', autoIncrement: true },
name: { type: 'string', required: true, },
price: { type: 'number', required: true, },
category: { type: 'string', required: true, },
author: { type: 'string' },
description: { type: 'string' },
},
routes
'post /newbook': 'BookController.create',
'get /book/:id': 'BookController.readone',