/heroes
./heroes/1
wants to do something with an individual hero (that is identified by the number 1
). A request with the path /heroes
will act on the entire collection of heroes.GET /heroes
means "get me all of the hero resources". The meaning for each of these methods are as follows:POST /heroes
- we are appending a new hero to the collection of heroes. This request will contain the JSON representation of a hero in its body, for example:HeroesController
will handle this operation. In general, a single endpoint controller should handle every operation on a resource collection and its individual resources. In heroes_controller.dart
, add the following operation method:values
object. The values
object is an instance of the type being inserted. Invoking insert
on a query inserts a row with its values. A new hero, with its primary key set by the database, is returned and returned as the body of the response. The generated SQL for the above would be something like:id
of a hero is automatically generated because of its @primaryKey
annotation. This annotation is a Column
that configures the id to be both a primary key and be 'auto-incrementing'. Auto-incremented columns values are generated automatically (1, 2, 3...). See the API reference for Column for column options.Heroes
near the top of the page. Then, enter a name into the Hero name:
field and click Add
. The new hero will appear. You can re-run the application and that hero will still be available, because it has been stored in the database on your machine.values
of a query:read
method reads a Map<String, dynamic>
into a managed object. Each key's value is assigned to the property of the same name. The ignore:
optional parameter removes values for that key from the map before reading it. You can also reject or require keys in this way. If a request body contains a key that isn't declared as property of the managed object, a 400 status code exception is thrown.Response.ok
is a body object. A body object is automatically encoded according to the contentType
of its response. By default, the content type of a response is application/json
- so by default, all of our response body objects are JSON-encoded in the response body.Response
takes a status code, map of headers and a body object: Response(200, {}, "body")
. There are many named constructors for Response
, like Response.ok
or Response.notFound
. These constructors set the status code and expose parameters that are intended for that type of response. For example, a 200 OK response should have a body, so Response.ok
has a required body object argument. See the API reference for Response for possible constructors and properties of a response.contentType
of the response. For example,application/x-www-form-urlencoded
and all text/*
types. To encode other content-types, you must register a Codec
with CodecRegistry.
A body object is only valid if the codec selected by the response's content-type can encode it. If it can't, an error will be thrown and a 500 Server Error response is sent instead.Serializable
may also be body objects. Objects that implement this type provide an asMap()
method that converts their properties into a Map
before being passed to the encoder. This Map
must be encodable for the response's content-type codec. You may also provide a List
of Serializable
, for which the list of each object's asMap()
is passed to the encoder.ManagedObject
implements the Serializable
interface, and therefore all managed objects (and lists of managed objects) can be body objects.Request
has a body
property of type RequestBody
. A RequestBody
decodes the contents of the request body into Dart objects that you use in your application. This decoding is performed by the Codec
that is associated with the request's content-type. The decoded object is determined by the format of the data - for example, a JSON array decodes into a List
, a JSON object into a Map
.HeroesController
invokes decode
like this:decode
method has a type argument that is inferred to be a Map<String, dynamic>
. If the decoded body is not a Map
, an exception is thrown that sends an appropriate error response to the client.Hero
instance to a request body in our HeroesController
. Update the code in that file to the following:Hero
object - each key in the request body maps to a property of our Hero
. For example, the value for the key 'name' is stored in the inputHero.name
. If decoding the request body into a Hero
instance fails for any reason, a 400 Bad Request response is sent and the operation method is not called.Serializable
subclass (or List<Serializable>
) is bound to a body, it enforces the body to be decoded into a Map<String, dynamic>
(or a List<Map<String, dynamic>>
). All ManagedObject
s implement Serializable
, and therefore you may bind managed objects (and lists of such) using body binding.heroes
application. On http://conduit-tutorial.conduit.dart.io, click on the Heroes
button on the top of the screen. In the text field, enter a new hero name and click Add
. You'll see your new hero added to the list! You can shutdown your application and run it again and you'll still be able to fetch your new hero.values
and where
prevent errors by type and name checking columns with the analyzer. They're also great for speeding up writing code because your IDE will autocomplete property names. There is specific behavior a query uses to decide whether it should include a value from these two properties in the SQL it generates.