#We're making a wrapper over the Discord API using Java!!
1 messages Β· Page 1 of 1 (latest)
*There are 3 main libraries that exist for Java: *
- JDA
This is the main defacto library for most people looking to make bots in Java. The problem with JDA is its codebase and user experience.
As users of JDA we have had issues with JDA not handling errors properly. An example of this is the recent bug fix we did. When you do simple functions like channel.getMessageHistory() this will return 0 messages. That's because it doesn't load them. You have to request channel messages a different way. Is this clearly documented? Nope.
What about the difference between User, Author, Member? These are discord terms and as a wrapper, we're supposed to simplify this. JDA does not.
Here's a code snippet from the recent issue we had with TJ-Bot, they don't even return errors to the end user so they're left in the dark:
handle.exceptionally(ex -> {
WebSocketClient.LOG.error("Encountered exception trying to handle member chunk response", ex);
result.completeExceptionally(ex);
return null;
});```
2. **Javacord**
This is a bit better than JDA and has a similar coding style to JDA but better. It lacks detailed documentations and has limitations to what it supports (from what I have heard). It's hardly maintained. There's so many open issues on the GH and PRs that have been around for over a year. Some of these PRs even show the lack of functionality that Javacord has. It has some verbosity to its development style e.g. `addServerVoiceChannelMemberLeaveListener`.
3.** Discord4J**
These guys are try-hards and have over complicated the user facing code. It's not beginner friendly so there's a steep learning curve. Take the following example code:
```java
gateway.on(MessageCreateEvent.class).subscribe(event -> {
Message message = event.getMessage();
if ("!ping".equals(message.getContent())) {
MessageChannel channel = message.getChannel().block();
channel.createMessage("Pong!").block();
}
});
Yeah...
While it's coded superior to JDA and Javacord, it's not worth using because you're not going to have fun with development.
Now that this is out of the way, why are we doing it?
Few reasons:
- We never really get to work on architecturally challenging projects. Neither here or in most work environments. This will be a great learning experience, even for some of us experts.
- To have a deeper understanding of the Discord API.
- To write a library that's not as trash as JDA or complicated like Discord4J
- Maybe we'll get sponsored by Discord (they are known to give out $30k to projects like this)
- It'll be great out reach for TogetherJava. A community project by our community experts is great and we should get some good traffic.
If the "why" isn't convincing, just take it as a learning project that has a cool product at the end of it!
@oak flare you wanted issues right? π https://github.com/javadiscord/java-discord-api/issues/1
I liked this coz we're doing annotations style library
Which I really like
Also I wouldn't want it to be associated with tj
Doesn't have to be
i've never heard about the 30k sponsor tho, did other 3 major java libs got that?
I did it under the javadiscord org because I own javadiscord.com so I think that it would have good SEO? We can use whatever name we decide 
for those wondering what Taz means by this: ```java
import com.javadiscord.jdi.core.Discord;
import com.javadiscord.jdi.core.annotations.ChannelCreate;
import com.javadiscord.jdi.core.annotations.EventListener;
import com.javadiscord.jdi.internal.models.channel.Channel;
@EventListener
public class ExampleListener {
@ChannelCreate
public void exampleChannelCreate(Channel channel) {
System.out.printf("Channel created: %s", channel.name());
}
@ChannelCreate
public void exampleChannelCreate(Channel channel, Discord discord) {
if (channel.name().equals("gaming")) {
// discord.getGuild(channel.guildId())
// .getChannel(channel.id())
// .sendMessage("Hello, World!");
}
}
@MessageCreate
public void exampleMessageCreate(Message message) {
Database.save(message);
}
}
Now there's a immediate issue with doing this pattern. For all the events, how will users know which parameter types they will need? They would have to refer to the documentation or Javadocs for the annotation itself.
But I think it's a good idea to also support the normal traditional way of using an interface for that caveat but still focus more on the annotation processing
I've only seen JDA get it and some JavaScript lib
I have a really good way to get immediate visibility with discord though so there's always a chance :p - if we ever did get sponsored, bet you're all getting a share
is it possible to do both?
yeah why not?
the annotation processing is pretty much going to be a wrapper over: ```java
List<Listener> listener;
void add(Listener l) {
listeners.add(l);
}
for fun, I also created a board for something more visual
Whenever we get issues, they'll show up in the backlog. Once they're refined, they can go into the "Ready" column for any contributor to pickup! π
going to check tomorrow :D
kinda burned out today
is this too ugly?
np squid π
mmm no it's not that bad
other option is to have a class for each type of request
but thats too much repetition
repetition isn't good - I already have some "accidental" repetition with the EventDecoder
it's a quick fix for the EventDecoder but I think for now i'll leave it because it's designed like that for flexibility
@light loom is setting to response necessary after we've logged it already?
ig we shoould write this in java 22
i have no idea of what you are doing but this sound like a really, really bad idea
wazei did that
y is it bad tho
well the sendRequest method doesnt throw
idk what we're catching
Then the only thing it could catch would be a NPE if queue is null lol
Interrupted exception
idk how that works
ohh
and please don't ignore exceptions
we cant just add thorws
the method signature will change
this is a Runnable class
so just log it?
depends of the context
what is the meaning of this exception ?
- critical bug ? -> crash
- minor bug ? -> either crash or log error
- logic ? -> then what the logic said
we should use java 22 preview for strings
so i've basically rewrote entire api package
infinitely scalable 
just need to fix the code i broke
fk it lets just write everything in kotlin
kotlin better anyways
y did u not push the gradle folder
It's to provide callback to the caller
too bad i removed it
Then how will the caller know the request failed?
Imagine this flow:
- You call channel.sendMessage
- No errors in console
- No message sent in discord
"This library is broken"
This isn't good advice here, that class is critical, if it fails, that's your entire bot offline - we need to at the least log it
And we don't watch a separate block for all the possible exception variations, there's no point in doing :
} catch(InteruptedException) {
...
} catch(IOException) {
...
} catch (NullPointerExeption) {
}```
but theres error log in console
in jda as well we dont get any error back its just gets logged in console
Yeah but when this is running in a server, you won't see the logs
We want to propogate errors to be handled by the end user otherwise they can't handle it
ok ill add it bac
Imagine this scenario:
- User creates a slash commands to send a message to a channel
- The user in server uses that command but passes invalid channel id
- Bot fails to make the request because channel id does not exist
Now they need to know that a failure happened so they can respond to the slash commands with an error
see the logs in server
Remember, this was the exact issue we faced with the MemberChunk, JDA was just logging the errors, we didn't know why and just got an ugly exception. We ended up looking through JDA code to figure out what we need to do
how will sending the error back help?
They can handle it or at least know how to fix the problem, at the least we can provide meaningful exceptions back to them
ok
Oops π
Ok cool idea but if motivation is sponsorship then idk if this will work out
who said motivation is sponsorship
i didn't even knew that was a thing
can wazei clearly said motivation is learning
It is
So first, multicatch exist
Second, you do not want to catch bugs and behave like nothing happened
Third, You are literally catching and doing nothing
Fourth, if what you say is true, then you would put catch everywhere in your program, all of methods, which is bs
Fifth, I specifically said for minor bugs, just log them, which is something you seem to talk about here
i was debating myself over this, but it makes sense its not like we have 2 or more apis
ah wait - yeah taz did it correctly
:c
I didn't notice I was using a Exception to catch an InterruptedException
because further down we do ```java
} catch (Exception e) {
LOGGER.error("Failed to send request to {}{}", BASE_URL, request.getUri(), e);
request.getFuture().setException(e);
}
In this example, we can't handle the error ourselves. We don't want to throw the exception because we don't want to kill applications by accident. So we leave it to the caller to deal with it (enduser)
i was debating myself over this as well, but that'll kill the syntax
as u pointed out in ur comment it looks very neat like this
except the nulls but cant do anything about that in j ava
lets use kotlin
hm, so how would it look like with a builder? ```java
DiscordRequest request = DiscordRequest
.builder()
.get()
.setURL("/channels/%s/invites".formatted(channelId))
.setHeader(..)
.setBody(Map.of(...))
.build();
do u have any better name Future is wrong
DiscordResponse?
except the maps are multiline
can u add a field in discord response to hold the exception
or do u want a wrapper
I think we'll need a wrapper
before, Future was that wrapper
This part of the code is for us internal maintainers and would be abstracted away for the enduser anyway, so I'm not too bothered on the naming
Thinking about it, we're compromising on readability for a "clean" syntax π
I suppose we should do the builder, multiple constructors isn't flexible long-term
I'll let you decide π
DiscordRequest request = DiscordRequest
.builder()
.setURL("/channels/%s/invites".formatted(channelId))
.setHeader(
Map.of(
"Content-type", "application/json",
"style", 2
)
)
.setBody(
Map.of(
"names", names,
"ids", ids
)
)
.build();
i can probably get rid of the header part
coz headers aren't used much in discord api
so we have 1 less constructor
I think that works
if only java allowed literal objects in parameters lol
then we would have done: ```java
.setHeaders({
key: value,
key: value
});
but it's okay π
lets use kotlin
trust me after u learn kotlin java looks dog water
how hard would it be to switch it to a kotlin project in the future?
changing the whole codebase to kotlin?
depends on how big it gets
adding support for kotlin+java is very easy
just some gradle config
A populair project in a whileπ
I'll think about it - for now let's continue with Java π
bruh 
then what to call the current DiscordResponse?
The discord object π
Discord is going to be the proxy between your stuff and the user
no u said to name the wrapper DiscordResponse, but i already have a class DiscordResponse
I misunderstood what you asked
I just re-read, I still think I misunderstood lol
peeps! I finished decoding all the gateway events 
Also introduced imposter mocks, this will let us use the discord openapi spec to write integration tests against a stubbed API
There are valid use cases of doing this
That's what I said...
uh you sure?
.
and as a rules of thumbs
unless you know what you are doing
don't catch it
well thats not related to your "dont catch the class Exception"
nor throwable
99.9 % of cases it's people not knowing what to do
would you say people working on this not know what they are doing?
then there is the 0.01% where you catch it in your main loop so you don't crash the whole server
well yes, unless you call this knowing what you are doing
catch(Exception ignored) {}
Because for this specific code, there is no reason, no use case for this
well I dont have context to this discussion, just relating to this
We're all adequate developers here so let's not get caught up on it
any mistakes are going to be accidental or intentionally done a certain way
ok i'll push it u can check if its fine
@light loom this is y i dont like spotless
@shy notch would you say this user story covers what you were asking about?
yeah our feature requests are done via user stories π π
@orchid portal can you review? https://github.com/javadiscord/java-discord-api/pull/19
i didn't forget the co-authored-by
y do u call this future
thers nothing future about it
what is this
stop the spotless
@light loom am i blind or does ur builder doesnt have a build method
this makes no sense what r u doing
why do u guys do CRs on discord instead of just on github?
also, u have to work a bit on ur attitude when u do CRs. imo ur wording is hostile and not really welcoming
ur DiscordRequest is making a lot of assumptions which i dont think is correct (i haven't read the entire discord api, nor have u so dont make wild assumptions)
hes fine w/ it
ur messages, if posted here, are also read by ur future potential new contributes. who, when seeing that, will rather turn around and not start contributing
i couldn't find a better name for it π¦
no i mean make it a builder
add the build method
ah I think I know what you mean
it's a future because the response comes back later
why not using javas future?
its not a future
thats what im saying
it'll trip anyone
why is it not a future
into relating it with javas future
basically, when we send a request
I return a DiscordResponseFuture
that contains the result which you can access via onSuccess
I use callbacks because the request isn't executed immedately
but let's talk about it on GH because Zabu has made a really good point, we don't want to scare away contributors by sounding really harsh
yea we've alreay scared chris enough
i'll be less active in next few days
do whatever u like, i'll check later
also if u dont want to make it a real builder dont name it a builder
ig thats what u want
I guess it depends how strict you take the word "builder" to be explicitly only for the builder pattern
But yeah I added my responses to the comments π
@light loom ig we have different vision for DiscordRequestBuilder
i'd also want to have HttpRequest formRequest(...) inside it
it's a small detail, the important thing is: "can it be maintained?" - I think so because all the java http logic is in 1 place rather than in 2 places. let's see how it pans out - we can always refactor and improve if it really does become a problem
but, this PR now means we can start implementing all of what discords REST API provides π
also ur body is always a string
i know i know with file uploads, this is a problem
ye
i haven't looked at the file upload part of their api properly so am not sure what it involves. since it's just 1 method, it's single place refactor to make it work for file uploads when we work on that
with a few changes ur code can be very extensible
yep, that's what it means to have good code, easy to refactor without breaking loads of places β€οΈ
the refactoring is so small we can do it when we need it - right now i just want us to be in a postion to be able to start progressing
make the body BodyPublisher
and also use enum for methods
its very sketchy to use to uppercase and stuff
let's have the discussion in GH because we'll have trackable conversations on all our decisions
so when somebody looks at the code and asks "why", they can just refer themselves to the PR at a click of a button and see everything
thanks taz 
@light loom r u not writing the code in ide
i am ofc
u just pushed a code which doesn't compile
oops!
blame spotless i swear
it keeps changing my line encodings randomly between each run. first it sets it to LF then 5 mins later it sets it to CLRF so all my files show up as modified
dont use spotless
spotless is for projects with beginners anyways
we can format our own code
nooo
the reason i have it is because we all have different personal formatting styles so with spotless its unopinionated formatting
no rush - we can do this any time
this is kind of a work around of what i suggested
add 2 methods setSucessResult and setFailureError
we have those already in the response future
in DiscordResponseBuilder
this might become a discussion can you post it on the pr?
tomorow, shadow me at work - i'll be reviewing some PRs and want to walk you though the process
I'll stream it in the VC or something, I think it's important to see how a PR should be reviewed. We do PRs wrongly on TJ-Bot too so it might be something I might write up for a mod to review. Ideally, it shouldn't be an opinonated discussion were the developer is rewriting code to how a reviewer would have wrote it. I am not saying this is something you're doing right now, but it's good to share that knowledge with everyone else
if i'll be able to
I'll do a write up at the the least π
@light loom what does 15 mean here?
the ticket number π
it's a test i was doing, when using stuff like Jira, you would put the ticket number in the commit so it shows up the board
i'm not sure if it works with the GH board but I was testing it with these commits,
it doesn't π¦
maybe if u do #15
there's no ui for it lol
just the branch - but i had to manually link the branch too
even though GH gives a branch name template, it doesn't automatically link it
in the description u have to say "fixes #15"
it's on the sidebar of the PR
the sidebar of a PR also does not link correctly with the board
the "projects" section is kinda out of sync lol
but at least the development part came up automatically
...and u pushed non compiling code again
u sure?
ty for the approval 
Is the revamp by taz finished btw? So I can start looking into some of the issues?
he might be making a few tweaks but the code is all free for you squid
check out the "Ready" column, the stuff with "No Status" is something that needs refinment which you're also happy to do
just bang whatever you pick up into progress so nobody else accidently starts on the same thing as you
(issue we've had in TJ bot so I'm hoping the board view will make this more visible)
ah nice
all the major stuff is done
is it on main branch already?
yes
Yes
I created some more issues for the ready column, hopefully there will be loads of tickets that people can pick up and start working on straight away
Including some spike tickets, testing tickets, dev tickets so a good range
looks so professional :3
apart from the 0 tickets in progress π π but that's expected rn :p
You actually bought the valo thingy 
i want to reorder everything in DiscordRequestBuilder but then it'll be a big pr for no reason
we need to sort this out
check out my draft pr
discord API takes optional fields for example which might be messy logic
for example:
https://github.com/javadiscord/java-discord-api/pull/38/files#diff-abfbacc7a9d385971084260093a2605599eac0bba0dfe3cea2c7da39a9037b34 and this where you're only allowed 1 specific param and not the other
and y is that a problem?
ohh got it
so in jia i actually make 2 contructors
and that was a normal class
but my design is very different and more sophisticated than urs
any http request in the world can be implemented without any change to the core code
wish i never archived the project π’
I suppose we could just directly create the request using java http instead of discordrequest/discordrequestbuilder
that would be the most powerful/flexible "here take the entire http library mr discord request"
@orchid portal I didn't realize you raised a PR
I added this to my current WIP: https://github.com/javadiscord/java-discord-api/pull/38/commits/b13c20c51597895ad243ff0c15cb789ed2b5107c
should we work on yours and i can rebase?
yes mine is smaller as well
I suppose the main difference in my PR is:
protected String getQueryParameters() {
StringBuilder encodedParams = new StringBuilder();
for (Map.Entry<String, Object> entry : queryParameters.entrySet()) {
if (encodedParams.isEmpty()) {
encodedParams.append("?");
} else {
encodedParams.append("&");
}
encodedParams.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8));
encodedParams.append("=");
encodedParams.append(
URLEncoder.encode(String.valueOf(entry.getValue()), StandardCharsets.UTF_8));
}
return encodedParams.toString();
}
and you've added to sendRequest
String parameters = "?";
if (discordRequestBuilder.getParameters() != null
&& !discordRequestBuilder.getParameters().isEmpty()) {
parameters =
discordRequestBuilder.getParameters().entrySet().stream()
.map(
entry ->
entry.getKey()
+ "="
+ URLEncoder.encode(
entry.getValue().toString(),
StandardCharsets.UTF_8))
.collect(Collectors.joining("&"));
}
how would you like it done? we can use mine or we can fix up your PR? we have different approaches to the same effect - i think mines a bit more cleaner?
this is my implementation rn as well for the optional fields :S :S
i couldn't think of a cleaner way
in CreateMessage API all fields are optional 
Scared to use builder pattern for some of these.
this looks awesome!
is this for JDK 21?
At the moment it's targeted at 21 but once we're done, I'll make a Java 8 version too
for java 21 use virtual threads
for java 8 use quasar
ultimate performance π
uhh, this is a library
discord bot requests usually are async
No they're not
Unless you mean async as in they get executed in the future, then yes
yes they are
We don't want to send them async from each other otherwise you'll get messed up by the rate limit
In our current system, we can perform the actual request itself async but as long as the queuing mechanism isn't changed
@light loom i see in models u skiped some fields
y is that
also if a request response with partial guild should i just parse it into guild or make another model for PartialGuild
ig this will be everywhere
@JsonIgnoreUnknown is set on all the models already so any partial objects will parse
So use the main guild object, the reason is that we'll keep a track of all the objects in the future caching work
and whenever we receive an object, we'll update the cache and populate any missing fields that way
after a few different requests, the cache will contain "complete" objects
but primarily, what we'll most likely do is on startup, request everything to initialize the cache and then any other response we get will just be adding/updating the cache
might of been by accident or the docs didn't mention it in the bits i was looking, just update them to include those fields that are missing
Ok
need help. i run imposter by docker and map the mocks folder to /opt/imposter/config, but i face problem like below
how r u running this
are you in the /mocks directory?
you need to run imposter up in the same directory as the imposter-config.yaml and openapi-spec.json
(fyi, the maintainer of imposter is one of my collegues!)
the only maintainer or one of the maintainers?
he's the only but we use imposter heavily at government so we're all "maintainer-like"
but there's no issues with imposter, it's battle tested at government π
only make the models from where they're defined https://discord.com/developers/docs/resources/guild#guild-object-guild-structure
do i run properly
nice! if you're using that url from localhost it's all setup
you can test each of the endpoints using postman or cURL or something
are you interested in writing integration tests for us @sinful snow ? 
of course I can help you if you're interested in doing that, you can also have a go at any of the ready tickets posted here: https://github.com/orgs/javadiscord/projects/1/views/2
unit tests might be an easy one because integration tests are a little harder
already running into limitations
yeah I was too with the /channel endpoints
need to add requests with files
yeah I think files is the only limitation at the moment, feel free to refactor and improve to support it
hmm, ig i'll make multiple small prs rather than a big one so u can work on other apis
lets reverify all models just in case
do you mean like this
try it
yeey :D
we suck :c
which means you can't do integration testing to the fullest just yet π¦
but you can still create the initial framework for it
what do you mean framework
i.e. bootstrapping imposter, https://docs.imposter.sh/embed_jvm/
and getting mockito, junit etc ready
we don't need docker for the tests, they have a maven dependency
Nah i use window os so i try to run with docker
yeah the docker image is for running locally but we shouldn't start docker in the code when the tests run
y not 
OpenApiMockEngine imposter = new OpenApiImposterBuilder<>()
.withSpecificationFile(specFile)
.startBlocking();
because that's all we need
URL mockEndpoint = imposter.getBaseUrl(); for the URL that we pass to our code
in discord its bitrate but u did bitRate should i fix it or jackson will figure it out? @light loom
oh i see
oops - change it please
@light loom also instead of storing snowflakes as long can we use string?
idk long makes it seems like we can do arethmetics on it
fair point but they're just IDs from the looks of it, I don't see the value of making it a string, we get better performance using a long
i think it's better to enforce types but let's see how it pans out
when read this codebase, what anything i should consider first to undestand how it operate
i thought the same but wasn't able to find any other
ig ur not implementing the models from their definition
1 second
okay it's mixed
that ThreadMember is actually coming from a gateway event
when a member joins/leaves a thread, the websocket sends that object
so we should maybe distinguish gateway objects and api objects
some of the objects are the same though - so if you see anything that's different then consider renaming or repackaging
all the gateway stuff happens here
maybe we can move the gateway models here
i.e. events/codec/models or similar
and also change name?
otherwise the names will clash
i see ThreadMember is getting used in ThreadMemberUpdate
ohh ok its a gateway model as well
so ig not changing name will be fine
hmm this is more hard than i thought
i'll just implement all the models while im at it
bro how do i store timestamp
bro u have so many
Instant
i want to deserlize ISO8601 timestamp using jackson
ah
Then use JsonFormat annotation
yea just found a bealdung article about it
@sharp ferry what the type should be?
Depends of what you want
LocalDateTime?
OffsetDateTime since ISO8601 has a offset
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
is pattern correct?
I was trying to hard faff around with timestamps that I gave up in the end and just left it as string 
wait fr?
thats not good
yeah 
I was gonna add it as tech debt to do look into it later - but if you're in the space it might be worth revisting and doing it properly
Try and see I guess
Is there any contributing guidelines ? Kinda bored and looking to contribute
yess
@plain ledge if u make a model make it full
Yes sir
I was gonna work on it on the plane but I forgot how to connect to the wifi on arch Linux
Iβm a fake arch user
lol
nmcli d wifi show
nmcli d wifi connect ssid password
theres not really anything arch linux about this
these command are same for any distro
u just dont know a cli tool
which is normal
use nmcli help
and find ur way through
thats how u learn
NetworkManager: π
What should I do about optional values in requests, ignore the fact they are optional or what, would it be preferred to create multiple contructors in that case or what
I've been using Optional!
Take a look at my draft PR for some ideas
The idea in the future is to have another wrapper over the classes we create e.g. builder methods or whatever and do something like that but we'll figure it out together when the time comes
If there's a weird API let us know, at the moment we have some limitations at the moment such as handling files but we're getting there
Ok so there will be wrappers over stuff like integers that should be represented to the user as an enum
Wym?
I mean for all the fields that are optional, you can use Optional<Integer> for example if the optional field is an int
The wrapper will be like :
discord.someAction(param, param);
discord.someAction(param, param, optional, optional);
Like PrivacyLevel for stages, they are 0, 1
There is already an enum but for implementing the request records should I use that or an int
Use int
ππ
The wrapper we create (on top of your code) will use the enum or class it needs
At the moment, we're working at the lowest level of the API we'll need to create a higher level interface for the end users
Wait Optionalβs work with jackson?
Here's an example of how I did it for one of the requests
This is my draft PR for some of the other channel endpoints
It's draft because it's work in progress
But essentially, it's just a record that's implementing DiscordRequest
Here's another example:
package com.javadiscord.jdi.internal.api.impl.channel;
import com.javadiscord.jdi.internal.api.DiscordRequest;
import com.javadiscord.jdi.internal.api.DiscordRequestBuilder;
import java.util.Optional;
import java.util.stream.Stream;
public record FetchChannelMessagesRequest(
long channelId,
Optional<Long> around,
Optional<Long> before,
Optional<Long> after,
int limit)
implements DiscordRequest {
public FetchChannelMessagesRequest {
if (Stream.of(around, before, after).filter(Optional::isPresent).count() > 1) {
throw new IllegalArgumentException(
"Only one of the values 'around', 'before', or 'after' should be set.");
}
}
@Override
public DiscordRequestBuilder create() {
DiscordRequestBuilder requestBuilder = new DiscordRequestBuilder();
requestBuilder.get();
around.ifPresent(val -> requestBuilder.queryParam("around", val));
before.ifPresent(val -> requestBuilder.queryParam("before", val));
after.ifPresent(val -> requestBuilder.queryParam("after", val));
around.ifPresent(val -> requestBuilder.queryParam("around", val));
requestBuilder.queryParam("limit", limit);
requestBuilder.url("/channels/%s".formatted(channelId));
return requestBuilder;
}
}```
annotate nullable
omg bro
Alright last question, Iβve just about finished up stage requests. Is there anything I need to do for gateway events
i'd insult u but ur a senior
so i wont
Should I be doing that for models?
no models are fine
dont do anything in models
Ok
thats for constructors
@orchid portal
Just an example, not actual implementation
no idea
Woah quick?
i've barely seen any code outside api and models
It was 4 requests
well stage has like 4 requests and 2 structures
Iβm at airport 4 hours early
π
Any way to download the discord api docs locally
Open the website, I think it's just 1 single page?
But there's also the openapi spec you can try follow
its nto
Yeah
^ dont
Btw EventHandlerCodec:218 something doesnβt look right
Good catch!!
@JsonProperty("removed_member_ids") long[] removedMemberIds) {}
I'm heading to sleep, cya peeps 
yea i'll sleep too
but use list
not array
idk if array will even work
Finished the discord scheduled events endpoints, in the package with endpoints I named it scheduledevents, would there be a better name for that
Raise the PR and we can check π
Done, I opened both PR's for 30 and 31
I think I left a couple comments in the code which I need to remove but need some feedback on those (I will remove those before merge)
Ty I'll review them once I'm out of bed and get time 
ok wazie
well wazai lets talk about using optional
@light loom ok wazie what to do if a model is used both in codec and api
ThreadMetadata
if it's the same, share it
sure
the other solution would be to use the builder pattern
but we are gaining nothing, we don't gain extra readability or flexibility
y not just annotate will nullable and handle it as null
where to put it tho?
hmm
maybe we should have a different object
thinking about it, it might be weird to start coupling shared objects because if one sided changes then you mess up the other
intent, we want to express optionality
I reviewed your PRs peeps
@plain ledge your stage API is OK - your scheduled events needs tiny changes
@orchid portal pre-commit please and can you check #44 to help Nopox since you touched dates
Want me to switch stuff to nullable?
It does make the code more ugly
Optionals are nice to handle with the ifPresent
Gimme that time format Taz
see my pr
im shitpositng in chitchat
cant do code rn
OffsetDateTime joinedAt,
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
is it that?
yes
also test it if u can
I got no idea how to test
lol then dont
I am attempting to implement a second constructor for ModifyScheduledEventRequest
public ModifyScheduledEventRequest(
String guildId,
String scheduledEventId,
EntityMetadata entityMetadata,
Optional<String> name,
Optional<Integer> privacyLevel,
Optional<Long> scheduledStartTime,
Long scheduledEndTime,
Optional<String> description,
Optional<Integer> status,
Optional<String> image
) {
now when I do, not sure what to pass in when calling super for channelId (Optional<Long> in primary constructor), I need it to put it in th body as null and not ignore it , should I just pass in Optional.of(-1L) and then just check if its -1 and replace it with null in the create function
public record ModifyScheduledEventRequest(
String guildId,
String scheduledEventId,
Optional<Long> channelId,
Optional<EntityMetadata> entityMetadata,
Optional<String> name,
Optional<Integer> privacyLevel,
Optional<Long> scheduledStartTime,
Optional<Long> scheduledEndTime,
Optional<String> description,
Optional<Integer> entityType,
Optional<Integer> status,
Optional<String> image)
implements DiscordRequest {
@Override
public DiscordRequestBuilder create() {
Map<String, Object> body = new HashMap<>();
// check if entityType = 3 (EXTERNAL)
// channelId must be set to null
// entityMetadata (entity_metadata), scheduledEndTime are all required
if (entityType.isPresent() && entityType.get() == 3) {
if (entityMetadata.isEmpty() || scheduledEndTime.isEmpty()) {
// TODO: replace with custom exceptions when implemented
throw new IllegalArgumentException(
"When entityType is EXTERNAL, both entityMetadata and scheduledEndTime must"
+ " be provided");
}
body.put("channel_id", null);
} else {
channelId.ifPresent(val -> body.put("channel_id", val));
}```
I am trying to replace that validation check as requested
I'll go through this later with you π
@light loom dont merge the models pr
i haven't looked at other packages
also i ended up putting common models in models
otherwise it'll be too much duplication
guild package is kinda big
the models pr is done
i went through all the packages
just a last few things are left
im not gonna implement all the models nor complete all the models
but i'll leave a note on them so its less of a headache for the next dev
Ty tomorrow is my working on this project day, so I'll go through everything and continue with the APIs
and i can finally start wroking on user api
sorry I said I am going to do stuff on this project but I currently need to focus on finals 
No worries squid, focus on your school and don't think about this project
pr is ready to merge
ig we all have it on low prio anyways
Merged your stage request contribution @plain ledge 
We can talk about what's needed to get the schedule endpoints over the line today if you get some time 
I'm bouta go to bed π
This was just the question I had, I was asked to convert that validation to a dif constructor
ooh it's late deffo later π - or if you don't mind - I can comit changes directly to your branch and we can talk about the changes i've made once you're available again?
sure
I'll be on tmr mroning since weekend

