Giter VIP home page Giter VIP logo

core's Introduction

API Platform Core

API Platform Core is an easy-to-use and powerful system to create hypermedia-driven REST and GraphQL APIs. It is a component of the API Platform framework and it can be integrated with the Symfony framework using the bundle distributed with the library.

It natively supports popular open formats including JSON for Linked Data (JSON-LD), Hydra Core Vocabulary, OpenAPI v2 (formerly Swagger) and v3, JSON:API, HAL and Problem Details.

Build a working and fully-featured web API in minutes. Leverage the awesome features of the tool to develop complex and high-performance API-first projects. Extend or override everything you want.

GitHub Actions

Documentation

The documentation of API Platform Core Library can be browsed on the official website.

core's People

Contributors

aaa2000 avatar alanpoulain avatar antograssiot avatar arnoudthibaut avatar bendavies avatar chalasr avatar dannyvw avatar dunglas avatar gregoirehebert avatar guilhemn avatar guilliamxavier avatar gwendolenlynch avatar jdeniau avatar jocel1 avatar jotwea avatar julienfalque avatar lyrixx avatar meyerbaptiste avatar nightbr avatar norkunas avatar ocramius avatar silverbackdan avatar simperfit avatar soyuka avatar sroze avatar teohhanhui avatar theofidry avatar toflar avatar vincentchalamon avatar zowac avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

core's Issues

How to manage i18n resource with API / JSON-LD / Hydra ?

Imagine you have a "Country" (http://schema.org/Country) resource in your API.
How to manage i18N on it ?

Here is a detailed solution, i have design based on experience, and the JSON-LD spec.
Tell me if you think this is a good idea ?
If you think it's not ... tell me why ?

How to get a specific locale on a resource ? (=GET)

My solution

Add a GET specific parameter "locale"
Why ?

  • Simple (this is the way used in FB graph api for example)
  • One URL = One localized resource (like wikipedia, better for indexing or caching)
  • use of @language specified in JSON-LD spec
  • use @container:@language

Sample 1 : No locale specified

GET http://api.example.com/countries/1

{
  "@context": {
    "@base" : "http://schema.org",
    "name" : {
      "@container": "@language"
    }
  },
  "@type": "Country",
  "@id": "/countries/1",
  "name": {
    "fr-FR" : "Angleterre",
    "en" : "England"
  }
}

=> Will return resource with all locale data

Sample 2 : Use specific localization

GET http://api.example.com/countries/1?locale=fr-FR

{
  "@context": "http://schema.org",
  "@type": "Country",
  "@id": "/countries/1",
  "@language": "fr-FR",
  "name": "Angleterre"
}

=> Will return resource with requested locale

Note we use locale (on request + response) in W3C format (IETF's BCP 47), see http://www.w3.org/International/articles/language-tags/
It's the format used also with JSON-LD.

Sample 3 : Error localization don't exist

GET http://api.example.com/countries/1?locale=es-CA

{
  "@context": "/contexts/LocalizationError",
  "@type": "LocalizationError",
  "hydra:title": "An error occurred",
  "hydra:description": "no localization found for locale es-CA"
}

=> Will return code "404 not found", because es-CA localization don't exist in my api.

How to get a specific locale on a list of resource ? (=GET)

My solution :

same as for one resource

Sample 1 : No locale specified

GET http://api.example.com/countries

{
  "@context": {
    "@base" : "http://schema.org",
    "name" : {
      "@container": "@language"
    }
  },
  "@id": "/countries",
  "@type": "hydra:PagedCollection",
  "hydra:totalItems": 1,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": [
    {
      "@type": "Country",
      "@id": "/countries/1",
      "name": {
        "fr-FR" : "Angleterre",
        "en" : "England"
      }
    }
  ]
}

=> Will return resources with all available localization

Sample 2 : Use specific localization

GET http://api.example.com/countries?locale=fr-FR

{
  "@context": "http://schema.org",
  "@id": "/countries",
  "@type": "hydra:PagedCollection",
  "@language": "fr-FR",
  "hydra:totalItems": 1,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": [
    {
      "@type": "Country",
      "@id": "/countries/1",
      "name": "Angleterre"
    }
  ]
}

=> Will return resource with requested locale

Sample 3 : Error localization don't exist

GET http://api.example.com/countries?locale=es-CA

