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

URL path and query parameters #1714

Closed
treeder opened this issue Jul 17, 2021 · 13 comments
Closed

URL path and query parameters #1714

treeder opened this issue Jul 17, 2021 · 13 comments
Labels
type:question A question about how to do something in Marko

Comments

@treeder
Copy link

treeder commented Jul 17, 2021

I must be missing something, but I can't seem to find how to get URL and query parameters.

For example, if I have a URL like `/stuff/123?id=456

How do I set that up so that it would use the stuff page and then how could I get the path parameter and the query parameter? Or does that require using a server integration?

@treeder treeder added the type:question A question about how to do something in Marko label Jul 17, 2021
@tigt
Copy link
Contributor

tigt commented Jul 17, 2021

Correct, whatever you’re using for HTTP listeners in Node.js would provide these. The specifics vary by framework so the list could be infinite, but here are the 3 most common:

Koa
Just ctx.query out of the box. For POST requests, you’ll need something like koa-bodyparser to provide a ctx.req.body object.
Express
req.query and req.body.
Vanilla Node.js
Only provides the URLSearchParams builtin querystring parser, which means default Node can only handle GET requests and POST with application/x-www-form-urlencoded — you’ll need an npm module for multipart/form-data.

(Vanilla Node is only as common as it is because @marko/serve and @marko/build only use the builtin http module.)

However, for each case you’ll need to put the query/body objects from the parsed requests into Marko templates yourself — the server integrations do not in fact do that for you. I personally use Koa kinda like this:

import Koa from 'koa'
import markoTemplate from "./whatever.marko"

const app = new Koa()
app.use(ctx => {
  ctx.type = 'text/html;charset=utf-8'
  ctx.body = markoTemplate.stream({
    $global: {
      query: ctx.query,
      posted: ctx.req.body
    }
  })
})
<section>
  <h2><code>GET</code> parameters</h2>
  <pre>${JSON.stringify(out.global.query, null, 2)}</pre>
</section>

<section>
  <h2><code>POST</code> parameters</h2>
  <pre>${JSON.stringify(out.global.posted, null, 2)}</pre>
</section>

@treeder
Copy link
Author

treeder commented Jul 17, 2021

Ok, thanks for the info, I'll give it a try. It would be nice to support this kind of thing out of the box. Maybe like sveltekit does it: https://kit.svelte.dev/docs#routing-advanced-rest-parameters

@ryansolid
Copy link

I think it is important to distinguish the difference between the core framework from the prebuilt template. Ie.. the difference between Svelte vs SvelteKit.

@tigt's answer is the general one. In a similar way if you were to use Svelte directly there would be no specific solution for routing as it does not come built-in in Svelte.

However, It's worth mentioning if you are using Marko CLI, the templates that use Marko Build/Serve, with its built-in file-based routing, that you can get the path params on input.params.___ and the queryString is available at input.query. Here's an example of them both being used in a simple CLI based app: https://github.com/ryansolid/marko-hackernews

@treeder
Copy link
Author

treeder commented Jul 19, 2021

@ryansolid had a quick glance through that project, I think that's what I'm looking for. Once I have a chance to try it out, I'll report back.

@treeder
Copy link
Author

treeder commented Jul 23, 2021

Thanks for the help! @ryansolid that's exactly what I was looking for. Found those docs here: https://github.com/marko-js/cli/blob/main/packages/serve/README.md#route-params for anyone else looking. It doesn't have an example with the /x/:y style though. Might want to link to your hackernews clone repo from there.

BTW, can't get over how fast all of this stuff is, both compiling and rendering 🤯

@treeder treeder closed this as completed Jul 23, 2021
@treeder
Copy link
Author

treeder commented Jul 27, 2021

@tigt how do you get around this? I copied your code exactly:

node:internal/process/esm_loader:74
    internalBinding('errors').triggerUncaughtException(
                              ^

TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".marko" for /home/treeder/dev/treeder/tokentapper-marko/index.marko

@tigt
Copy link
Contributor

tigt commented Jul 27, 2021

I personally use the @marko/rollup plugin to build my application, which handles that part for me. If you’re doing it in raw Node, Marko has a way to teach require() about the .marko extension, but the docs don’t mention it anymore and its source code mentions it’s going to be deprecated.

@treeder
Copy link
Author

treeder commented Jul 27, 2021

I'm struggling to get anything working, seems like the docs are out of date or something for server integrations at least. I'm on Node 16, maybe that has something to do with it. The only thing that has worked for me is the Marko CLI, it's the only thing that's worked out of the box.

If the CLI way of doing things could run some code to preload data before rendering, then add it to inputs, I think I'd have everything I need.

@tigt
Copy link
Contributor

tigt commented Jul 27, 2021

The Marko CLI should add input.query and input.params… are you accessing them at the topmost .marko file? If it’s a child component, you may have to pass those inputs down to it.

@treeder
Copy link
Author

treeder commented Jul 28, 2021

@tigt yes, that part works. Preloading is a different issue (which I think I tried to do in a .marko file but had issues with awaiting on data,.I think it's this #675).

@treeder
Copy link
Author

treeder commented Jul 28, 2021

I went back to the code to recall what the issue was and made a new issue here: #1722

@treeder
Copy link
Author

treeder commented Jul 30, 2021

Any reason input.query is string and input.params is a map?

This is what I"m getting:

PARAMS: { id: 'ABC' }
QUERY: amount=1

@DylanPiercey
Copy link
Contributor

@treeder params are handled explicitly by the router and so it makes sense to provided the (already parsed) result to the user. With params there are various formats people use in the wild, especially around nesting.

Luckily it seems node is moving toward the web standard way of parsing the querystring which will work nicely here also.

Basically you can do:

$ const query = new URLSearchParams(input.query);
$ const amount = query.get("amount");

(see https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:question A question about how to do something in Marko
Projects
None yet
Development

No branches or pull requests

4 participants