public API for Chrome Extension
I am trying to create an API to receive and send information from a Chrome extension, what would be the correct process to define it in main.wasp?
Create me a complete example
20 Replies
Hi @NEROX. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
To create a public API for a Chrome extension using Wasp, you need to define a custom HTTP API endpoint in your
main.wasp
file. Here's a complete example of how to do this:
1. First, define the API in your main.wasp
file:
This defines an API endpoint that will be accessible at POST /api/generate-jwt
.
2. Next, implement the API function in your src/apis/generateJwt.js
file:
This implementation creates a JWT token for the user. In a real-world scenario, you would need to implement proper authentication logic.
3. Make sure to set up CORS for your API to allow requests from your Chrome extension. You can do this by adding a middleware config in your main.wasp
file:
4. Implement the middleware in src/middleware.js
:
This setup will create a public API endpoint that your Chrome extension can use to generate JWT tokens. The extension can then use these tokens for authentication in subsequent requests to your Wasp backend.
Remember to handle security carefully, especially when dealing with extensions and public APIs. This example is simplified and you should add proper authentication, rate limiting, and other security measures in a production environment.
Sources:
Custom HTTP API Endpoints
Making Sure CORS Works
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @NEROX, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?@kapa.ai
main.wasp:
query getSitemap {
fn: import { getSitemap } from "@src/server/webScraper.js",
entities: []
}
query checkUrlStatus {
fn: import { checkUrlStatus } from "@src/server/webScraper.js",
entities: []
}
query getPageContent {
fn: import { getPageContent } from "@src/server/webScraper.js",
entities: []
}
webScraper.ts:
import axios from 'axios';
import { xml2js } from 'xml-js';
import * as cheerio from 'cheerio';
import puppeteer from 'puppeteer';
import TurndownService from 'turndown';
import type { GetSitemap, CheckUrlStatus, GetPageContent } from 'wasp/server/operations';
// Define input/output types
type GetSitemapArgs = { domain: string };
type CheckUrlStatusArgs = { urls: string[] };
type GetPageContentArgs = { url: string };
// Define XML types
interface XMLLoc {
_text: string;
}
interface XMLUrl {
loc: XMLLoc;
}
interface XMLUrlset {
url: XMLUrl | XMLUrl[];
}
interface XMLSitemap {
loc: XMLLoc;
}
interface XMLSitemapIndex {
sitemap: XMLSitemap | XMLSitemap[];
}
interface XMLResult {
urlset?: XMLUrlset;
sitemapindex?: XMLSitemapIndex;
}
// Export interfaces as plain objects to satisfy SuperJSON
export type UrlStatus = {
url: string;
status: number;
redirectUrl?: string;
}
export type PageContent = {
title: string;
content: string;
contentMd: string;
metadata: {
description: string;
keywords: string;
author: string;
};
styles: string[];
scripts: string[];
inlineStyles: string;
}
Let me check the knowledge base for you again. One moment! :books:
----------------------
I apologize, but I don't have enough information in the provided knowledge sources to give a complete and accurate answer about the specific code you've shared. The code you've provided seems to be a mix of Wasp query declarations and TypeScript implementations, but I don't have detailed information about these specific queries or their implementations in the context you've provided.
However, I can provide some general information about Wasp queries based on the knowledge sources:
1. Queries in Wasp are declared in the
main.wasp
file and implemented in separate JavaScript or TypeScript files. This is consistent with what you've shown in your code snippet. Declaring Queries
2. The syntax for declaring queries in the main.wasp
file looks correct based on the examples in the documentation. API Reference
3. For TypeScript implementations, Wasp generates types that you can use to specify the query's input and output types. This is similar to what you're doing with the GetSitemap
, CheckUrlStatus
, and GetPageContent
types. Implementing Queries
4. The use of entities: []
in your query declarations suggests that these queries don't directly interact with any Wasp entities. This is valid, but different from some of the examples in the documentation which often show queries using entities.
If you have specific questions about how to implement these queries or how to use them in your Wasp application, I'd be happy to try to answer based on the general Wasp documentation. However, for the specific implementation details and types you've defined, I don't have enough context in the provided knowledge sources to comment on their correctness or provide guidance.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @NEROX, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?@kapa.ai
main.wasp:
query getSitemap {
fn: import { getSitemap } from "@src/server/webScraper.js",
entities: []
}
query checkUrlStatus {
fn: import { checkUrlStatus } from "@src/server/webScraper.js",
entities: []
}
query getPageContent {
fn: import { getPageContent } from "@src/server/webScraper.js",
entities: []
}
webScraper.ts:
import axios from 'axios';
import { xml2js } from 'xml-js';
import * as cheerio from 'cheerio';
import puppeteer from 'puppeteer';
import TurndownService from 'turndown';
import type { GetSitemap, CheckUrlStatus, GetPageContent } from 'wasp/server/operations';
// Define input/output types
type GetSitemapArgs = { domain: string };
type CheckUrlStatusArgs = { urls: string[] };
type GetPageContentArgs = { url: string };
// Define XML types
interface XMLLoc {
_text: string;
}
interface XMLUrl {
loc: XMLLoc;
}
interface XMLUrlset {
url: XMLUrl | XMLUrl[];
}
interface XMLSitemap {
loc: XMLLoc;
}
interface XMLSitemapIndex {
sitemap: XMLSitemap | XMLSitemap[];
}
interface XMLResult {
urlset?: XMLUrlset;
sitemapindex?: XMLSitemapIndex;
}
// Export interfaces as plain objects to satisfy SuperJSON
export type UrlStatus = {
url: string;
status: number;
redirectUrl?: string;
}
export type PageContent = {
title: string;
content: string;
contentMd: string;
metadata: {
description: string;
keywords: string;
author: string;
};
styles: string[];
scripts: string[];
inlineStyles: string;
}
what I'm doing creating my API endpoint? fix my example completely
Let me check the knowledge base for you again. One moment! :books:
----------------------
Based on the code you've provided, it appears you're trying to create query operations for web scraping functionalities in a Wasp application. However, if you're aiming to create API endpoints that can be accessed externally (e.g., from a Chrome extension as mentioned in your previous question), you should use the
api
declaration in Wasp instead of query
.
Here's how you can modify your main.wasp
file to create API endpoints:
Now, let's modify your webScraper.ts
file to implement these API endpoints:
These changes will create three API endpoints:
1. GET /api/sitemap
for fetching a sitemap
2. POST /api/check-url-status
for checking URL statuses
3. GET /api/page-content
for fetching page content
A few important points:
1. We've changed query
to api
in the main.wasp
file. This creates HTTP endpoints instead of Wasp queries.
2. We've added httpRoute
to each API declaration, specifying the HTTP method and path.
3. In the implementation file, we're now importing types from wasp/server/api
instead of wasp/server/operations
.
4. The implementation functions now take req
, res
, and context
parameters, as is standard for Express.js route handlers.
5. We're using res.json()
to send the response, which is the correct way to respond in an Express.js-style API.
Remember to handle errors appropriately and validate input in your actual implementations.
Also, you might want to add CORS configuration if these APIs will be accessed from a different origin (like a Chrome extension). You can do this as shown in the previous answer:
And implement the middleware in src/middleware.js
:
This setup will create public API endpoints that can be accessed externally, which seems to be what you're aiming for.
Custom HTTP API Endpoints
</assistant_answer>
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @NEROX, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?@kapa.ai
Is this corect?
api getSitemapApi {
fn: import { getSitemap } from "@src/server/webScraper.js",
httpRoute: (GET, "/api/sitemap")
}
api checkUrlStatusApi {
fn: import { checkUrlStatus } from "@src/server/webScraper.js",
httpRoute: (POST, "/api/check-url-status")
}
api getPageContentApi {
fn: import { getPageContent } from "@src/server/webScraper.js",
httpRoute: (GET, "/api/page-content")
}
apiNamespace webScraperApi {
middlewareConfigFn: import { webScraperApiMiddleware } from "@src/middleware.js",
path: "/api"
}
Let me check the knowledge base for you again. One moment! :books:
----------------------
Yes, the code you've provided is correct for defining custom API endpoints in Wasp. Let's break it down:
1. API Definitions:
Your three
api
declarations for getSitemapApi
, checkUrlStatusApi
, and getPageContentApi
are correctly structured. Each one specifies:
- A function to handle the request (fn
)
- An HTTP route with method and path (httpRoute
)
This is consistent with the API declaration syntax described in the Custom HTTP API Endpoints documentation.
2. API Namespace:
You've also correctly defined an apiNamespace
called webScraperApi
. This is used to apply middleware to all routes under the "/api" path. The syntax matches the example provided in the Customize Per-Path Middleware section of the Wasp documentation.
Your code will create the following endpoints:
- GET /api/sitemap
- POST /api/check-url-status
- GET /api/page-content
And all of these endpoints will use the middleware defined in webScraperApiMiddleware
.
Remember to implement the actual functions (getSitemap
, checkUrlStatus
, getPageContent
) in your @src/server/webScraper.js
file, and the webScraperApiMiddleware
function in your @src/middleware.js
file.
This setup will allow you to handle CORS and any other middleware concerns for all your API routes in one place, which is a good practice for maintaining consistency across your API endpoints.
Custom HTTP API Endpoints
Customize Per-Path Middleware
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @NEROX, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?Woah let's try
@kapa.ai is possible to test API endpoints in development with localhost:3000?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Yes, it is possible to test API endpoints in development using localhost:3000, but there's an important detail to note about Wasp's default port configuration.
By default, Wasp uses two different ports for development:
1. Port 3000 for the web client (frontend)
2. Port 3001 for the API server (backend)
This means that while your React frontend will be accessible at
<http://localhost:3000
,> your API endpoints will actually be served from <http://localhost:3001
.>
To test your API endpoints during development, you should use <http://localhost:3001
> followed by your API route. For example:
- <http://localhost:3001/api/sitemap
>
- <http://localhost:3001/api/check-url-status
>
- <http://localhost:3001/api/page-content
>
You can use tools like Postman, curl, or even your browser (for GET requests) to test these endpoints.
If you need to use a different port, Wasp allows you to configure this. As mentioned in the Github issue about port configuration, you can set custom ports using environment variables:
1. For the web client, in .env.client
:
2. For the API server, in .env.server
:
Remember, when testing your API endpoints, make sure your server is running (wasp start
). Also, if you're calling these APIs from your frontend code during development, Wasp should handle the correct URL configuration automatically.
Make it easy to use different ports (than 3000 and 3001) during Wasp development
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
Sorry @NEROX, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist:
Perhaps try again in 15mins?Just built a Chrome extension with Api, thx Kapa!
;)


Dude!!!! You are killing it!
Cool. What is this useful for?
I think his app on product hunt is about SEO, maybe an addon
Having all URLs it's easier to automate any kind of interlink, it's very easy extension for now.
I still don't get what it's useful for, but I trust it is 🙂
It's useful for SEO stuff, right?
teach me 👶
Did you build an extension with a new wasp project or is it an api?
We should do another community get together
I have built the whole API with Wasp and later the extension that makes the calls, I have also created it in tool format: https://whitehatseotactics.com/website-page-counter
For any content writing task with AI for example, you can pass to ChatGPT the whole list of links and ask it to create in an article the most relevant internal links in a natural way for example.

ok I love this tool now 🏩
great idea