{
  "@context": "http://schema.org",
  "@id": "/countries",
  "@type": "hydra:PagedCollection",
  "@language": "es-CA",
  "hydra:totalItems": 0,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": []
}

How to delete a localized resource ? (=DELETE)

My solution :

same as usual but the localization are also deleted completely

DELETE http://api.example.com/countries/1
=> Will delete country and all associed localization

DELETE http://api.example.com/countries/1?locale=fr-FR
=> Will delete country localization fr-FR only !

How to create a localized resource ? (POST)

My solution :

create with a locale container or indicate the language in context

POST http://api.example.com/countries

{
    "name": {
        "fr-FR" : "Angleterre",
        "en": "England"
    }
}

=> Will create country with two localized value

OR

POST http://api.example.com/countries

{
    "@context": {
        "@language": "fr-FR"
    },
    "name": "Angleterre"
}

=> Will create country with one localized value

How to add a new locale to a localized resource ? (PUT)

My solution :

same as POST, you must specified @language or put all localized data

PUT http://api.example.com/countries/1

{
    "@context" : {
        "@language": "it"
    },
    "name": "Inghilterra"
}

=> Will add or replace locale "it" name for the resource /countries/1

PUT http://api.example.com/countries/1

{
    "name": {
        "fr" : "Angleterre"
    }
}

=> Will delete all localization for name and just have fr localization

How to list all available locale for a resource ?

My solution :

add a specific endpoint to api like :

GET http://api.example.com/countries/1/locales

{
  "@context": "http://schema.org",
  "@id": "/http://api.example.com/countries/1/locales",
  "@type": "hydra:PagedCollection",
  "hydra:totalItems": 2,
  "hydra:itemsPerPage": 3,
  "hydra:firstPage": "/countries",
  "hydra:lastPage": "/countries",
  "hydra:member": [
    {
      "@type": "Locale",
      "@id": "/locale/fr"
    },
    {
      "@type": "Locale",
      "@id": "/locale/en"
    }
  ]
}

=> Will return all available locale for the resource

For the "dev" part :

  • create specific normalizer/denormalizer to manage @language in JSON-LD
  • implements an Interface : LocalizedEntity
  • Create a LocalizedResourceController to manage ?locale param and /locales endpoint

FindOne endpoint

The current filters on collections allow to search for entities matching a given criteria. But sometimes we don't want to find entities, but the first entity matching a criteria. The easiest way to achieve that would be to add an endpoint /offers/findOne?criteria. So basically an endpoint on which the filters enabled for the collection are enabled too, but which returns the first entity found, pretty much like we did /offers?criteria and then retrieved hydra:member[0].

Do you think this could be added or do you deem it too specific?

Fix filters descriptions

At the moment only the filter description (hydra:search) of the search filter is well implemented. For the order filter and date filter the description is lacking or invalid.

Using an alternative ID

When using two "IDs": one is the real ID for the database and the other is the ID exposed to the API, for example with an entity User for which the database ID is id and the "API ID" is username, the DataProvider should be extendable or have the necessary operations to avoid any dumb copy/paste.

Feature request - custom pagination

As of now it is possible to customize the number of items per page at a global level on the API side with the option items_per_page.

But the number of items per page is a parameter you may wish to change for some entities on the API side and sometimes let the client adjust it to his need.

To cover most of the use case without having to override a DataProvider a defining a custom Paginator, tit should be possible to configure the following with some parameters in the config:

  1. Configure the items_per_page on a global basis on the API side (already possible)
  2. Configure the items_per_page on a resource basis on the API side
  3. Enable the possibility for the client to change the default page size for all resources
  4. Enable the possibility for the client to change the default page size on a resource basis

Suggestion of configuration

Feature 1

Keep it as it is.

Feature 2

services:
    resource.dummy:
        parent:    "api.resource"
        arguments: [ "AppBundle\Entity\Dummy" ]
        calls:
            -      method:    "setPagination"
                   arguments: 50

And in this case, regardless of the value of items_per_page in the config.yml, this pagination for Dummy will be at 50.

Feature 3

Since it's for all the resources it seem logical to define it in the config.yml:

dunglas_api:
    title:              "Your API name"
    description:        "The full description of your API"
    default:
        items_per_page:
            default_value:     30
            client_pagination: true # Default to false
        order:          ~

Maybe adding which values we allow for the pagination via a request would be nice too. If you deem it too specific then letting the user extending the paginator to achieve that is fine.

Feature 4

services:
    resource.dummy:
        parent:    "api.resource"
        arguments: [ "AppBundle\Entity\Dummy" ]
        calls:
            -      method:    "enableClientPagination"
                   arguments: [10, 50, 100, 200] # valid values, if no value provided all value is accepted.

Syntax

Syntax proposal for the custom pagination on the client side:

url?itemsPerPage=value

Relations missing in generated API Doc using NelmioAPIDocBundle

I have an entity which has a ManyToMany relation to another entity:

/**
 * This object represents an unit. Units can be: Volt, Hertz etc. 
 *  
 * @ORM\Entity
 * @TargetService(uri="/unit")
 * @ExclusionPolicy("none")
 **/
class Unit extends BaseEntity {
    /**
     * The name of the unit (e.g. Volts, Ampere, Farad, Metres)
     * @ORM\Column(type="string")
     * @Type("string")
     *
     * @var string
     */
    private $name;

    /**
     * The symbol of the unit (e.g. V, A, F, m)
     * @ORM\Column(type="string")
     * @Type("string")
     * @var string
     */
    private $symbol;

    /**
     * Defines the allowed SiPrefixes for this parameter unit
     * @ORM\ManyToMany(targetEntity="PartKeepr\SiPrefixBundle\Entity\SiPrefix")
     * @ORM\JoinTable(name="UnitSiPrefixes",
     *          joinColumns={@ORM\JoinColumn(name="unit_id", referencedColumnName="id")},
     *          inverseJoinColumns={@ORM\JoinColumn(name="siprefix_id", referencedColumnName="id")}
     *          )
     * @Type("ArrayCollection<PartKeepr\SiPrefixBundle\Entity\SiPrefix>")
     * @var ArrayCollection
     */
    private $prefixes;

However, the generated doc using NelmioAPIDocBundle doesn't include that relation as input:

2015-06-10-203318_920x452_scrot

I'm not sure if this is an issue of the NelmioAPIDocBundle or this bundle and if this is supported at all.

Invalid syntax

The following syntax is considered as a malformed YAML:

# app/config/services.yml

services:
    resource.offer.search_filter:
        parent:    "api.doctrine.orm.search_filter"
        arguments: [ {
                        "id": "exact",    # Filters on the id property, allow both numeric values and IRIs
                        "price": "exact", # Extracts all collection elements with the exact given price
                        "name": "partial" # Elements with given text in their name
                   } ]

In Adding Doctrine ORM fitlers.

A valid one would be:

# app/config/services.yml

services:
    resource.offer.search_filter:
        parent:    "api.doctrine.orm.search_filter"
        arguments: [ { id: "exact", price: "exact", name: "partial"  } ]

And for very long ones or when we wished to put some comments:

# app/config/services.yml

services:
    resource.offer.search_filter:
        parent:    "api.doctrine.orm.search_filter"
        arguments:
            -
                   id:    "exact"      # Filters on the id property, allow both numeric values and IRIs
                   price: "exact"      # Extracts all collection elements with the exact given price
                   name:  "partial"    # Elements with given text in their name

extendable DataProvider

Would it be possible to make the properties and functions of DataProvider protected instead of private or it has been made so on purpose?

Fos User and Post Data

Hello,

Sorry for my english, I'm French ....

After configuring and FOS FOS BUNDLE USER AUTH USER. I have no problem with but with a GET on HOST POST / api / books for example , I have this error:

hydra:description": "Catchable Fatal Error: Argument 1 passed to Dunglas\\ApiBundle\\FosUser\\EventSubscriber::__construct() must implement interface Symfony\\Component\\EventDispatcher\\EventDispatcherInterface, none given, called in /var/www/local.dev/XXXX/api-platform/app/cache/prod/appProdProjectContainer.php on line 331 and defined"

thank you for your answers

Extend usage of name converter

Actualy name converter is used in (de)normalization of the object.
But it should also be used in several locations:

  • In violation's propertyPath
"violations": [
        {
            "message": "This value should not be blank.", 
            "propertyPath": "content" <== here
        }
    ]
  • In filters => http://localhost:8000/api/offers?price=10 price should be denormalized
  • or in /offers?order[name]=desc&order[id]=asc.

Filters names conversion

As existing filters are based on properties, when using a name converter, it feels odd to have properties and filters named differently.
That's why I'd like to use the name converter for filters too.

The straightforward solution is to inject the name converter, if configured, in each filters (I think we won't inject it in the AbstractFilter, as custom filters might no be based on a property, therefore, might not need conversion).
Injecting the converter is what we are already doing in ItemNormalizer for instance.

But, another solution came to my mind:

  • Create a new convertedName (or any better name) property in AttributeMetadata
  • Inject the name converter in the AttributeLoader and populate the new property with the converted name using the converter.
  • Inject the ClassMetadataFactory in AbstractFilter and provide a getMappingMetadata method.
  • Use those metadata in each filter in order to retrieve the converted name whenever it is needed (documentation and query parameters from request).

The drawback is that we need to maintain both mappingMetadata from ClassMetadataFactory and doctrine metadata in the current filters. In such cases, we need to loop over the mappingMetadata to find the matching doctrine property and the proper convertedName.

The benefits are that we won't need to inject the name converter anymore, as the api.mapping.class_metadata_factory is used instead.
For what it is worth, the conversion is also done only once. Custom filters are free to use metadata or not.

Do you see anything wrong with this approach ? Do you have any suggestion ?

TOC for doc

The documentation is becoming quite long so a TOC would be very much appreciated regardeless if the doc is planned to be move elsewhere later!

Serialization with FOSUser

I'm using the FOSUserBundle with my User entity. I wish to hide some properties of the User entity, for example the password and the plainPassword. However, I still need to be able to use the plainPassword property in the PUT or POST to set or update the password of the user.

Here's the configuration:

<?php
// src/AppBundle/Entity/User.php

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Entity\User as FosUser;
use Symfony\Component\Serializer\Annotation\Groups;

/**
 * User.
 *
 * @ORM\Entity
 */
class User extends FosUser
{
    /**
     * @var int
     *
     * @ORM\Column(type = "integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy = "AUTO")
     * @Groups({"user"})
     */
    protected $id;

    /**
     * @var string
     *
     * @Groups({"user"})
     */
    protected $email;

    /**
     * @var string
     *
     * @ORM\Column(type = "string", length = 45)
     * @Groups({"user"})
     */
    private $username;

    /**
     * @var string
     *
     * @Groups({"password"})
     */
    protected $plainPassword;

    public function __construct()
    {
        parent::__construct();
    }
}
# app/config/services.yml
resource.user:
    parent:    api.resource
    arguments: [ AppBundle\Entity\User ]
    calls:
        -      [ initNormalizationContext, [ { groups: [ user ] } ] ]
        -      [ initDenormalizationContext, [ { groups: [ password, user ] } ] ]
    tags:      [ { name: api.resource } ]

When I GET an entity or a collection, the properties are hidden as expected. However the POST fails stating the column password cannot be null.

Have you any idea on what may be the problem?

initSerializationContext

In the README.md, the property initSerializationContext, which does not exists is used instead of initNormalizationContext.

Add recommendation for custom filters

More like guidelines for custom filters:

  • keep in mind the queryBuilder parameters conflict
  • never use setParameters instead of setParameter as it will wipe out all previous parameters

I do not know if it has really its place here though.

Introduce a @Depth annotation

When serializing trees with groups such as the following, it is convenient to be able to configure the Serialization depth:

class TreeEntry
{
    /**
      * @var TreeEntry
      * @Groups{"a"}
      */
    public $parent;
}

A new @Depth(n) where N is the maximum depth level to normalize can be useful for such use case. When n is reached, the normalizer will output the IRI of the resource instead of embedding it. Proposal:

class TreeEntry
{
    /**
      * @var TreeEntry
      * @Groups{"a"}
      * @Depth(2)
      */
    public $parent;
}

How to create nested objects on the fly?

I have started developing a demo app for DunglasApiBundle. I tried to deserialize a new User with a new Group:

POST api/users

{"_format": "json",
"groups": [{
"name":"newgroup"
}],
"name": "test12311"
}

I have configured serialization groups, however, I'm receiving the following error:

hydra:title: "An error occurred"
hydra:description: "Nested objects for attribute "groups" of "AppBundle\Entity\User" are not enabled. Use serialization groups to change that behavior."

Here's my entity: https://github.com/felicitus/DunglasApiBundleDemo/blob/master/src/AppBundle/Entity/User.php

Invalid property for filter behavior

As of now, if we filter a collection on a not enabled property, the collection will be returned as a whole as if no filter is given. bIMO it is error prone in a sense that you have no way to tell there is an error occurred unless you take a look at the result.

Would it be possible to change that or it's a desired behavior?

Add support for Doctrine ORM filters on embedded relation

As seen with @dunglas it would be great to enable filters on embedded relations.

Exemple:

services:
    resource.dummy.search_filter:
        parent: api.doctrine.orm.search_filter
        arguments:
            -
                dummyRelation.slug: exact # enable to use search filter on slug property of the target entity

And then to use the search filter on it: ?dummyRelation.slug=value.

The same way for the date and order filter:

  • ?dummyRelation.dummyDate[before]=value
  • ?order[dummyRelation.dummyDate]=asc

Filters refactoring and extendability

As of now we have three native filters:

  • search filter: ?property=value
  • order filter: ?order[property]=<asc|desc>
  • date filter: ?property[<before|after>]=value

In the process we added the Dunglas\ApiBundle\Doctrine\Orm\AbstractFilter class to do some refactoring. Still, as discussed, there still some redundancy and maybe more logic could be moved into the AbstractFilter.

Besides the main issue one could meet with those filter is:

  • The need to change the syntax, for instance to have an API more StrongLoop like: filter[where][property][op]=value&filter[order][property]=<asc|desc>
  • The need to change the behaviour of a filter: for instance extending the search filter to handle special format for dates values or to look for null values.

To do so, we could try to keep the same pattern used in Dunglas\ApiBundle\Doctrine\Orm\OrderFilter which is dividing the Filter::apply() method in two: Filter::apply() and Filter::applyFilter(). The later would take an array of values and implement the behavior of the filter while the first would retrieve the values and pass them to the second method. Another way would be as you suggested to use a Closure to do so. The gist of it is to provide a way to easily extend a filter to tackle one of the two issue mentioned above.

Other notes:

  • make properties protected or add a getter otherwise requires to redeclare it when overriding getDescription

Filters logging

It would be great to have some tools to ease the development and debug of filters, for starter:

  • list all filters
  • get which filters are enabled for a given resource
  • for a given URI, which filters are applied, output of the DQL query if using Doctrine?
  • logs in the profiler with detailed view of which filter is being used, applied and what it has done

I guess it won't be a priority but I still find it worth being mentioned.

Embedded relations

As explaiend here, given we have a relation between User and Job, it is possible to display the properties of Job when getting the properties of User, which gives the following result:

{
    "@context": "/api/contexts/User",
    "@id": "/api/users/1",
    "@type": "User",
    "username": "John Doe",
    "email": "[email protected]",
    "roles": [
        "ROLE_USER"
    ],
    "jobs": [
        {
            "@id": "/api/jobs/101",
            "@type": "Job",
            "title": "President",
            "abbreviation": "PR",
            "mandate": "/api/mandates/12"
        }
    ]
}

Now as you can see with the JSON above, I also have a relation between Job and Mandate. If I use the same pattern (adding a serialization group to Mandate, I get the following result:

{
    "@context": "/api/contexts/User",
    "@id": "/api/users/1",
    "@type": "User",
    "username": "John Doe",
    "email": "[email protected]",
    "roles": [
        "ROLE_USER"
    ],
    "jobs": [
        {
            "@id": "/api/jobs/101",
            "@type": "Job",
            "title": "President",
            "abbreviation": "PR",
            "mandate": {
                "@id": "/api/mandates/12",
                "@type": "Mandate",
                "startAt": "2016-03-14T20:34:19+01:00",
                "endAt": "2016-08-03T10:53:22+02:00",
                "jobs": [
                    "/api/jobs/32",
                    "/api/jobs/96",
                    "/api/jobs/99",
                    "/api/jobs/100",
                    "/api/jobs/101"
                ]
            }
        }
    ]
}

Regardless on which attribute I putted the serialization group (for ex: in this case I added it on startAt.

In other words, the serialization group does work for this case but completly ignore which attributes we wish to expose for the embed relation of the embed relation.

Nitpicking - style

In extract of Yaml code (ex: disabling-operations), you indent the code as the following:

services:
    resource.product.collection_operation.get:
        class:                                 "Dunglas\JsonLdApiBundle\Api\Operation\Operation"
        public:                                false
        factory:                               [ "@api.operation_factory", "createItemOperation" ]
        arguments:                             [ "@resource.product", "GET" ]

    resource.product:
        parent:                                "api.resource"
        arguments:                             [ "AppBundle\Entity\Product" ]
            -                                  [ "addCollectionOperation", [ "@resource.product.collection_operation.get" ] ]
        tags:                                  [ { name: "api.resource" } ]

While the result is clean and pretty, the space between the key and the value is far too big and result in two things:

  • If you have a column not wide enough (on a mobile or simply in our case the width of the readme), you have to scroll to see the actual value.
  • If you are a little bit dyslexic, it is completely unreadable.

Maybe keeping the indentation as follow would be a better although less pretty (at least IMO):

services:
    resource.product.collection_operation.get:
        class:     "Dunglas\JsonLdApiBundle\Api\Operation\Operation"
        public:    false
        factory:   [ "@api.operation_factory", "createItemOperation" ]
        arguments: [ "@resource.product", "GET" ]

    resource.product:
        parent:    "api.resource"
        arguments: [ "AppBundle\Entity\Product" ]
            -      [ "addCollectionOperation", [ "@resource.product.collection_operation.get" ] ]
        tags:      [ { name: "api.resource" } ]

And maybe remove unnecessary ":

services:
    resource.product.collection_operation.get:
        class:     Dunglas\JsonLdApiBundle\Api\Operation\Operation
        public:    false
        factory:   [ @api.operation_factory, createItemOperation ]
        arguments: [ @resource.product, GET ]

    resource.product:
        parent:    api.resource
        arguments: [ AppBundle\Entity\Product ]
            -      [ addCollectionOperation, [ @resource.product.collection_operation.get ] ]
        tags:      [ { name: api.resource } ]

Or does it causes any error?

Handling circular references with a custom normalizer

Given an entity with has a relation with itself, for instance via the attributes parent and children, the circular reference is not handled.

I'm not sure if it should be handled natively or not, but if not then I guess we should use a custom normalizer to handle it. In this case there is three problems:

  • first, the declaration is quite heavy: since the @api.json_ld.normalizer.item requires lots of arguments. While I'm not really against it, since if we require multiple normalizer for such use case, we can declare an abstract one to lighten the declaration. If you prefer that rather than declaring the abstract normalizer in your bundle, I believe this could be added in the doc.
  • second: while declaring our own normalizer, we have no choice but to copy/paste the whole normalizer and add our conditional statements to handle the special attributes. It's kind of a pain and I wanted to know if you have any recommendation regarding that.
  • third: it is currently not possible to use a custom normalizer since some services are lazy loaded and an error is returned because the class of the proxy object does not match the expected class

In both cases it may be a use case frequent enough to deserve a chapter in the doc. What do you think?

cc/ @Pyrex-FWI

NelmioAPIDocBundle doesn't allow me to specify IDs

When I have a relation, I can't specify the ID of the new group in the sandbox of NelmioAPIDocBundle:

nelmio

When I try to put ["@id":"/~felicitus/DunglasApiBundleDemo/web/app_dev.php/api/groups/1"] into the groups field, the resulting JSON is:

groups: "["@id":"/~felicitus/DunglasApiBundleDemo/web/app_dev.php/api/groups/1"]"

when it should be:

groups: ["@id":"/~felicitus/DunglasApiBundleDemo/web/app_dev.php/api/groups/1"]

I have no idea if the issue is caused by DunglasAPIBundle or NelmioAPIDocBundle. The best would be for NelmioAPIDocBundle to recognize that we expect an array here, and support adding array elements to there.

Additionally, this bundle returns an internal server error when attempting to post the quoted groups parameter:

{
  "@context": "/~felicitus/DunglasApiBundleDemo/web/app_dev.php/api/contexts/Error",
  "@type": "Error",
  "hydra:title": "An error occurred",
  "hydra:description": "Warning: Invalid argument supplied for foreach()",
  "trace": [
    {
      "file": "/home/felicitus/repos/DunglasApiBundleDemo/vendor/dunglas/api-bundle/JsonLd/Serializer/ItemNormalizer.php",
      "line": 247,
      "function": "handleError",
      "class": "Symfony\\Component\\Debug\\ErrorHandler",
      "type": "->",
      "args": [
        2,
        "Invalid argument supplied for foreach()",
        "/home/felicitus/repos/DunglasApiBundleDemo/vendor/dunglas/api-bundle/JsonLd/Serializer/ItemNormalizer.php",
        247,
        {
          "data": {
            "_format": "json",
            "name": "dsfsadf",
            "groups": "[\"@id\":\"/~felicitus/DunglasApiBundleDemo/web/app_dev.php/api/groups/1\"]"
          },
          "class": "AppBundle\\Entity\\Group",
          "format": "json-ld",
          "context": {
            "0": {
              "groups": [
                "user"
              ]
            },
            "resource": {}
          },

(skipped rest of the backtrace)
}

Cannot register custom resource class

The sample doesn't work.

In ResourcePass.php => all tagged element with "api.resource" are added to resource_collection (OK :) )
But method call "addItemOperation" and "addCollectionOperation" are added on custom resource wich not implements these method (ResourceInterface not required them)

So, maybe add a check that the new resource implements default resource ?
Or maybe add options to yml to filter default operation (for having a more simple definition) like :

resource.locale:
    class:     "MyBundle\MyCustomResource"
    buildItemOperations: ["GET"]
    buildItemCollectionOperations : ["GET", "POST"] 
    tags:      [ { name: "api.resource" } ]

what do you think ?

0.1.0 release

The goal is to release a 0.1.0 version when Symfony 2.7 will be out.

What do you think @sroze?

Using a custom controller

Overriding a method of the controller is easy as it's just requires to extend the ResourceController. However in the case we wish to add a new action to the controller, for example countAction, to get the API endpoint GET /collection/count; It would be possible to add our route manually in our routing file, but then our rout would not "inherit" the prefixes that it would get if it were declared directly in the parent controller ResourceController. Is there a way to that in a more elegant manner?

Error when i'm trying to install bundle

Hello,

I have this error, do you have an idea?

CRITICAL - Fatal Parse Error: syntax error, unexpected 'finally' (T_STRING), expecting catch (T_CATCH)
CRITICAL - Uncaught PHP Exception Symfony\Component\Debug\Exception\FatalErrorException: "Parse Error: syntax error, unexpected 'finally' (T_STRING), expecting catch (T_CATCH)" at /vendor/dunglas/api-bundle/Routing/Router.php line 75

Thanks!

Changelog

I know this is in a heavy development state but I'd be nice to have a changelog instead of reading the commits :).

Controller doc

The 10th place for the Controller chapter seems a bit far. And there is a little error with the link of the previous chapter for the Controller.

PUT my object user (Fos user) not work

Hello,
When I made โ€‹โ€‹a PUT request on my user id identified with FOS Oauth SERVER BUNDLE and FOS USER , I am instead a POST because it does not retrieve the user object.

If I want to update the User object different from mine , no problem

Here the User with id 3 with the token that begins with MWQ1 ....

PUT on api/v1/users/ 2 it's work
PUT on api/v1/users/ 3 not work

capture d ecran 2015-05-08 a 11 54 18
capture d ecran 2015-05-08 a 11 54 41

Here the User with id 2 with the token that begins with NTU1 ....

PUT on api/v1/users/3 it's work
PUT on api/v1/users/2 not work

capture d ecran 2015-05-08 a 11 55 37
capture d ecran 2015-05-08 a 11 55 19

In Dunglas\ApiBundle\FosUser\EventSubscriber.php

public function updateObject(ObjectEvent $event)
    {
        $object = $event->getObject();
        if ($object instanceof UserInterface) {
            $this->userManager->updateUser($object);
            $this->eventDispatcher->dispatch(Events::POST_UPDATE, $event);
            $event->stopPropagation();
        }
    }

$object is null for the user who wants to change their own user object but correct for the user object of another user..

I do not know if I explained the problem ...

Blump

Developement version tags

Could it be possible to tag the following commits:

  • 059a86a: at that time there was only the SearchFilter and we had to extend the DataProvider for adding custom filters. Not particularly useful but would for everyone but still more practical for our project.
  • 4a077ea: was before refactoring the filters, since there is a lot of BC breaks, it would also help to us and be more convenient
  • a release for after the refactoring of the filters

Of course since the bundle is still in development, the tags could be 0.X which is well handled by Composer.

Feature request - Extended date filter

When using dates, we rarely need filter a collection which has the given date but rather filter by period: before or after a date or between two dates.

Syntax

Taking into account the change in the way we expose URL as mentioned in the PR #43, we could use the following syntax:

url?filter[date][propertyName][after]=value
url?filter[date][propertyName][after]=value

Where value is a format understandable for the instantiate a \DateTime from it.

Adding support for the year

Sometimes you don't want to look for a specific date but just want to give a year:

url?filter[date][createdAt][after]=2005&filter[date][updatedAt][before]=2015

Will filter the collection to expose only the items with a createdAt date superior or equal to 2006-01-01 and a updatedAt date value inferior or equal to 2014-12-32.

If we do so maybe adding a support for the month would make sense too.

Edit: Adding a support for the month would be logical if we add one for the year, but IMO it would be too much and lead to confusion regarding the format and the use case is specific/rare enough to let the one to add his own filter.

Serialization group problem

I'm a little stuck and I really don't get what's wrong in my config.

I installed a dunglas/api-platform project with FOSUserBundle. I declared my own User, which extends the FOSUserBundle entity, as a resource to expose it to my API. So far so good, if I request GET /api/users I get the expected result.

Now I add use Symfony\Component\Serializer\Annotation\Groups; to my Entity class and use the annotation @Groups({"user"}) to properties I which to expose to my API. The properties are properly redeclared as protected. Then in my service.yml I add:

calls:
    - [ "initNormalizationContext", [ { groups: [ "user" ] } ] ]

But the result is that no properties are exposed, I only get the @id and @type properties.

Any idea from where the error may come from?

FOSUserBundle

Although the FOSUserBundle integration is pretty simple, there is no mention of it in the doc. Could it be added?

Adding one custom operation without loosing the default ones

Because of this line if the resource already has one operation (in my example the custom one added), it won't add the default GET, PUT, DELETE operations.

I know this is a nice behavior when it comes to add only the resources you want (like no POST in the collection from the readme) but when adding one resources it's bringing extra lines of code to get back the normal behavior.

What about adding a parameter inside the resource that is beeing checked by the DI compilation to avoid loosing default routes?

P.S.: Sorry for beeing a lazy guy \o/

Search filter for null values

One request often made when filtering a collection by values is the case of the null value. Sadly this is a very painful case because the value retrieved on the server side is always a string and that it's no possible with the current implementation to pass an empty value.

Unfortunately I didn't find much on the subject aside from this post which suggest a "hacky" solution: defining custom values.

I tested a little bit with a StrongLoop application and the following query ?filter[where][property]=null works whatever the type of the value is.

The only problem is for string values. Indeed it becomes impossible to search for a string with the value "null".

@dunglas, @sroze what are your though on this case? Should we do as StrongLoop which has the drawback of disabling the search filter for string properties of value "null"?

Broken link

The link in the TOC for returning a page collection is broken (I guess it's the R of Request which broke the link, should be `r' instead).

Rename the bundle

As the core of the bundle is now independent of JSON-LD and Hydra (it's possible to add HAL or any other serialization format support), what do you think about renaming the bundle "ApiBundle"?

Search for empty values

At first I added this in #70 but I moved it here since it's a different problem although related.

So to sum it up another use case which might happen quite often is to look for "empty" values. I quote the word "empty" since its meaning is a little bit ambigus. Indeed in PHP a value is empty if undefined, null or a value equivalent to false. For this case I'm talking refering to a value equivalent to false which is not null.

As seen with StrongLoop test in #70, to search for empty value: ?filter[where][property] or ?filter[where][property]=

Values matching the criteria for each types, nothing surprising of course:

  • string: ""
  • number: 0
  • date: throw an error Invalid date
  • boolean: false

As of now, ?property or ?property= is silently ignored from our filters. Would it be possible to change this to look for an empty value instead?

Disabling operations causes circular reference

I believe there is some issues with the current doc of disabling operations:

  • missing calls key:
resource.product:
    parent:    "api.resource"
    arguments: [ "AppBundle\Entity\Product" ]
    calls: # is missing
        -      [ "initCollectionOperations", [ [ "@resource.product.collection_operation.get" ] ] ]
    tags:      [ { name: "api.resource" } ]
  • since the @resource.product service is registered in @resource.product.collection_operation.get and vice-versa it causes a circular reference.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.