@@ -950,3 +950,197 @@ book_post_publication:
950
950
_api_resource_class: App\E ntity\B ook
951
951
_api_item_operation_name: post_publication
952
952
` ` `
953
+
954
+ # # Expose a model without any routes
955
+
956
+ Sometimes, you may want to expose a model, but want it to be used through subrequests only, and never through item or collection operations.
957
+ Because the OpenAPI standard requires at least one route to be exposed to make your models consumable, let's see how you can manage this kind
958
+ of issue.
959
+
960
+ Let's say you have the following entities in your project :
961
+
962
+ ` ` ` php
963
+ <?php
964
+ // src/Entity/Place.php
965
+
966
+ namespace App\E ntity;
967
+
968
+ use Doctrine\O RM\M apping as ORM;
969
+
970
+ /**
971
+ * @ORM\E ntity
972
+ */
973
+ class Place
974
+ {
975
+ /**
976
+ * @var int
977
+ *
978
+ * @ORM\I d
979
+ * @ORM\G eneratedValue
980
+ * @ORM\C olumn(type="integer")
981
+ */
982
+ private $id;
983
+
984
+ /**
985
+ * @var string
986
+ *
987
+ * @ORM\C olumn
988
+ */
989
+ private $name;
990
+
991
+ /**
992
+ * @var float
993
+ *
994
+ * @ORM\C olumn(type="float")
995
+ */
996
+ private $latitude;
997
+
998
+ /**
999
+ * @var float
1000
+ *
1001
+ * @ORM\C olumn(type="float")
1002
+ */
1003
+ private $longitude;
1004
+
1005
+ // ...
1006
+ }
1007
+ ` ` `
1008
+
1009
+ ` ` ` php
1010
+ <?php
1011
+ // src/Entity/Weather.php
1012
+
1013
+ namespace App\E ntity;
1014
+
1015
+ class Weather
1016
+ {
1017
+ /**
1018
+ * @var float
1019
+ */
1020
+ private $temperature;
1021
+
1022
+ /**
1023
+ * @var float
1024
+ */
1025
+ private $pressure;
1026
+
1027
+ // ...
1028
+ }
1029
+ ` ` `
1030
+
1031
+ We don't save the `Weather` entity in the database, since we want to return the weather in real time when it is queried.
1032
+ Because we want to get the weather for a known place, it is more reasonable to query it through a subresource of the `Place` entity, so let's do this :
1033
+
1034
+
1035
+ ` ` ` php
1036
+ <?php
1037
+ // src/Entity/Place.php
1038
+
1039
+ namespace App\E ntity;
1040
+
1041
+ use ApiPlatform\C ore\A nnotation\A piResource;
1042
+ use App\C ontroller\G etWeather;
1043
+ use Doctrine\O RM\M apping as ORM;
1044
+
1045
+ /**
1046
+ * @ORM\E ntity
1047
+ *
1048
+ * @ApiResource(
1049
+ * itemOperations={
1050
+ * "get",
1051
+ * "put",
1052
+ * "delete",
1053
+ * "get_weather": {
1054
+ * "method": "GET",
1055
+ * "path": "/places/{id}/weather",
1056
+ * "controller": GetWeather::class
1057
+ * }
1058
+ * }, collectionOperations={"get", "post"})
1059
+ */
1060
+ class Place
1061
+ {
1062
+ // ...
1063
+ ` ` `
1064
+
1065
+ The `GetWeather` controller fetches the weather for the given city and returns an instance of the `Weather` entity.
1066
+ This implies that API Platform has to know about this entity, so we will need to make it an API resource too :
1067
+
1068
+
1069
+ ` ` ` php
1070
+ <?php
1071
+ // src/Entity/Weather.php
1072
+
1073
+ namespace App\E ntity;
1074
+
1075
+ use ApiPlatform\C ore\A nnotation\A piResource;
1076
+
1077
+ /**
1078
+ * @ApiResource
1079
+ */
1080
+ class Weather
1081
+ {
1082
+ // ...
1083
+ ` ` `
1084
+
1085
+ This will expose the `Weather` model, but also all the default CRUD routes : ` GET` , `PUT`, `DELETE` and `POST`, which is a non-sense in our context.
1086
+ Since we are required to expose at least one route, let's expose just one :
1087
+
1088
+
1089
+ ` ` ` php
1090
+ <?php
1091
+ // src/Entity/Weather.php
1092
+
1093
+ namespace App\E ntity;
1094
+
1095
+ use ApiPlatform\C ore\A nnotation\A piResource;
1096
+
1097
+ /**
1098
+ * @ApiResource(itemOperations={
1099
+ * "get": {
1100
+ * "method": "GET",
1101
+ * "controller": SomeRandomController::class
1102
+ * }
1103
+ * })
1104
+ */
1105
+ class Weather
1106
+ {
1107
+ // ...
1108
+ ` ` `
1109
+
1110
+ This way, we expose a route that will do… nothing. Note that the controller does not even need to exist.
1111
+
1112
+ It's almost done, we have just one final issue : our fake item operation is visible in the API docs.
1113
+ To remove it, we will need to [decorate the Swagger documentation](/docs/core/swagger/#overriding-the-openapi-specification).
1114
+ Then, remove the route from the decorator :
1115
+
1116
+ ` ` ` php
1117
+ <?php
1118
+ // src/Swagger/SwaggerDecorator.php
1119
+
1120
+ namespace App\S wagger;
1121
+
1122
+ use Symfony\C omponent\S erializer\N ormalizer\N ormalizerInterface;
1123
+
1124
+ final class SwaggerDecorator implements NormalizerInterface
1125
+ {
1126
+ private $decorated;
1127
+
1128
+ public function __construct(NormalizerInterface $decorated)
1129
+ {
1130
+ $this->decorated = $decorated;
1131
+ }
1132
+
1133
+ public function normalize($object, $format = null, array $context = [])
1134
+ {
1135
+ $docs = $this->decorated->normalize($object, $format, $context);
1136
+
1137
+ // If a prefix is configured on API Platform's routes, it must appear here.
1138
+ unset($docs['paths']['/weathers/{id}']);
1139
+
1140
+ return $docs;
1141
+ }
1142
+
1143
+ // ...
1144
+ ` ` `
1145
+
1146
+ That's it : your route is gone!
0 commit comments