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