Last active
November 21, 2024 03:38
-
-
Save sfboss/a77fe817291d3b1306c7841a552c4df6 to your computer and use it in GitHub Desktop.
ksenia_gist
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| List<DWS_API__c> dwsList = [SELECT Id, fromDate__c, toDate__c, apiToken__c, privateToken__c, expirationDate__c FROM DWS_API__c LIMIT 1]; | |
| DWS_API__c dws = dwsList[0]; | |
| System.debug (dws); | |
| String apiToken = dws.apiToken__c; | |
| String privateToken = dws.privateToken__c; | |
| HttpRequest req = new HttpRequest(); | |
| req.setEndpoint('https://ws.dws.utah.gov/uwapi/rest/va/token'); | |
| req.setMethod('PUT'); | |
| req.setHeader('Content-Type', 'application/json'); | |
| req.setHeader('Content-Length', '0'); | |
| req.setHeader('apiToken', privateToken); | |
| req.setHeader('privateToken', apiToken); | |
| Http http = new Http(); | |
| HTTPResponse res = http.send(req); | |
| System.debug(res.getBody()); | |
| /* | |
| Hello, | |
| For this endpoint, we have tried to send apiToken and privateToken (and combinations of single tokens) and consistently get a 200 (success) misleading response and then either an "invalid token" or "additional token invalid" | |
| For what it's worth the additional token error gives a "2" status back from your api, and the other description without additional gives a "10". | |
| At this point we need to confirm when refreshToken method runs, what should the headers be and which tokens is it expecting if not "apiToken" and/or "privateToken"? | |
| e | |
| Thanks! | |
| endpoint: https://ws.dws.utah.gov/uwapi/rest/va/token | |
| we added headers for content-type, content-length, apiToken, privateToken | |
| the request body is empty | |
| Reference: | |
| REST standard ResponseCode | |
| 200 - Success - out outbound request was successful "Made it out of the buildng/Salesforce" | |
| 400 - Bad Request - something wrong with the request we sent | |
| 401 - Unauthorized - wrong credentials | |
| 403 - Forbidden | |
| 404 - Not Found | |
| 405 - Method Not Allowed - wrong method used (GET,PUT,POST,DELETE) | |
| 406 - Not Acceptable | |
| 500 - Internal Server Error - error on THEIR server, request made it successfully though | |
| Recap: | |
| Problem - The integration between Utah and Veterans was having token expiration issues. | |
| The API is configured to use an expiring API key that is refreshed monthly via providing the apiKey and a privateToken | |
| The original error in the logs indicates that we are getting out of Salesforce with our integration attempt and their system is responding to us that the token in our header is invalid. | |
| No API Specs available from veterans, going off of reverse engineering working setups | |
| The normal token to integrate seems to work fine and the refresh process is what has problems | |
| Worked with Ksenia to troubleshoot the code, and reviewed the callout, how it sets headers and the endpoint, and how it handles the response | |
| Explained the JSON payloads that we either send them as a setBody() value of HttpRequest ("Request") or what we receive as a getBody() value of HttpResponse ("Response").. for our token expiration endpoint the request body is empty and the headers seem to need to contain the tokens | |
| We are getting a 200 response from the endpoint, but the response body is indicating that the token is invalid | |
| We need to confirm when refreshToken method runs, what should the headers be and which tokens is it expecting if not "apiToken" and/or "privateToken"? | |
| Confirm request body should be empty and all info for refreshing sent through headers | |
| Confirm if the tokens need to be base64 encoded or not like in basic auth | |
| We need to confirm the token expiration date and how to handle it in the code to make it hands off for the dev | |
| The API when it responds with the 200 also sends a custom status code in the response body that indicates the token is invalid, we need to confirm what the status codes are and what they mean, and veterans needs to provide this since it isnt in the documentation or part of REST standards. | |
| With Rest standards, we know that a 200 is a success, but the response body is what tells us if the request was successful or not, and the response body is what we need to parse to determine if the token is invalid or not | |
| We looked at JSON2APEX to see if we could generate a class to parse the response body, but we need to know what the response body will look like to do that correctly, but showed TokenWrapper class as an example of how to parse JSON in Apex so that the JSON string deseriaizes into a class that we can use in Apex. | |
| "Valid" json has to have these characteristics: | |
| - Starts with { or [. | |
| - Ends with } or ]. | |
| - Contains key-value pairs separated by a colon (:). | |
| - Key-value pairs are separated by commas (,). | |
| - Keys must be strings enclosed in double quotes ("). | |
| - Values can be: | |
| - Strings enclosed in double quotes ("). | |
| - Numbers (integer or floating-point). | |
| - Booleans (true or false). | |
| - Arrays (enclosed in square brackets []). | |
| - Objects (enclosed in curly braces {}). | |
| - null. | |
| - Arrays can contain any combination of valid JSON values. | |
| - Objects can contain nested objects and arrays. | |
| - Here is an example of valid JSON: | |
| { | |
| "name": "John", | |
| "age": 30, | |
| "isStudent": false, | |
| "courses": ["Math", "Science"], | |
| "address": { | |
| "street": "123 Main St", | |
| "city": "Anytown" | |
| }, | |
| "grades": null | |
| } | |
| */ | |
| ------ | |
| - In apex the Map<String, Object> is the closest thing to a JSON object, and the List<Object> is the closest thing to a JSON array | |
| - Field/Value pairs make up the JSON object, and a salesforce field and its value inside of curly braces is hypothetically something that can be a map<String, Object> in apex, and a list of these objects is a list<Object> in apex | |
| - The JSON string is the string that is returned from the API, and we need to parse it into a map<String, Object> or a list<Object> to be able to use it in Apex only if we can't properly deserialize it into a class that we define in Apex which is much preffered and is referred to as it being "Typed" | |
| - The code is a bit old and antiquated being used for the integration, and there is no reason to use the CalloutUtils and all those other classes when httpRequest works just fine for the integration, and the code is much simpler and easier to read and understand | |
| - We troubleshot the logs and looked for the HttpRequest and HttpResponse objects to see what was being sent and received, and we saw that the response body was indicating that the token was invalid, and we need to confirm what the status codes are and what they mean, and veterans needs to provide this since it isnt in the documentation or part of REST standards. | |
| - Some typical things to make it so you can avoid digging into the logs are to post the response to slack or something or just surface the info on the integration attempt every time as a log | |
| - other considerations: | |
| - if possible using OAUTH2.0 would be much better than using the tokens, and the "clientid" and "clientsecret" would be used to authenticate the integration and get the refreshed token which Named Credentials will do automatically for you and is the modern way to do it (Very future state) | |
| Finally, | |
| This is difficult to get to be efficient with and you did awesome today for being scatter brained. Concentrate on the REST standards and documenting APIs with things like Swagger, and you will have a base of knowledge to be conversational. It will take time though and has a lot of nuance. | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment