swapi icon indicating copy to clipboard operation
swapi copied to clipboard

Searching using the Wookiee encoding can produce invalid JSON

Open mpvvliet opened this issue 7 years ago • 5 comments

If you search for items using Wookiee encodings, the API returns invalid JSON if there is no next or previous search result.

For example: https://swapi.co/api/planets/?format=wookiee&search=z returns the following response:

{"oaoohuwhao":1,"whwokao":whhuanan,"akrcwohoahoohuc":whhuanan,"rcwochuanaoc":[{"whrascwo":"Zooanrawh","rcooaoraaoahoowh_akworcahoowa":"huwhorwhooohwh","oorcrhahaoraan_akworcahoowa":"huwhorwhooohwh","waahrascwoaoworc":"huwhorwhooohwh","oaanahscraaowo":"huwhorwhooohwh","rrrcrahoahaoro":"huwhorwhooohwh","aoworcrcraahwh":"huwhorwhooohwh","churcwwraoawo_ohraaoworc":"huwhorwhooohwh","akooakhuanraaoahoowh":"huwhorwhooohwh","rcwocahwawowhaoc":["acaoaoakc://cohraakah.oaoo/raakah/akwoooakanwo/70/"],"wwahanscc":[],"oarcworaaowowa":"2014-12-20T16:56:37.250000Z","wowaahaowowa":"2014-12-20T20:58:18.514000Z","hurcan":"acaoaoakc://cohraakah.oaoo/raakah/akanrawhwoaoc/54/"}]}

Due to the fact that the JSON value null is valid, but the Wookiee translation whhuanan is not, this is invalid JSON.

mpvvliet avatar Sep 18 '17 19:09 mpvvliet

I also faced the same issue and found a workaround for this solution. First of all, Convert the response into a string and then replace whhuanan with "whhuanan" (in string) globally and then parse the result string into JSON.


  const params = {
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    },
    method: 'GET',
  }
  return fetch(''https://swapi.co/api/planets/1/?format=wookiee'', params).then(response => {
    return response.text().then((text) => {
        text = text.replace(/whhuanan/g, '"whhuanan"')
        return JSON.parse(text)
      })
  }).catch(error => {
    throw error
  })

Hope it helps.

bansalritesh18 avatar May 22 '18 18:05 bansalritesh18

Shouldn't null just not be rendered as whhuanan instead?

sgvictorino avatar May 23 '18 23:05 sgvictorino

Jackson will produce following exception during deserialization:

javax.ws.rs.ProcessingException: Error reading entity from input stream.
	at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:865)
	at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:784)
	at org.glassfish.jersey.client.ClientResponse.readEntity(ClientResponse.java:297)
	at org.glassfish.jersey.client.InboundJaxrsResponse$1.call(InboundJaxrsResponse.java:91)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
	at org.glassfish.jersey.internal.Errors.process(Errors.java:205)
	at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:365)
	at org.glassfish.jersey.client.InboundJaxrsResponse.runInScopeIfPossible(InboundJaxrsResponse.java:240)
	at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:88)
	at com.company.rest.entity.PropertyObjectEntityWrapper.readEntity(PropertyObjectEntityWrapper.java:26)
	at com.company.rest.call.internal.RestCall.getEntity(RestCall.java:35)
	at com.company.rest.test.RestCallTest.callGetOnSwapi(RestCallTest.java:44)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:566)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)
