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

Is is possible to access data.body when using middlewares? #84

Open
ashishjullia opened this issue Aug 8, 2023 · 5 comments
Open

Is is possible to access data.body when using middlewares? #84

ashishjullia opened this issue Aug 8, 2023 · 5 comments

Comments

@ashishjullia
Copy link

ashishjullia commented Aug 8, 2023

Hi,

I've the following code in which I'm trying to run a middleware on data.body.email but unable to do so, am I missing something or is it just possible with request.

index.js

import { OpenAPIRouter } from "@cloudflare/itty-router-openapi";
import { SignUp } from "./Users/controller";
import isValidEmail from "./utils/email"

const router = OpenAPIRouter({
	schema: {
		info: {
			title: "Worker OpenAPI Example",
			version: "1.0",
		},
	},
});

router.post("/api/users", isValidEmail, SignUp)

// Redirect root request to the /docs page
router.original.get("/", (request) =>
	Response.redirect(`${request.url}docs`, 302)
);

// 404 for everything else
router.all("*", () => new Response("Not Found.", { status: 404 }));

export default {
	fetch: router.handle,
};

./utils/email.js

const EMAIL_REGEXP = new RegExp(
    /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
);

const isValidEmail = (request,
    env,
    context,
    data) => {
    console.log(data)
    return EMAIL_REGEXP.test(data.body.email);
}

export default isValidEmail

./users/controller.js

import {
    Bool,
    OpenAPIRoute,
    Path,
    Str
} from "@cloudflare/itty-router-openapi";

import isValidEmail from "../utils/email"

const SignUpResponse = {
    message: "User Added!"
}

export class SignUp extends OpenAPIRoute {
    static schema = {
        tags: ["Users"],
        summary: "User Sign Up",
        requestBody: {
            contentType: 'application/json',
            firstname: new Str({
                description: "User Firstname",
                required: true,
                example: "Ashish"
            }),
            lastname: new Str({
                description: "User Lastname",
                required: true,
                example: "Jullia"
            }),
            email: new Str({
                description: "User Email",
                required: true,
                example: "username@example.com"
            }),
            password: new Str({
                description: "User Password",
                required: true,
                example: "As@121212121212"
            })
        },
        responses: {
            "200": {
                contentType: 'application/json',
                schema: {
                    Response: SignUpResponse,
                },
            },
        },
    };

    async handle(
        request,
        env,
        context,
        data
    ) {
        // Retrieve the validated slug
        const { firstname, lastname, email, password } = data.body

        // console.log(isValidEmail(email))

        return {
            message: "User Added!"
        };
    }
}
@ashishjullia
Copy link
Author

ashishjullia commented Aug 8, 2023

Also, the contentType: 'application/json' is not working for requestBody, not sure how to pass it correctly.

I've an issue opened for confirmation: #85

@ashishjullia
Copy link
Author

With a framework like expressjs (out of context of cf workers) which provides you (req, res, next) and makes it easier to follow middleware pattern and extracting say (email key) from body as req.body.email.

Is is possible to achieve the same with this itty-rotuer-openapi? I'm aware that it has (request, env, context, data) but unable to get the data.body.email and next in the similar fashion :/

@G4brym
Copy link
Member

G4brym commented Aug 9, 2023

Hey there, in order to validate emails you should use the Email type like this:

import {
    Email
} from "@cloudflare/itty-router-openapi";

...

            email: new Email({
                description: "User Email",
                required: true,
            }),

Currently middleware support is limited, and you cannot access the data object, you can read more about whats supported here

itty-router-openapi doesn't support the next() function like express, but you should be able to modify the request, env, context parameters in middlewares and these changes will be applied in downstream endpoints

@ashishjullia
Copy link
Author

@G4brym
Hmm, thanks for the information but by providing the email example I wanted to know whether how to play on data.body when working with middleware because a lot of powerful things like authentication/authorization can be done via these middlewares or more such things.

Sad to know that it won't be possible with this. :/

@G4brym
Copy link
Member

G4brym commented Aug 9, 2023

You can do middlewares the "old fashion", because the endpoints are all class based, you can just build a base class that does authentication and then extend your endpoint from there.

otherwise you can still do authentication with the current middleware support here is a snipped taken from here

export function getBearer(request: Request): null | string {
    const authHeader = request.headers.get('Authorization')
    if (!authHeader || authHeader.substring(0, 6) !== 'Bearer') {
        return null
    }
    return authHeader.substring(6).trim()
}


export async function authenticateUser(request: Request, env: any, context: any) {
    const token = getBearer(request)
    let session

    if (token) {
        session = await context.qb.fetchOne({
            tableName: 'users_sessions',
            fields: '*',
            where: {
                conditions: [
                    'token = ?1',
                    'expires_at > ?2',
                ],
                params: [
                    token,
                    new Date().getTime()
                ]
            },
        }).execute()
    }

    if (!token || !session.results) {
        return new Response(JSON.stringify({
            success: false,
            errors: "Authentication error"
        }), {
            headers: {
                'content-type': 'application/json;charset=UTF-8',
            },
            status: 401,
        })
    }

    // set the user_id for endpoint routes to be able to reference it
    env.user_id = session.results.user_id
}

...


// Authentication middleware
router.all('/api/*', authenticateUser)

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

2 participants