question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Endpoint Middleware

See original GitHub issue

Describe the problem

I would like to propose a better model for endpoints middleware rather than the global hooks.

Current state: Today, we only have what appears to be one (1) hook src/hooks.ts that is run every time SvelteKit receives a request.

Issue: While this is ok for general things such as checking for authentication with a pathname e.g., check_auth if pathname.startsWith('/admin'). The handle becomes quite large and unwieldy to check each pathname, etc.

Describe the proposed solution

Proposal: Permit the creation of one (1) hook per Endpoint in addition to the globally defined hook.

// src/routes/user.hook.ts 
// This file can be used to perform a logic for this endpoint only

export async function handle({event, resolve}) {
  const {method, body} = event.request;

  // get to the page if GET request
  if (method === 'GET') return resolve(event);
  
  try {
    await validate(body)
    return resolve(event)
  } catch (error) {
    return Response(JSON.stringify(e), {status: 422})
  }
}

The sequence for Sveltekit hooks would be as follows

src/hooks.ts -> src/{endpoint}.hook.{ts/js} -> src/{endpoint}.{ts/js} -> src/{endpoint}.svelte

This would provide a nice global hook with the additional benefits of a hook per endpoint.

Alternatives considered

Current implementation is as follows and is a terrible experience.

export async function handle({event, resolve}) {
  const route = event.url.pathname
  const {method, body} = event.request;

  switch (route) {
    case '/users':
      if (method === 'GET') return resolve(event);
      try {
        await validateUserBody(body)
        return resolve(event)
      } catch (error) {
        return Response(JSON.stringify(e), {status: 422})
      }
      break;

    case '/notes':
      if (method === 'GET') return resolve(event);
      try {
        await validateNotesBody(body)
        return resolve(event)
      } catch (error) {
        return Response(JSON.stringify(e), {status: 422})
      }
      break;

    .... other endpoints....
  }
}


### Importance

would make my life easier

### Additional Information

I think this feature would be nice to have too many of the developers that are using Sveltekit today.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:7
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

4reactions
UltraCakeBakerycommented, Feb 15, 2022

I’ve implemented my own middleware solution that works both for page component load and endpoint handlers. You basically create a function that returns a endpoint handler, import that function in your endpoints and pass your handler function as a parameter:

// lib/authMiddleware
async function authMiddleware( fruits, load )
{
    return async function( context )
    {
        const hasTHEFruit = permissions.includes('banana')
        const loaded = load ? await load(context) : {}

        return merge(loaded, { props: { hasTHEFruit } }) 
    }
}

// some endpoint
export const get = authMiddleware(['apple', 'orange', 'banana'], ( context ) => {
    // Handle your endpoint..
})
3reactions
puchesjrcommented, Feb 13, 2022

@f-elix yes, looked at it, but won’t solve the exact problem I outlined above. While I could create each handle and use sequence, this is not exactly performant as it would run all of the handles in sequence. And, while you can have an escape hatch for the handle by checking for the pathname as the first thing, it is still not an optimal solution - which is why I propose a separate hook or middleware file that can be used/called for each endpoint.

The call graph, for lack of a better term, using sequence is roughly src/hooks[n] -> src/routes/user.ts -> src/routes/user.svelte. As you can see here, the sequence model is to n - an unbounded number.

Whereas my call graph would be src/hooks[1] -> src/routes/user.hooks.ts -> src/routes/user.ts -> src/routes/user.svelte as you can see, by separating the flow of the hooks “middleware” we have 1 global although it could be more, and 1 for the user endpoint. The call flow is much easier to grok, I know that things like ensuring authentication should be in the global hook, and things specific to my user should be in the user.hook.

Read more comments on GitHub >

github_iconTop Results From Across the Web

ASP.NET Core Middleware | Microsoft Learn
The Endpoint middleware in the preceding diagram executes the filter pipeline for the corresponding app type—MVC or Razor Pages.
Read more >
Creating an endpoint from multiple middleware in ASP.NET ...
In this post I show how you can create a composite endpoint in ASP.NET Core 3.x, by combining multiple middleware into a pipeline...
Read more >
Understanding Middleware in ASP.NET Core - Endjin
An endpoint is the object that contains the information needed to execute a request. So here, the Routing middleware matches the HTTP request...
Read more >
Cover image for ASP.NET Core Endpoints. Add endpoint ...
UseMiddleware extension method to add middleware as a class and access an endpoint from parameter ( HttpContext ). // Startup.cs app.
Read more >
ASP.NET Core Endpoints. Add endpoint ... - nikiforovall.blog
UseMiddleware extension method to add middleware as a class and access an endpoint from parameter ( HttpContext ). // Startup.cs app.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found