approved 
implementing these APIs is so freaking long
peeps let's discuss this while we're working on the endpoints
tru
y cant ai do this
ai sux
ikr π¦
looking into it now @plain ledge !
okay @plain ledge look at the other comments and we can think about what to do with ModifyScheduledEventRequest when we start implementing the higher level code
I can't really think of a proper solution right now until we actually start using it
so should I remove that validation
or what
keep it
Wazei
I thought you didnβt like annotation based libraries
Or was this someone else
it was wazei ig
I don't remember, I don't think it was me?
Hey, so we have an open discussion at the moment on GH which you're happy to get involved with prior to the higher level stuff as it might influence how it's implemented, however if you want stuff to do there's loads in the Ready column, primary focus right now is getting these APIs done
Once the APIs are done, we can finally leave the discord docs alone and focus on actually making the library fantastic
@light loom can u check out that pr
You missed the constructor 
But the rest looks good, I can approve it once that's added 
Didn't we say that we weren't gonna do that for now?
.
It's a different constructor π
The if(limit > 100) one in GetScheduledEventUsersRequest
π
Yeah that's how you do constructors in records
alright fixed that
Thanks, I'm still in bed but I'll check everything again and approve + merge! 
Alright! Also it might be worth considering https://starlight.astro.build/ for docs
I've used it once or twice before and they've got very nice UI components & it's pretty easy to use (also md, maybe mdx)
What's the difference between this and docusaurus
They all look the same except the one I thought of originally is developed by Facebook and has demos
I think they are just different styles as well as come with different UI components out of the box
- it's astro :)
merged ur PR @plain ledge thank you 
there's a few small tasks somebody could pick up which is invite api, stickers, emoji and auto mod endpoints
haven't followed progress of this project
but if this is something community wants, and there are community members working on it
we can host it on our org github, and provide infra to run/test it
and if this is something that would benefit this community
we are deep into JDA with all our shit, is there a way this project helps us?
Thanks for the offer but we have everything needed from agile board and proper project management. You can see this here, https://github.com/orgs/javadiscord/projects/1/views/2
The issues are sized and since we're extensively using the board for contributions, it's very streamline
Actually yes, if we could replace JDA with our work that would be amazing, here's why:
Firstly, our community will have members that know the guts of our new framework. We also know the juts of TJ bot, what does this mean? Extremely, efficient bug fixes and better maintance. We'll know the entire codebase inside out and everything that it's using
It will be a lot of effort though
We know JDA has problems, we have seen it's internal code because we were forced to debug the actual library
It's bad and it's a big job for them to fix
Yeah it won't happen over night. The library we're making will take months
And a similar timespan moving TJ bot across
I would be interested though
I only want to migrate TJ bot if I truly feel that we have made something to truly be proud of and can provide real value that a migration is worth it
I've been tracking all our tech debt, documenting decisions etc. even planning testing (unit and integration) - at the very least we have a proper project workflow and can have assurance that we're doing our best for the best possible code
@light loom can u assign me to the 2 one's I responded to (25 and 36)
Sure thing, you wanna pick up both?
(just as a general note since u just talked about it. we have selected jda for tjbot primarily bc its popular and also likely for people to be either a useful framework to know or they might already have experience with it
there has been a long discussion and a big poll at the beginning of the project about it.
its ofc not set in stone but i want to manage expectations a bit by saying that i dont really see any other tool replacing it in the near future for multiple reasons)
I agree with you zabu, I don't see it happening either, the work is massive too
I wouldn't want us to go through that hell for the sake of "hey we should do it because we made it"
We're experts and we know when something is actually going to solve a problem, I don't see us solving a problem yet that TJ has but if we find a lot of capacity and our framework is in a really good shape, maybe one day we'll we can think about it - it's not something I'm expecting (it's just a dream of a potential future)
I don't think that it is a good idea
But very unlikely to happen at all
what counts is u guys are having fun, learning sth new perhaps and while doing that even create sth cool that others may like as well π
Neither do I
It's a learning first project, with something cool that comes out of it. If people use it, yay! If they don't, no worries, we've all gotten better at coding!
And we can always use for our own personal projects 
once ready, it can definetly be used on another tj project though. similiar to tj-plays
Yup
The auto moderation models are incomplete, should I include them in my auto moderation api pr too?
yes please! 
ok and then 1 more then @light loom , this post request requires me to pass in a https://discord.com/developers/docs/resources/auto-moderation#auto-moderation-rule-object-trigger-metadata
can I just pass it in normally or do I need to do any serialization stuff
i have to do an interview but i'll help later
Pass it in normally and follow the structure as you have been doing if you can
Ok I didnβt know if there was so thing I should he thinking about like how the Map<String, Object> for body gets serialized
Yupp
Mind if I redo the auto moderation models
sure
Last question, are we using arrays or lists?
List
Finished both those PR's lmk any changes
Tomorrow please, it's almost 1am here 
figured it out
for making the API requests we're using Java HTTP client
for the web socket communication and some of the light bootstrapping we're using vert.x
is that optional?
wym
I don't want to add vert.x if I just want to make some discord http requests
for the REST API you don't need vert.x
so if you're just ripping code out of our repo just to make discord requests, you should be okay
the moment you need to do gateway events, if you're using our code, you'll either need to use vert.x or refactor that bit of the work
ah, I was hoping for a maven release, with a split dependency thing
Or just optional dependencies on vert.x or something
I am thinking of splitting it into it's own deps
so like seperate smaller libs for gateway, api and our framework
or making it modular
did you generate the api with the openapi spec?
wym
did you manually add all the api calls?
yes
of course, we can't dynamically do this
Yo I want to contribute
Do I just scroll thru the issues and comment on which one I want to take or is there a particular process I need to go through?
open the repo go to projects tab and u'll find a very nice looking board
comment on the issue u want to work on
i'll assign u
I was finishing up stickers and I see a field called file content, I talked with the folks in the discord development server about what that was and they said itβs a multipart data thing. Do we already have an system for dealing with that, should I just leave it as a Object for nos or what
sounds like something to be handeled with gateway events?
I donβt think it is
Itβs part of a body request
Yeah Iβm just having a herd time figuring out what that is, I havenβt dealt with multipart data before
#1130595287078015027 message
ur talking about this right?
π
lemme see how i did in jia
instagram only accepts the image in body and other things in headers
so i just used bodypublisher on byte array
idk how to combine both
also ig we dont have a body method which accepts BodyPublisher yet?
i feel bad for the 19 stars and 8 forks 
We should be able to handle the multipart with the Java client
yea just saw theres a concat method
declaration: module: java.net.http, package: java.net.http, class: HttpRequest, class: BodyPublishers
@plain ledge so just make both separate and then concat, maybe will also need to make this ^ method if its not already
@plain ledge might moving the ones that are in review to "in review"? thanks 
is he in org?
yess β€οΈ
cool
i moved user api to in progress but not working on it :c
it's okay, there's no rush
bro ur models were fked ok
im sorry 
@plain ledge if ur not writing a model complete write a todo comment on top so the next dev will have "less headache"
it was very manual and i hated the entire process of doing it, i just went brain dead so made mistakes π¦
Ight ima pick up one of the API implementation tasks later tonight
I thought I finished all the models that I edited
I moved the ones that I finished to for review, the sticker is pretty much done I just need to deal with that multipart thing we was talking about
So in the constructor take in a BodyPublisher and byte[] ?
im not saying u didn't i haven't checked just saying if u leave any intentionally which is fine for now, just mark it
no take path of the file
and use BodyPublishers.file(Path path)
Has a name been come up for this wrapper yet?
nope π¦
put your ideas here: https://github.com/javadiscord/java-discord-api/discussions/54
@restive void maybe you can help me with my issue? https://github.com/javadiscord/java-discord-api/issues/22 
You can work off my branch + there's a few remaining endpoints that I have added to the comments
Sure Iβll try later
Sounds good
Would there be a better way instead of returning null here?
did u just took a picture of ur screen instead of a screenshot
I commented under the ticket so u can assign me
No please throw
returning null might end up supressing the error so we want to make it obvious to the user 
we might want to validate early in the constructor e.g. checking the file size is correct and fail fast
@orchid portal mind reviewing nopox's PRs? a second pair of eyes would be nice 
and if they're good we can let nopox press the merge button 
sure
thanks! β€οΈ
nah i'll press that button
i love that button
haha sure
jk
i don't think we have that many APIs left to do??
channels, users and anything I missed from the list?
user?
yeah the one u have assigned
we can maybe split the number to share the workload as channel and user endpoints have a lot
e.g. everyone can do like 5 or something or if you're capable, try the entire thing
i've done half of the channel endpoints anyway so if anax gets a bunch of them (or if he's really good, the rest) - we are pretty much done with the "discord integration"
then let's fix up all the tech debt we've accumulated and work on the core stuff (finally!)
maybe we can modularize the program a little e.g. make the gateway and api bits independent modules that people can use
i wont just how good he is with this, this is purely labour
judge*
nope, no need to judge the goal is for understandable and maintainable code. The framework we've setup together taz does make it really hard for mistakes or "bad code" to be introduced that goes against being able to maintain it
and yeah you're right these integrations are really sweat shop labour and we're finally almost done!
I want this trend to continue were we make a really good framework for the core integration so the actual logic just follows a pattern that by design prevents bad code from entering
our api integrations are really small classes, easy to modify and maintain. Very understandable so we have a good future!
minimal and straight to the point logic
once we finalise the design for the user interaction, it should be in the same position were you can't really go wrong anywhere, things work as expected
I donβt got wifi on my laptop
I was in public
Iβve got a intel code template so u just click request and it does the entire record for me and I just need to write the function and fill in fields
Intelj
so what does the template do?
make the record?
Should I refractor the DiscordRequest class then to have a throws Exception on that method?
also this implementation is not gonna work
is that not what u were saying or what
I thought u were saying add that to the body and then we make a serializer for it
no, make a body publisher with the map and a body publisher with file (as u did) and then use BodyPublishers#concat
to get one single bodypublisher, then use that as the body
sounds good
or maybe that'll not work as well
@plain ledge make a postman request and see how it expects stuff, then it'll be easier to write a code for that
kk
@light loom u use httpie right? is it any better?
i mean all are electron but i gotta use smth before i make my own
@orchid portal is this what u use? https://www.postman.com/discord-api/workspace/discord-api/overview
or what
Uhh no? I just send the request?
Ask wazei tho he's more exp in this
just intstalled httpie
looking good
@light loom rn it looks like the request it self doesn't mention what the parsed response class is?
ig we haven't talked about this yet
can't we just provide it as a T?
Like GetStickerRequest<Sticker>
yes thats what i did in jia
https://www.postman.com/discord-api/workspace/discord-api/request/23484324-db2bd396-efb6-455d-986a-ef3e332c40d5 looks like we may need to use forrm data for this instead of a body.
ohh wait discord did all the hard work for us?
wdym
I mean I don't think we can parse from that but it's a good reference
i mean without this we'll have to just do trial and error(kind of) till we find the right format
Yeah
right
I've never used form data so this will be new, is there any methods for it already?
or should I write them
no
yes
actually this is kinda meh
they didn't mentioned nothing
I'm gonna use it as a ref for this
not only a method but ig u'll need to write a custom BodyPublisher implementation
I'ma write a test application (just 1 class and get that one http request working with java http client and then write the wrapper)
That's for spring boot tho,
I'll look into it dw
ig u should sleep
real
this is a bad implementation
@light loom does vert.x have smth for this?
but then ig we'll need to change everything
Probably does,I just woke up so give me a few more hours, 5:30am rn lol
ur a senior u should be able to do this in ur sleep
fr
no
we shouldnt use vert.x for this at all
Because wazei was talking about making it possible to use the requests part without using the gateway
if ppl just want smth light
yes im totally against using it as well
I mean atleast for the http we shouldn't use it
It does feel a little bloated for the whole gateway since we aren't taking advantage of vert.x's verticles as far as I am aware, unless vert.x websocket system isn't a big file
GetCurrentUserApplicationRoleConnectionRequest 

