Comments (13)
By the way, something I found interesting was to create 3 traits depending on the way the data its sent and to be able to use interactions with or without relay, I did;:
namespace App\Interactions\Traits;
trait RelayCreateHandler
{
public $isRelay = false;
public $responseMsg = '';
public function relayValidator(array $data)
{
$payload = array_get($data, 'payload');
if (!$payload) {
throw new ValidationError('Form should be wrapped in a payload.');
}
return $this->validator($payload);
}
public function relayHandle(array $data)
{
$this->isRelay = true;
return $this->handle(array_get($data, 'payload'));
}
public function relayResponse($payload = [], $success = true)
{
return [
'success' => $success,
'msg' => $this->responseMsg,
'payload' => json_encode($payload),
];
}
}
namespace App\Interactions\Traits;
trait RelayPureHandler
{
public $isRelay = false;
public $responseMsg = '';
public function relayValidator(array $data)
{
return $this->validator($data);
}
public function relayHandle(array $data)
{
$this->isRelay = true;
return $this->handle($data);
}
public function relayResponse($payload = [], $success = true)
{
return [
'success' => $success,
'msg' => $this->responseMsg,
'payload' => json_encode($payload),
];
}
}
namespace App\Interactions\Traits;
trait RelayUpdateHandler
{
protected $isRelay = false;
protected $responseMsg = '';
public function relayValidator(array $data)
{
$payload = array_get($data, 'payload');
if (!$payload) {
throw new ValidationError('Form should be wrapped in a payload.');
}
return $this->validator(auth()->id(), $payload);
}
public function relayHandle(array $data)
{
$this->isRelay = true;
return $this->handle(auth()->id(), array_get($data, 'payload'));
}
public function relayResponse($success = true, $payload = [])
{
return [
'success' => $success,
'msg' => $this->responseMsg,
'payload' => json_encode($payload),
];
}
}
for this to work here its my interaction directive for graphql
namespace App\GraphQL\Directives;
use GraphQL\Language\AST\DirectiveNode;
use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;
use Nuwave\Lighthouse\Support\Exceptions\DirectiveException;
use Nuwave\Lighthouse\Support\Exceptions\ValidationError;
use Nuwave\Lighthouse\Support\Traits\HandlesDirectives;
class InteractionDirective implements FieldResolver
{
use HandlesDirectives;
/**
* Name of the directive.
*
* @return string
*/
public function name()
{
return 'interaction';
}
/**
* Resolve the field directive.
*
* @param FieldValue $value
*
* @return FieldValue
*/
public function resolveField(FieldValue $value)
{
$directive = $this->fieldDirective($value->getField(), $this->name());
$className = $this->getClassName($directive);
$data = $this->argValue(collect($directive->arguments)->first(function ($arg) {
return 'args' === data_get($arg, 'name.value');
}));
return $value->setResolver(function ($root, array $args, $context = null, $info = null) use ($className, $data) {
return $this->interaction($className, [$args]);
});
}
/**
* Get class name for resolver.
*
* @param DirectiveNode $directive
*
* @return string
*/
protected function getClassName(DirectiveNode $directive)
{
$class = $this->directiveArgValue($directive, 'class');
if (!$class) {
throw new DirectiveException(sprintf(
'Directive [%s] must have a `class` argument.',
$directive->name->value
));
}
return $class;
}
protected function interaction($interaction, array $parameters)
{
$validator = $this->call($interaction . '@relayValidator', $parameters);
if ($validator->fails()) {
throw with(new ValidationError('validation'))->setValidator($validator);
}
return $this->call($interaction, $parameters);
}
/**
* Will call interacion handle function if no other method its defined.
*
* @param string $interaction
* @param array $parameters
* @return mixed
*/
protected function call($interaction, array $parameters = [])
{
if (!str_contains($interaction, '@')) {
$interaction = $interaction . '@relayHandle';
}
list($class, $method) = explode('@', $interaction);
$base = class_basename($class);
return call_user_func_array([app($class), $method], $parameters);
}
}
from lighthouse.
Keep in mind that there is a spec for file uploads which had been adopted by many client libraries already: https://github.com/jaydenseric/graphql-multipart-request-spec (see the list of available serverside implementations and client libs at the bottom).
I think it makes sense to conform to this spec. There is a standalone implementation for PHP (already mentioned above), but it works for PSR-7 requests only. On the other hand, it is not that big to implement separately if required (just two classes basically).
from lighthouse.
What about this https://github.com/Ecodev/graphql-upload
And here its the source webonyx/graphql-php#220
from lighthouse.
@hailwood Great question, I didn't realize there was some work being done in the GraphQL community on this (I've been using the REST method you mentioned as well). I'd definitely be interested in getting this worked into the package though!
It looks like the graphql-multipart-request-spec is currently the way to go so I'll add this to the roadmap. If anyone wants to create a PR for it I'd be happy to merge 😄
@kikoseijo Thanks for the suggestion, it looks like a good possible solution!!
from lighthouse.
Just throwing this in here, the folks over there have implemented file upload https://github.com/rebing/graphql-laravel
from lighthouse.
I made it work out of the box by processing file uploads with laravel and relay modern.
I can post some code tomorrow if any one needs, but didnt took long, was quite simple, single file upload.
from lighthouse.
@kikoseijo I'd be quite interested to see what you've got!
from lighthouse.
Here is the Relay Mutation
// @flow
import { commitMutation, graphql } from 'react-relay';
import environment from '@graphql/env';
import { type MediaUploadInput } from '@libs/types';
const mutation = graphql`
mutation MediaUploadMutation($payload: MediaUploadInput!) {
mediaUpload(payload: $payload) {
success
msg
payload
}
}
`;
export default (
payload: MediaUploadInput,
file: *,
onMutationSuccessCallback: Function,
onMutationErrorCallback: Function
) => {
const variables = { payload };
const uploadables = { file: file };
commitMutation(environment, {
mutation,
variables,
uploadables,
onCompleted: (response, error) => {
if (response.mediaUpload && response.mediaUpload.success) {
onMutationSuccessCallback(response.mediaUpload);
} else {
onMutationErrorCallback(error);
}
},
onError: err => onMutationErrorCallback(err)
});
};
React code, im usingmobx-react-form
and `react-native-image-picker
MediaUploadMutation(form.values(), form.foto, this._handleSuccess, this._handleError);
form.foto = {
uri: 'data:image/jpeg;base64,' + photoFile.data,
type: photoFile.type ? photoFile.type : 'image/jpeg',
name: photoFile.fileName ? photoFile.fileName : 'photo.jpg'
};
Now its the schema on Laravel
extend type Mutation @group(middleware: ["auth:api"]) {
mediaUpload(payload: MediaUploadInput!): ResponsePayload
@interaction(class: "App\\Interactions\\UserMediaContribution")
}
To finish the interaction using UserMediaContribution, but any request()->hasFile('file') will work
namespace App\Interactions;
use App\Enums\GalleryType;
use App\Repositories\GalleryRepository;
use Illuminate\Support\Facades\Validator;
use Nuwave\Lighthouse\Support\Exceptions\ValidationError;
class UserMediaContribution
{
use RelayUpdateHandler;
public function validator($id, array $data)
{
return Validator::make($data, [
'title' => 'required|string|min:5|max:255',
'body' => 'nullable|string|min:5|max:255',
]);
}
public function handle($id, array $data)
{
if (request()->hasFile('file')) {
$contribGallery = Larapp::call(GalleryRepository::class . '@contribGalleryForApp', []);
$name = array_get($data, 'title');
$body = array_get($data, 'body');
$contribGallery->addMediaFromRequest('file')
->usingName($name)
->withCustomProperties(['pass' => 'n', 'body' => $body, 'by' => $id])
->toMediaCollection(GalleryType::GA_CONTRIBUTIONS);
if ($this->isRelay) {
$this->responseMsg = 'La foto se ha recibido satisfactoriamente, será publicada despues de haberse aprobado.';
return $this->relayResponse($data);
}
return $data;
} else {
throw new ValidationError('No Photo found in request, contact admin.');
}
}
}
So, basically the trick on relay its to use the uploadables section to send the files there, haven't tried with an array but should also work, same as laravel, them file data and handles them very easy.
from lighthouse.
I am working on a Lighthouse client for Angular.
File uploads is a must in my use case, so I will be adding the functionality to the client. Is there any updates on an official standard for file uploads, or are you still interested in PRs?
I'm currently just using a scalar in my backend to handle file uploads through multipart-requests, but it would be nice with an official standard.
from lighthouse.
Laravel or any of their plugins works out of the box.
from lighthouse.
@kikoseijo File uploads through a GraphQL mutation works out of the box?
from lighthouse.
I have been out for a little while, but, as i work, i process requests inside a method. Does not matter how you sending file to server, you can retrieve it anywhere using request()->file('file_name').
I invite you to make a PR for what you would like it happen.
This is definitely a community driven beauty.
from lighthouse.
@kikoseijo Will do.
Great. That is pretty much the same way I'm doing it within my scalar (it just replaces the filename with the actual file) on all attributes of type File
.
I was just thinking that it would be an advantage for everyone, if we decided on an official way of uploading files so that third party libraries can use one standard, instead of having to conform to multiple ways of uploading files through mutations. :-)
from lighthouse.
Related Issues (20)
- Generate schema fail! HOT 1
- Exception Undefined array key "schemaExtensions" HOT 1
- Clear Cache (private) HOT 1
- Segmentation fault when handling large payloads HOT 8
- Requesting local scopes can pass parameters HOT 1
- New directive that mirrors functionality of `whereHas` for relations (not `@whereHasConditions`) HOT 1
- `make setup` failed on macOS
- Access context in `FieldMiddleware` HOT 3
- CanArgs is defined twice in schema-directives.graphql
- `extend scalar X` directives are lost
- @canFind is missing "model" argument in graphql definition HOT 1
- Allow to customize the unique key for `PaginatedModelsLoader`
- artisan lighthouse:union stub appears to be incorrect HOT 1
- Problem with subscription middleware HOT 2
- An error occurs in the SubscriptionRegistry when sending a subscription event via Subscription::broadcast with Laravel Octane (Swoole) HOT 5
- Laravel v11 support dependancy missing
- Enum Support for Morph Types HOT 1
- Mutation transaction seem not work HOT 4
- Failed to find class App\GraphQl\Queries\TodoQuery in namespaces [] for directive @paginate
- @whereNull and @whereNotNull No directive found!
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from lighthouse.