I want to upload image on by using graphql-upload package
This is my scheme file
const { GraphQLSchema, GraphQLObjectType, GraphQLBoolean } = require("graphql");
const { GraphQLUpload } = require("graphql-upload");
const schema = new GraphQLSchema({
mutation: new GraphQLObjectType({
name: "Mutation",
fields() {
return {
uploadImage: {
description: "Uploads an image.",
type: GraphQLBoolean,
args: {
image: {
description: "Image file.",
type: GraphQLUpload
}
},
async resolve(parent, { image }) {
const { filename, mimetype, createReadStream } = await image;
const stream = createReadStream();
// Promisify the stream and store the file, then…
return true;
}
}
};
}
})
});
This is my server file. When I run the file it gives error on the browser side. it showed: {"errors":[{"message":"Must provide query string."}]}.
const express = require("express");
const graphqlHTTP = require("express-graphql");
const { graphqlUploadExpress } = require("graphql-upload");
const schema = require("./schema");
express()
.use(
"/graphql",
graphqlUploadExpress({ maxFileSize: 10000000, maxFiles: 10 }),
graphqlHTTP({ schema })
)
.listen(3000);
**What am I doing wrong? **
Related
So I'm trying to send an image to our server with react native using GraphQL query and I don't know why but it always return an error : [CombinedError: [Network] Network request failed].
The query :
import { graphql } from '../../gql';
import { gql, useMutation } from 'urql';
const AddProfilePicture_Mutation = graphql(`
mutation AddPicture_Mutation ($userId: ID!, $picture: Upload!) {
uploadProfilePicture(input: {
userId: $userId
picture: $picture
}) {
id
}
}`);
export const useAddProfilePicture = () => {
const [{fetching, error}, execute] = useMutation(AddProfilePicture_Mutation);
return {
error: !!error,
fetching,
addProfilePicture: execute,
}
}
and the code :
const pictureHandler = async () => {
const options = {
mediaType: 'photo' as MediaType,
includeBase64: true,
selectionLimit: 1,
};
const profilePicture = await launchImageLibrary(options);
if (profilePicture.assets?.[0].fileSize && profilePicture.assets?.[0].fileSize > MAXFILESIZE) {
showError(t('profileScreen.PictureSize'));
}
if (profilePicture.assets?.[0].uri && profilePicture.assets[0].fileName && profilePicture.assets[0].type) {
// const myBlob = await fetch(profilePicture.assets[0].uri).then(r => r.blob());
const blob = new Blob([profilePicture.assets[0].base64 as BlobPart], {
type: profilePicture.assets[0].type,
});
const file = new File([blob], profilePicture.assets[0].fileName, { type: `${profilePicture.assets[0].type}`});
const {error} = await addProfilePicture(
{ userId: userId!, picture: file},
{ fetchOptions: { headers: { 'graphql-require-preflight': '' } } }
);
if (!error) {
showSuccess(t('profileScreen.PictureSuccessAdded'));
navigation.navigate('UserProfile');
} else {
console.log(error);
showError(t('profileScreen.PictureErrorAdded'));
}
};
};
I've been trying everything I found on the web, Formdata, react-native-blob-util and rn-fetch-blob. If I try sending anything else then a File, the server reject it and says for exemple:
Variable 'picture' has an invalid value: Expected type org.springframework.web.multipart.MultipartFile but was java.util.LinkedHashMap]
Update :
After long research and help from other programmers. We never did found the answer. We open a new access point in the backend specifically for the uploaded picture and used a regular fetch post.
I'm learning to use the Redis for my backend database and I would like to try using redis-om for fastify not sure whether they are compatible or not, but I got error.
I use service of app.redislabs.com
I don't know what I just messed up? And how can I fix the problem?
server.js
const { createCar, createIndex } = require("./redis");
app.post("/add", async (req, res) => {
await createIndex();
const { make, model, image, description } = req.body;
const data = { make, model, image, description };
await createCar(data);
res.code(200).send('ok');
});
const PORT = 5000;
app.listen(PORT, function (err) {
if (err) {
app.log.error(err);
process.exit(1);
}
});
redis.js
const { Client, Entity, Schema, Repository } = require("redis-om");
const client = new Client();
const connect = async () => {
if (!client.isOpen()) {
await client.open("redis://default:password#localhost:6379");
} else {
console.log("CONNECTED");
}
};
class Car extends Entity {}
let schema = new Schema(
Car,
{
make: { type: "string" },
model: { type: "string" },
image: { type: "string" },
description: { type: "string" },
},
{ dataStructure: "JSON" }
);
const createCar = async (data) => {
await connect();
const repository = new Repository(schema, client);
const car = repository.createEntity(data);
const id = await repository.save(car);
return id;
};
const createIndex = async () => {
await connect();
const repository = new Repository(schema, client);
await repository.createIndex();
};
module.exports = {
createCar,
createIndex,
};
My JSON Body
You cannot call new on Repository. This is a breaking change I introduced in version 0.2.0 of Redis OM. There are a couple of others that are documented in the CHANGELOG.
Call const repository = client.fetchRepository(schema) instead, as shown here. Unfortunately, there are some videos and blogs that have the older syntax and so this crops up from time to time.
Thanks for using my library!
I'm building a GraphQL API and I want to test some resolvers and the database with jest.
Here is my helper file, where I set up the context and the Prisma Client for testing.
import { PrismaClient } from "#prisma/client";
import { ServerInfo } from "apollo-server";
import { execSync } from "child_process";
import getPort, { makeRange } from "get-port";
import { GraphQLClient } from "graphql-request";
import { nanoid } from "nanoid";
import { join } from "path";
import { Client } from "pg";
import { server } from "../api/server";
type TestContext = {
client: GraphQLClient;
db: PrismaClient;
};
export function createTestContext(): TestContext {
let ctx = {} as TestContext;
const graphqlCtx = graphqlTestContext();
const prismaCtx = prismaTestContext();
beforeEach(async () => {
const client = await graphqlCtx.before();
const db = await prismaCtx.before();
Object.assign(ctx, {
client,
db,
});
});
afterEach(async () => {
await graphqlCtx.after();
await prismaCtx.after();
});
return ctx;
}
function graphqlTestContext() {
let serverInstance: ServerInfo | null = null;
return {
async before() {
const port = await getPort({ port: makeRange(4000, 6000) });
serverInstance = await server.listen({ port });
return new GraphQLClient(`http://localhost:${port}`);
},
async after() {
serverInstance?.server.close();
},
};
}
function prismaTestContext() {
const prismaBinary = join(__dirname, "..", "node_modules", ".bin", "prisma");
let schema = "";
let databaseUrl = "";
let prismaClient: null | PrismaClient = null;
return {
async before() {
schema = `test_${nanoid()}`;
databaseUrl = `postgresql://user:123#localhost:5432/testing?schema=${schema}`;
process.env.DATABASE_URL = databaseUrl;
execSync(`${prismaBinary} migrate up --create-db --experimental`, {
env: {
...process.env,
DATABASE_URL: databaseUrl,
},
});
prismaClient = new PrismaClient();
return prismaClient;
},
async after() {
const client = new Client({
connectionString: databaseUrl,
});
await client.connect();
await client.query(`DROP SCHEMA IF EXISTS "${schema}" CASCADE`);
await client.end();
await prismaClient?.$disconnect();
},
};
}
My test file looks like this:
import { createTestContext } from "./__helpers";
const ctx = createTestContext();
it("register user", async () => {
const testUser = {
username: "Test",
email: "test#test.com",
password: "password",
};
const registerResult = await ctx.client.request(
`
mutation registerNewUser($username: String!, $email: String!, $password: String!) {
register(username: $username, email: $email, password: $password) {
user {
user_id
username
email
}
}
}
`,
{
username: testUser.username,
email: testUser.email,
password: testUser.password,
}
);
const resultUsername = registerResult.register.user.username;
const resultEmail = registerResult.register.user.email;
const resultUserID = registerResult.register.user.user_id;
expect(resultUsername).toBe(testUser.username);
expect(resultEmail).toBe(testUser.email);
expect(resultUserID).not.toBeNull;
const users = await ctx.db.user.findMany();
const savedUser = users[0];
expect(savedUser.username).toBe(testUser.username);
expect(savedUser.email).toBe(testUser.email);
expect(savedUser.user_id).toBe(resultUserID);
expect(savedUser.first_name).toBeNull;
expect(savedUser.last_name).toBeNull;
expect(savedUser.role).toBe("USER");
expect(savedUser.password).not.toBe(testUser.password);
});
it("all events", async () => {
const eventsResult = await ctx.client.request(
`
query {
allEvents {
event_id
title
description
}
}
`
);
expect(eventsResult.allEvents.length).toBe(0)
});
When I just run one file with one test in it, everything works. But when I run multiple tests in one file, the first one runs normal, but the ones after not. I receive this error:
The table `test_LjrcmbMjI4vLaDYM9-lvw.Event` does not exist in the current database.: {"response":{"errors":[{"message":"\nInvalid `prisma.event.findMany()` invocation:\n\n\n The table `test_LjrcmbMjI4vLaDYM9-lvw.Event` does not exist in the current database.","locations":[{"line":3,"column":7}],"path":["allEvents"],"extensions":{"code":"INTERNAL_SERVER_ERROR","exception":{"code":"P2021","clientVersion":"2.11.0","meta":{"table":"test_LjrcmbMjI4vLaDYM9-lvw.Event"}}}}],"data":null,"status":200},"request":{"query":"\n query {\n allEvents {\n event_id\n title\n description\n }\n }\n "}}
Also when I run two tests in separated files, on every second test run I get this error:
listen EADDRINUSE: address already in use :::4200
I did the nexus tutorial (Step 4, and 5), where they explained how to test, but somehow it doesn't work. So please help me.
https://nexusjs.org/docs/getting-started/tutorial
I have created a repo with parallel tests for the same here. The test environment setup is in the prisma folder and a similar helper is created in the tests folder.
How to post a file to Amazon S3 using node and react and save it path to mongoDB. with mongoose and formidable.
private async storeFile(file: { buffer: Buffer, fileId: string }): Promise<string> {
try {
const awsConfig = new AWS.Config(storageConfig);
const s3 = new AWS.S3(awsConfig);
let storageLink = undefined;
fs.readFile(file.buffer, (err, data) => {
if (err) {
throw err;
}
const params = {
Bucket:storageConfig.s3Bucket,
Key: `${storageConfig.s3Prefix}${file.fileId}`,
Body: data,
};
s3.upload(params, (s3Err: Error, s3Data: AWS.S3.ManagedUpload.SendData) => {
if (s3Err) {
throw s3Err;
}
storageLink = s3Data.Location;
});
});
return storageLink;
} catch (error) {
throw error;
}
}
In your Service file where you wanna call this function, update with record in collection
const storageLink = this.storeFile({ buffer, fileId });
const file = await file.updateOne({ _id: fileId }, {
status: fileStatus.UPLOADED, // just a flag
fileId: storageLink,
});
I am trying to upload image to amazon s3,If possible can any one provide links /docs for how to upload to amazon s3, any help much appreciated
S3 options:
// this.state.s3options in YourComponent
{
"url": "https://yourapp.s3.eu-central-1.amazonaws.com",
"fields": {
"key": "cache/22d65141b48c5c44eaf93a0f6b0abc30.jpeg",
"policy": "eyJleHBpcm...1VDE0Mzc1OVoifV19",
"x-amz-credential": "AK...25/eu-central-1/s3/aws4_request",
"x-amz-algorithm": "AWS4-HMAC-SHA256",
"x-amz-date": "20161125T143759Z",
"x-amz-signature": "87863c360...b9b304bfe650"
}
}
Component:
class YourComponent extends Component {
// ...
// fileSource looks like: {uri: "content://media/external/images/media/13", isStatic: true}
async uploadFileToS3(fileSource) {
try {
var formData = new FormData();
// Prepare the formData by the S3 options
Object.keys(this.state.s3options.fields).forEach((key) => {
formData.append(key, this.state.s3options.fields[key]);
});
formData.append('file', {
uri: fileSource.uri,
type: 'image/jpeg',
});
formData.append('Content-Type', 'image/jpeg')
var request = new XMLHttpRequest();
request.onload = function(e) {
if (e.target.status === 204) {
// Result in e.target.responseHeaders.Location
this.setState({avatarSourceRemote: {uri: e.target.responseHeaders.Location}})
}
}.bind(this)
request.open('POST', this.state.s3options.url, true);
request.setRequestHeader('Content-type', 'multipart/form-data');
request.send(formData);
} catch(error) {
console.error(error);
}
}
// Example display the uploaded image
render() {
if (this.state.avatarSourceRemote) {
return (
<Image source={this.state.avatarSourceRemote} style={{width: 100, height: 100}} />
);
} else {
return (
<Text>No Image</Text>
);
}
}
}
This works for me
import fs from 'react-native-fs';
import {decode} from 'base64-arraybuffer';
import AWS from 'aws-sdk';
export const uploadFileToS3 = async (file) => {
const BUCKET_NAME = 'XXXXXXXXXX';
const IAM_USER_KEY = 'XXXXXXXXXX';
const IAM_USER_SECRET = 'XXXXXXXXXXXXXXX';
const s3bucket = new AWS.S3({
accessKeyId: IAM_USER_KEY,
secretAccessKey: IAM_USER_SECRET,
Bucket: BUCKET_NAME,
signatureVersion: 'v4',
});
const contentType = file.type;
const contentDeposition = `inline;filename="${file.name}"`;
const fPath = file.uri;
const base64 = await fs.readFile(fPath, 'base64');
const arrayBuffer = decode(base64);
return new Promise((resolve, reject) => {
s3bucket.createBucket(() => {
const params = {
Bucket: BUCKET_NAME,
Key: file.name,
Body: arrayBuffer,
ContentDisposition: contentDeposition,
ContentType: contentType,
};
s3bucket.upload(params, (error, data) => {
utils.stopLoader();
if (error) {
reject(getApiError(error));
} else {
console.log(JSON.stringify(data));
resolve(data);
}
});
});
});
};
This worked for me after a significant amount of trying over and over again...
I am also using a lambda function to serve me the link to post with.
The lambda function is just using getSignedUrl.
// Lambda Function
const AWS = require('aws-sdk')
AWS.config.update({
accessKeyId: {bucket_access},
secretAccessKey: {bucket_secret},
signatureVersion: 'v4',
region: {bucket_region}
})
const s3 = new AWS.S3()
exports.handler = async (event) => {
const URL = s3.getSignedUrl('putObject', {Bucket: {bucket_name},
// name of file name being placed in S3 Bucket
// event === metaData object
Key: `${event.{key}}/photo00`})
return URL
};
// React Native
const imagePreview = '{image_uri}'
const handleURL = async () => {
// metaData object
const obj = {
key: "meta_data"
}
const response = await fetch{{lambda_func_endpoint}, {
method: 'POST',
body: JSON.stringify(obj)
})
const json = await response.json();
return json
}
const handleUpload = async () => {
const URL = await handleURL()
const imageExt = imagePreview.split('.').pop()
// I have no idea why you are supposed to fetch before fetching...
// makes no sense. But it works. Lots of trying as I said.
let image = await fetch(imagePreview)
// I have no idea why it needs to be a blob in order
// to upload... makes no sense.
image = await image.blob()
await fetch(URL, {
method: 'PUT',
body: image,
headers: {
Accept: `image/${imageExt}`,
'Content-Type': `image/${imageExt}`
}
})
.then((res) => console.log(JSON.parse(JSON.stringify(res)).status))
.catch((err) => console.error(err))
}
Let me know what you guys think!