swapi
swapi copied to clipboard
Searching using the Wookiee encoding can produce invalid JSON
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.
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.
Shouldn't null
just not be rendered as whhuanan
instead?
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
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"');
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' });
}