does the question mark means its optional?
Yeha
Typically, make sure u check below or above cause sometimes it says otherwise
@orchid portal https://stackoverflow.com/a/61286969
Java enjoys a neat, built-in HTTP client. However, it lacks key HTTP features like multipart uploads, caching and response decompression. Methanol comes in to fill these gaps. The library comprises a set of lightweight, yet powerful extensions aimed at making it much easier & more productive to work with java.net.http. You can say it's an HttpClient wrapper, but you'll see it almost seamlessly integrates with the standard API you might already know.
Methanol isn't invasive. The core library has zero runtime dependencies. However, special attention is given to object mapping, so integration with libraries like Jackson or Gson becomes a breeze.
Methanol it is then
I have considered removing vert.x for the websocket side in favour of a lighter library
But I've left it in the meantime for stuff like this where we need a good library that just works
Fair enough
Yeah the problem with vert.x and others, is that they all ship an entire fucking reactive stack
If you want to go for just 21, it's so nice to not have to do that anymore
Created some tickets for a few of the missed APIs
@light loom
Can I just add that library in the stickers Pr?
i'd say do the work in a separate pr
then rebase and use it in ur main pr
wym
the parsed response of the request
which endpoint? sorry I am multi tasking with work atm (in a pair programming session, helping these noobs)
for all endpoints that data is not available in the request record/class
Like saying what the endpoint returns
okay, so from what I'm understanding, we don't have a way to get the response object back?
no, but what class the response object is going to be
parsed
So that's a task that's mainly important for all the GET operations
yes ig
When we start writing the user facing code, we'll need to create those response objects
Taz is saying like have it as a T maybe
Or we could also make a sub class thatβs like
GetDiscordRequest
You mean GetUserResponse?
And implement that for Grt requests
well all requests can have a response
True
then we'll have problem with finding out which class to parse "this json" into
yup but it depends what we care about - we don't want a response object for every request. Only the ones that contain data that we/user needs
e.g. if we do a PUT, we only care about 201 responses, the body might not matter
but whatever the case
we'll need to do this at the time of using the requestgs
so when we create our user facing request sending methods, that's when we'll implement the response models. It only makes sense to do it then instead of right now
we'll get overwealmed with having to make too many changes if we did it right now
that's why we're just focusing on sending the request and storing the raw data we get back as a DiscordResponse
public interface DiscordRequest<T extends DiscordResponse> {
DiscordRequestBuilder create();
T responseType();
}
public final record SomeGetRequest() implements DiscordRequest<SomeGetResponse> {
@Override public DiscordRequestBuilder create() { ... }
public T responseType() { return SomeGetResponse.class; }
}
public final record SomePutRequest() implements DiscordRequest<DiscordResponse> {
@Override public DiscordRequestBuilder create() { ... }
public T responseType() { return DiscordResponse.class; }
}
forgor the extends
maybe that will work , sure
Donβt we need a way to get T
Like to pass in when we serialize
I havenβt used java types before in a while so Iβm used to kotlin
yes
let me think about it
better?
because we can also do DiscordRequestBuilder<T> and then on the Future we could run through object mapper so instead of returning a DiscordResponse we can return the actual Request Response Model
If we can limit the responsibility to a single method, that would the best way without having to modify it in a way that makes creating other stuff harder since currently it's beautifully simple
@light loom Are these pretty much the same?
yeah maybe, I lost track of the endpoints so I did a "hey chatgpt, here's the list of all the channel endpoints, here are my class names that i've done, what's left?"

no way 
yeah lol
why do u think the models were wrong

i'm so glad you guys pay close attention to the details, i would be lost without you 
Gotcha lol
I'm working onwards from Edit Channel Permissions rn
Are we including overwrite.id from the docs? I noticed the delete channel request doesn't include it
So far implemented 11 more channel endpoints
Wow that's amazing
Include if missed
Dont even know if theyre entirely correct lmao but i followed the general pattern of the other endpoints
@light loom U want me to just open a PR on the original repo's 22-implement-discord-channels-api branch so u can check it out?
yes please!
looks good just do spotless
it'll add more spots but anyways
i have an idea
i have a better spotless config
nvm
How do u use spotless? Never used it before
gradle spotlessApply
ohh he meant how to apply
there is intellijJava?
y didn't u used it then
i cant find
it
I googled it and thought the question was the answer 
spotless {
java {
// Configure Google Java Format with settings that approximate IntelliJ IDEA Java code style
googleJavaFormat('1.10')
.aosp()
.style('intellij')
.targetVersion('8')
}
ok happens to the best of us
I found this online
i have no belief in googleJavaFormat but i'll try that
Well it's the "style" section
But same, I think by default Google is like 2 space indents or something
And does something funky with parameters
I mean worst case, we can write our own formatter 
π
thats what i just did
lets try teaking it a little more
Needs some tweaks but maybe we can make it good
Some parts do look good
But gosh, do you understand the XML? 
I'm on my phone so it was just a random blob for me but I'll properly look on my pc Tomo
its autogenerated and yes
