# Field Writability
By default, fields are read-only. You can allow a field to be written to in PATCH and POST requests using the writable and readonly methods.
You can optionally supply a closure to these methods which will receive the model instance, and should return a boolean value.
For example, the following schema will make an email attribute that is only writable by the self:
$type->attribute('email')
->writable(function ($model, Context $context) {
return $model->id === $context->getRequest()->getAttribute('userId');
});
# Writable Once
You may want a field to only be writable when creating a new resource, but not when an existing resource is being updated. This can be achieved by calling the once method:
$type->hasOne('author')
->writable()->once();
# Default Values
You can provide a default value to be used when creating a new resource if there is no value provided by the consumer. Pass a value or a closure to the default method:
$type->attribute('joinedAt')
->default(new DateTime);
$type->attribute('ipAddress')
->default(function (Context $context) {
return $context->getRequest()->getServerParams()['REMOTE_ADDR'] ?? null;
});
TIP
If you're using Eloquent, you could also define default attribute values (opens new window) to achieve a similar thing. However, the Request instance will not be available in this context.
# Validation
You can ensure that data provided for a field is valid before the resource is saved. Provide a closure to the validate method, and call the first argument if validation fails:
$type->attribute('email')
->validate(function (callable $fail, $value, $model, Context $context) {
if (! filter_var($value, FILTER_VALIDATE_EMAIL)) {
$fail('Invalid email');
}
});
TIP
You can easily use Laravel's Validation (opens new window) component for field validation with the rules helper function.
This works for relationships, too. The related models will be retrieved via your adapter and passed into your validation function.
$type->hasMany('groups')
->validate(function (callable $fail, array $groups, $model, Context $context) {
foreach ($groups as $group) {
if ($group->id === 1) {
$fail('You cannot assign this group');
}
}
});
# Transformers
Use the transform method on an attribute to mutate any incoming value before it is saved to the model.
$type->attribute('firstName')
->transform(function ($value, Context $context) {
return ucfirst($value);
});
TIP
If you're using Eloquent, you could also define attribute casts (opens new window) or mutators (opens new window) on your model to achieve a similar thing.
# Setters
Use the set method to define custom mutation logic for your field, instead of just setting the value straight on the model property.
$type->attribute('firstName')
->set(function ($value, $model, Context $context) {
$model->first_name = ucfirst($value);
if ($model->first_name === 'Toby') {
$model->last_name = 'Zerner';
}
});
# Savers
If your field corresponds to some other form of data storage rather than a simple property on your model, you can use the save method to provide a closure that will be run after your model has been successfully saved. If specified, the adapter will NOT be used to set the field on the model.
$type->attribute('locale')
->save(function ($value, $model, Context $context) {
$model->preferences()
->where('key', 'locale')
->update(['value' => $value]);
});
# Events
# onSaved
Run after a field has been successfully saved.
$type->attribute('email')
->onSaved(function ($value, $model, Context $context) {
event(new EmailWasChanged($model));
});