Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to Upload Files with Soki in Next.js #5

Open
VienDinhCom opened this issue Jan 29, 2021 · 0 comments
Open

How to Upload Files with Soki in Next.js #5

VienDinhCom opened this issue Jan 29, 2021 · 0 comments

Comments

@VienDinhCom
Copy link
Owner

VienDinhCom commented Jan 29, 2021

Uploading files is one of the most important tasks while we're working on a web project. So, in the article, I will show you how I upload files with soki.

Schemas

File Schema

In this section, I will create a function type called upload. And I will put this function type into a child schema called FileSchema. The hello function will have the input and the output like the code below.

// src/shared/schemas/file.schema.ts

import { createSchema, fn, z } from 'soki';

export const FileSchema = createSchema({
  upload: fn({
    input: {
      file: z.file(),
    },
    output: z.string(), // file name
  }),
});

Root Schema

Next, I will put the FileSchema into the RootSchema like this.

// src/shared/schemas/root.schema.ts

import { createRootSchema } from 'soki';

import { FileSchema } from './file.schema';
import { MessageSchema } from './message.schema';

export const RootSchema = createRootSchema({
  file: FileSchema,
  message: MessageSchema,
});

On Server

File Resolver

This step, I will implement FileSchema with the Resolvers['file'] type. The upload function will return the name of the file I'm going to upload.

// src/backend/resolvers/file.resolver.ts

import { Resolvers, createResolver } from '@backend/core';

export const FileResolver = createResolver<Resolvers['file']>({
  upload: async ({ file }, context) => {
    return file.name;
  },
});

Root Resolver

Next, I will put the FileResolver into the RootResolver like this.

// src/backend/resolvers/root.resolver.ts

import { Context, createRootResolver } from '@backend/core';
import { RootSchema } from '@shared/schemas/root.schema';

import { FileResolver } from './file.resolver';
import { MessageResolver } from './message.resolver';

export const RootResolver = createRootResolver({
  RootSchema,
  resolvers: {
    file: FileResolver,
    message: MessageResolver,
  },
  context: async (req, res): Promise<Context> => {
    return {};
  },
});

On Client

Finally, I will create a form and an upload function. So I can call the upload function from the FileResolver.

// src/pages/upload.tsx

import { useState } from 'react';
import { DefaultLayout } from '@frontend/components/Layouts/DefaultLayout';
import { ApiService, useMuation, getFiles, File } from '@frontend/services/api.service';

export default function Page() {
  const [file, setFile] = useState<File>();

  const { loading, data, error, mutate } = useMuation(async (file: File) => {
    return ApiService.file.upload({ file });
  });

  return (
    <DefaultLayout>
      <h1>Upload Files</h1>
      <form
        onSubmit={(event) => {
          event.preventDefault();
          if (file) mutate(file);
        }}
      >
        <input
          type="file"
          onChange={(event) => {
            const files = getFiles(event.currentTarget.files);
            setFile(files[0]);
          }}
        />
        <br />
        {error && <p>Error: {error.message}</p>}
        {data && (
          <p>
            <b>{data}</b> is uploaded!
          </p>
        )}
        <p>
          <button type="submit">{loading ? 'Uploading...' : 'Upload Now!'}</button>
        </p>
      </form>
    </DefaultLayout>
  );
}

To test the result, please run yarn dev and go to http://localhost:3000/upload to see how it works.

Demo: https://next-full-stack-git-issue-5.maxvien.vercel.app/upload

Source Code

You can find the source code of this tutorial in this branch: https://github.com/Maxvien/next-full-stack/tree/issue-5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant