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

SSR Support in the adapter #171

Open
muneebshahid opened this issue Jun 7, 2023 · 5 comments
Open

SSR Support in the adapter #171

muneebshahid opened this issue Jun 7, 2023 · 5 comments

Comments

@muneebshahid
Copy link

muneebshahid commented Jun 7, 2023

A question rather than an issue. Does the adapter support SSR similar to angular-instant-search client.

https://www.algolia.com/doc/guides/building-search-ui/going-further/server-side-rendering/angular/#enable-server-side-rendering

In particular the equivalent for
import { createSSRSearchClient } from 'angular-instantsearch';

@jasonbosco
Copy link
Member

It should work with SSR - the adapter works at a higher level of abstraction, so it shouldn't matter if the app is being server-side rendered.

@mozi22
Copy link

mozi22 commented Jun 8, 2023

Hi,

As shown in the example here, the searchClient field is assigned createSSRSearchClient which itself has other fields like AppId, APIkey.

But in your example of the README the searchClient is assigned a property of TypesenseInstantSearchAdapter instance.

Additionally fields like ApplicationID are not available from typesense that makes me wonder if the createSSRSearchClient field attributes can also be passed to TypesenseInstantSearchAdapter.

In a nutshell, the field attributes for TypesenseInstantSearchAdapter and createSSRSearchClient don't match (e.g ApplicationId). So how can we achieve this ?

@jasonbosco
Copy link
Member

jasonbosco commented Jun 8, 2023

Ah I see, interesting.

I just took a look at the source code for createSSRSearchClient and it looks like it is coupled with algoliasearch (which is Algolia's search client).

So you would essentially have to clone that method, and use typesenseInstantSearchAdapter.searchClient instead of algoliasearch... This way you can remove any references to Algolia specific things like ApplicationId, etc in your version of this method.

I'm not familiar with Angular to be able to give you a working piece of code unfortunately. But if you're able to figure this out, would be great if you can share a code snippet here.

@mozi22
Copy link

mozi22 commented Jun 16, 2023

My final code looks like the following.

  public createSSRSearchClient({
    httpClient,
    HttpHeaders,
    transferState,
    makeStateKey,
    additionalSearchParameters,
  }: SSRSearchClientOptions) {
    const encode = encodeProxy.default || encodeProxy;
    const searchClient = new TypesenseInstantSearchAdapter({
      server: environment.search.credentials,
      additionalSearchParameters,
    }).searchClient;

    (searchClient as any)._request = (
      rawUrl: string,
      options: RequestOptions
    ) => {
      let headers = new HttpHeaders();

      headers = headers.set(
        'content-type',
        options.method === 'POST'
          ? 'application/x-www-form-urlencoded'
          : 'application/json'
      );

      headers = headers.set('accept', 'application/json');

      const url =
        rawUrl + (rawUrl.includes('?') ? '&' : '?') + encode(options.headers);

      const transferStateKey = makeStateKey<string>(`ngais(${options.body})`);

      if (transferState.hasKey(transferStateKey)) {
        const response = JSON.parse(
          transferState.get(transferStateKey, JSON.stringify({}))
        );

        return Promise.resolve({
          statusCode: response.status,
          body: response.body,
          headers: response.headers,
        });
      }

      return new Promise((resolve, reject) => {
        httpClient
          .request(options.method, url, {
            headers,
            body: options.body,
            observe: 'response',
          })
          .subscribe(
            (response) => {
              transferState.set(transferStateKey, JSON.stringify(response));

              resolve({
                statusCode: response.status,
                body: response.body,
                headers: response.headers,
              });
            },
            (response) =>
              reject({
                statusCode: response.status,
                body: response.body,
                headers: response.headers,
              })
          );
      });
    };

    return searchClient;
  }

Everything remains the same, I just

  • replaced algolia instance from line 55 with the typesense adapter.
  • removed line 101,102,103.
  • did npm install querystring-es3 and imported it with a require statement to avoid type errors as mentioned here.

@jasonbosco
Copy link
Member

Thank you for sharing this! 🙏

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

3 participants