Caused by: com.fasterxml.jackson.core.JsonParseException: Unrecognized token 'whhuanan': was expecting ('true', 'false' or 'null')
 at [Source: (org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$UnCloseableInputStream); line: 1, column: 36]
	at com.fasterxml.jackson.core.JsonParser._constructError(JsonParser.java:1804)
	at com.fasterxml.jackson.core.base.ParserMinimalBase._reportError(ParserMinimalBase.java:703)
	at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._reportInvalidToken(UTF8StreamJsonParser.java:3532)
	at com.fasterxml.jackson.core.json.UTF8StreamJsonParser._handleUnexpectedValue(UTF8StreamJsonParser.java:2627)
	at com.fasterxml.jackson.core.json.UTF8StreamJsonParser.nextFieldName(UTF8StreamJsonParser.java:1053)
	at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer.deserializeObject(JsonNodeDeserializer.java:247)
	at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:68)
	at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:15)
	at com.fasterxml.jackson.databind.deser.std.StdNodeBasedDeserializer.deserialize(StdNodeBasedDeserializer.java:72)
	at com.fasterxml.jackson.databind.ObjectReader._bind(ObjectReader.java:1574)
	at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:965)
	at org.glassfish.jersey.jackson.internal.jackson.jaxrs.base.ProviderBase.readFrom(ProviderBase.java:838)
	at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:233)
	at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:212)
	at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:132)
	at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1071)
	at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:850)
	... 35 more

atosscsd-bb avatar Nov 14 '19 09:11 atosscsd-bb

same issue here when I try to translate the language to Wookiee and the and the response of the API on the property 'previous' is actually null which is correct and its corresponding translation is this whhuanan, WITHOUT any quotation. Something like this.

English: "previous": null, Wookiee: "akrcwohoahoohuc": whhuanan

Here is my effect

fetchMoreEntities$ = createEffect(() => {
        return this._actions$.pipe(
            ofType(EntitiesActions.fetchMoreEntities),
            concatMap((action) =>
                this._entityService
                    .fetchEntities(action.entity, '', action.page)
                    .pipe(
                        map((data) =>
                            EntitiesActions.fetchMoreEntitiesSuccess({
                                entities: data.results || data.rcwochuanaoc,
                                nextPage: data.next || data.whwokao,
                            })
                        ),
                        catchError((error) =>
                            of(
                                EntitiesActions.fetchMoreEntitiesFailure({
                                    error,
                                })
                            )
                        )
                    )
            )
        );
    });

Now the problem is, when I call this API which starts with page 1, the property akrcwohoahoohuc value is whhuanan and it throws me an error saying it Unexpected token etc... which is correct because it has no quotation. It always goes to catchError.

I already add the regex to manually add a quotation in whhuanan, but I'm having a hard time figuring out where do I put this logic since it always goes to catchError. I tried to put it inside the map but does not work HELP. Anyone there that already encountered this please help me.

Here is my regex const fixedResponse = invalidResponse.replace(/(whhuanan)/g, '"$1"');

gitalvininfo avatar May 22 '23 09:05 gitalvininfo

Whoever encounter this same issue of mine, make sure your service method looks like this

getStupidEntity() {
    return this._http.get('https://swapi.py4e.com/api/planets/?page=1&format=wookiee', { responseType: 'text' });
  }

Add { responseType: 'text' } option. After that the response will be a text and now you can add quotation on the property "akrcwohoahoohuc": whhuanan, which does not have a quotation.

const fixedResponse = data.replace(/(whhuanan)/g, '"$1"'); const finalResult = JSON.parse(fixedResponse)

My whole code looks like this

Effect

loadEntities$ = createEffect(() => {
        return this.actions$.pipe(
            ofType(EntityActions.loadEntity),
            switchMap(() =>
                this._entityService.getEntities().pipe(
                    map((data: any) => {
                        const fixedResponse = data.replace(/(whhuanan)/g, '"$1"');
                        return EntityActions.loadEntitySuccess({ entities: JSON.parse(fixedResponse) })
                    }),
                    catchError((error) => {
                        console.error(error)
                        return of(EntityActions.loadEntityFailure({ error }))
                    })
                )
            )
        )
    }
    )

Service

getStupidEntity() {
    return this._http.get('https://swapi.py4e.com/api/planets/?page=1&format=wookiee', { responseType: 'text' });
  }

gitalvininfo avatar May 22 '23 12:05 gitalvininfo